I use OAuth in my app and launch an external browser to let the user log in, then catch the returnUri to localhost with an HttpListener.
Thing is, this listener renders the webpage correctly most of the time, but sometimes it shows "This site can’t be reached" exception in chrome.
This site can’t be reachedlocalhost refused to connect.
Try:
Checking the connection
Checking the proxy and the firewall
ERR_CONNECTION_REFUSED
It does not throw an exception when this happens.
I do get the context from http.GetContext() so the listener does catch the browser request on localhost, but for some reason the browser sometimes shows the error message instead of rendering the "login succes.html" page.
When it gives that error it tends to keep doing that, although it does return to working again after a few calls. so it's quite inconsistent.
I've tried a lot of things like:
- Running it on the UI thread (so no background task)
- shutting the listener down and creating a new one, now I have a static listener that I start and stop although that doesn't seem to matter much.
- Thread.Sleep(100) to see if it might be a deadlock or something.
It won't budge, does anyone here have any clue what could be causing this?
Here are the relevant bits: I have a modal form that with a static HttpListener:
static HttpListener http = new HttpListener();
The form then kicks off the login code on a background thread (to keep the UI responsive):
Task.Run(SignInOIDC);
private void SignInOIDC() {
try {
if (!http.Prefixes.Contains(OidcOptions.RedirectUri)) http.Prefixes.Add(OidcOptions.RedirectUri);
http.Start();
// todo use the logout url https://stackoverflow.com/questions/52302863/logging-out-from-identityserver-quietly
_client = new OidcClient(OidcOptions);
_loginState = _client.PrepareLoginAsync().Result;
// open system browser to start authentication
var uri = _loginState.StartUrl;
var proc = Process.Start(_loginState.StartUrl);
// wait for the authorization response.
var context = http.GetContext(); // blocking call, it does return from this so it catches the request
WriteLoginSucceeded(context);
var formData = context.Request.Url.ToString();
ShutdownHttp();
this.Activate();
// read token
OIDCLoginResult = _client.ProcessResponseAsync(formData, _loginState).Result;
if (_cancelled) return;
this.Invoke((MethodInvoker)delegate {
DialogResult = DialogResult.OK; // this closes the form
});
}
catch (Exception ex) {
var msg = Util.ReadException(ex);
MessageBox.Show(msg);
}
finally {
ShutdownHttp();
}
}
private string _hmtl;
private string HTML { get {
if (_hmtl == null) {
var fld = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var path = Path.Combine(fld, "LoginSuccess.html");
_hmtl = File.ReadAllText(path);
}
return _hmtl;
} }
private void WriteLoginSucceeded(HttpListenerContext context) {
HttpListenerResponse response = context.Response;
byte[] buffer = Encoding.UTF8.GetBytes(HTML);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
}
private void ShutdownHttp() {
try {
if (http != null) {
if (http.IsListening) http.Stop();
}
}
catch { }
}
Think I fixed it by adding a pause, haven't seen it in a while.
It seems the forms would close very quickly afterwards, that calls the ShutDownHttp method. This 150ms pause seems to give it enough time to get the page out the door.