Closed SaricVr closed 4 years ago
I don't think you're doing anything wrong. As a matter of fact, our sample program does the same.
Our EndPointManager
class, on the other hand, could be misbehaving. When configured to use IPv6 (the default), it translates "*"
(or "+"
, or even "0.0.0.0"
) to IPAddress.IPv6Any
, which is fine... as long as you actually have an IPv6 stack on your machine.
If a client only uses IPv4, there's no problem: EmbedIO will listen on both IP stacks. But if the server only uses IPv4, you'd better set EndPointManager.UseIpv6 = false;
before starting your WebServer
:
public static void Start()
{
var url = "http://*:9696"; // the same arises if I use "+" instead of "*"
EndPointManager.UseIpv6 = false; // This should do the trick
using (var server = CreateWebServer(url))
server.RunAsync();
}
private static WebServer CreateWebServer(string url)
{
var server = new WebServer(o => o
.WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO))
.WithLocalSessionManager().WithWebApi("/", m => m
.WithController<Controller>());
return server;
}
@SaricVr can you confirm that your machine has no IPv6 stack, and that the problem goes away if you set EndPointManager.UseIpv6
to false
? It's important that we understand what's going on exactly.
EmbedIO v4 will automatically detect the presence of an IPv6 stack and act accordingly; to tell the truth, it won't even have an EndPointManager
any more, but that's another story. However, if there is some other problem I'd like to nail it down and fix it in both v3 and v4.
Hi @rdeago, thanks for the answer.
My machine has definetly IPv6 capabilities. I run a few tests and noticed the following: if I start the webserver with an explicit url such as "http://localhost:9696", then I see the following listener on port 9696 (both with UseIpv6 = true
and UseIpv6 = false
).
LocalAddress LocalPort RemoteAddress RemotePort State AppliedSetting
------------ --------- ------------- ---------- ----- --------------
::1 9696 :: 0 Listen
It appears to be binding always on the IPv6 interface regardless of the UseIpv6 property value. However, if I insert the wildcard *, then no listener is reported listening on port 9696, indepentently on how I set the UseIpv6 property.
Hope this helps.
Hi, I've been able to solve the problem. I noticed that the webserver gets disposed when binding with a wildcard (* or +).
Exception thrown: 'System.ObjectDisposedException' in System.dll
By removing the using
block and declaring server
as a global variable (preventing it from being garbage collected), everything works correctly.
Now, the debugging of the problem has been really hard because I noticed that logging does not work (that's why I didn't notice the exception initially). Every time I try to use (or that EmbedIO tries to use) the Swan.Logger class this happens: Exception thrown: 'System.IO.IOException' in mscorlib.dll
. I had to implement my own ILogger in order to see the log. I guess the problem is related to the Terminal classs of Swan, but this is material for another bug report :)
Have you tried this?
// Remove all loggers.
Logger.NoLogging();
// Add a file logger
Logger.RegisterLogger(new FileLogger("path_to_log_file"));
As soon as the first EmbedIO 4.0 prerelease is out, we'll have to add SourceLink and symbol packages to Swan too. Not to mention fix logging.
@SaricVr if you're willing to spend some minutes on it, here's (more or less) how to "debug all the things", based upon my other comment:
clone the https://github.com/unosquare/swan.git
repository in a folder of your choice;
check out the master
branch;
build Swan.sln
in Debug mode;
clone the https://github.com/unosquare/embedio.git
repository in a folder of your choice;
check out the v3.X
branch;
remove the package reference to Swan.Lite in EmbedIO.csproj
your project and replace it with a library reference to the Swan.Lite.dll
you just built;
build EmbedIO.sln
in Debug mode;
remove the package references to both Swan.Lite and EmbedIO in your project, replacing them with library references to the Swan.Lite.dll
and EmbedIO.dll
you just built;
debug all the things! 😄
(Please @SaricVr don't think I'm mocking you or anything - on the contrary, you're doing a great service to the team! The "all the things" meme is mostly an inside joke, more aimed at @geoperez than at you.)
Lol
I've been busy, after breakfast I will take a look what is going on.
Ahahah @rdeago no offense taken at all!
Anyway... I think I've been able to track down also this bug (branch 3.X). Essentially, when binding with a wildcard "*" or "+", the disposing of the web server works properly, hence the using
keyword makes the web server to close after the start (if used just as I did). However, when a specific ip (or "localhost") is issued as url, the disposing of webserver does not work as intended (I think). This happens because EndpointListener.RemovePrefix
never finds the key inside the _prefixes
collection (line 173-17).
The reason is that _prefixes
is a Dictionary<ListenerPrefix, HttpListener>
, but the class ListenerPrefix
does not implement a custom comparer, only the ToString()
method. The keys inside _prefixes
are then compared to using the default comparer of objects, consequently never finding the same prefix since ListenerPrefix
is always a new instance created every time from the url string.
I quickly tested a fix obtaining a consistent behavior by implementing an IEqualityComparer
within ListenerPrefix
.
The reason why the removing works with wildcards is because a different method is used: RemoveSpecial
that explicitly compares the content of the prefix.
Let me know if this makes sense to you.
It totally makes sense! As a matter of fact, @desistud may have beaten you by a few hours with their PR #463. Please take a look at it and see if it does what you need.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hello,
I'm facing a strange problem... if I use this code to create a web server
I am not able to access the server using the IP addresses of my machine, i.e. "localhost", "127.0.0.1", "192.168.0.25". However, if I explicitly set multiple binding urls (using "WithUrlPrefixes" with an array of strings) such as "http://localhost:9696", "http://127.0.0.1:9696", "http://192.168.0.25:9696", then I can connect to every one of them.
Am I doing something wrong? Thank you.