Web API self host - bind on all network interfaces - c#

How do you make a Web API self host bind on all network interfaces?
I have the below code currently. Unfortunately, it binds only on localhost. So access to this server from other than localhost is failing.
var baseAddress = string.Format("http://localhost:9000/");
using (WebApp.Start<Startup> (baseAddress))
{
Console.WriteLine("Server started");
Thread.Sleep(1000000);
}

Just change the base address like this
var baseAddress = "http://*:9000/";
using (WebApp.Start<Startup> (baseAddress))
{
Console.WriteLine("Server started");
Thread.Sleep(1000000);
}
And it should bind correctlly to all interfaces.

If you get access exceptions, please DO NOT start Visual Studio as admin user. Add an URL reservation instead. The following example assumes that you want to open port 9000 as HTTP service on all ports & hostnames (http://+:9000/) without any user restriction.
Start a command console window as administrator and execute:
netsh
netsh> http add urlacl url="http://+:9000/" sddl=D:(A;;GX;;;S-1-1-0)
The SDDL translates to "all users" from your current domain / machine.
Modify your code accordingly:
var baseAddress = "http://+:9000/";
using (WebApp.Start<Startup> (baseAddress))
{
// your code here
}
You can delete the reservation by running:
netsh
netsh> http delete urlacl url="http://+:9000/"
However, Microsoft recommends to avoid Top-level wildcard bindings, see:
https://learn.microsoft.com/en-us/windows/win32/http/add-urlacl
For more information about the difference between http://*:9000/ and http://+:9000/ see:
What does a plus sign mean in a http url? -> http://+:80

Related

Why do we need to add a URL via netsh when listening to "http://*:8080" using HttpListener, but not when creating an HTTP server in Asp.NET Core?

Recently I am writing an HTTP server using HttpListener and met a problem.
I want my program listen to all IP address on port 8080. However I have to either run the program as administrator or add url http://*:8080 using netsh, otherwise it will throw an exception.
As far as I know, the built-in server like IIS or HttpSys from Asp.NET core can do the similar thing by just listening to IP address 0.0.0.0 without any administrator privileges or netsh thing.
How can they do this?
Edit:
I start an HttpListener like below:
var _listener = new HttpListener();
_listener.Prefixes.Add($"http://*:8080/");
_listener.Start(); // <-- Thrown exception "Access Denied" here

How to access web service on ServiceStack from android device?

I have an android application that's supposed to send a request to a simple HelloWorld C# webservice I made on ServiceStack but I am not able to connect. My application crashes when I try to connect. Here is my code on Eclipse, trying to access the ServiceStack service:
String base = "http://192.168.1.7:62938/json/reply/Hello?Name=";
String str = editTextField.getText().toString();
StringBuilder url = new StringBuilder(base + str);
String result = "";
HttpClient hc = new DefaultHttpClient();
HttpGet httpget = new HttpGet(url.toString());
HttpResponse r = hc.execute(httpget);
int status = r.getStatusLine().getStatusCode();
if (status == 200) {
HttpEntity e = r.getEntity();
String data = EntityUtils.toString(e);
JSONObject o = new JSONObject(data);
result= o.getString("result");
}
My C# service code for ServiceStack:
//Request DTO
public class Hello
{
public string Name { get; set; }
}
//Response DTO
public class HelloResponse
{
public string Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
//Can be called via any endpoint or format, see: //http://mono.servicestack.net/ServiceStack.Hello/
public class HelloService : Service
{
public object Any(Hello request)
{
return new HelloResponse { Result = "Helloooo, " + request.Name };
}
}
My service works fine on my laptop when I go to localhost:62938/json/reply/Hello?Name="arbitraryName"
but it does not work when I try to replace localhost with my laptop's ip address and access the service from an android device. It also does not work if I replace localhost with my IP address and try it on my browser on my laptop. Note: I want to make it work from a real android device, not an emulator.
Is there something different with ServiceStack services where I cannot access it normally from another device? I have already tried opening port 62938 and it did not work.
I appreciate any guidance. Thank you.
It also does not work if I replace localhost with my IP address and try it on my browser on my laptop.
If you have tried accessing the ServiceStack service through the local IP address of 192.168.1.7 in your computer's web browser and it is also unreachable, then the issue isn't isolated to Android.
This is issue is likely the result of one or more of these problems:
Check you are listening on the correct IPs:
Your ServiceStack service isn't configured to listen for requests on any other interfaces other than localhost. Select your relevant hosting option:
Self Hosting:
This can happen if you are self hosting and you have configure the app host to start with appHost.Start("http://localhost:62938/");. You would need to replace localhost with a + symbol to have it listen on all local addresses.
IIS Express:
By default IIS Express is used by Visual Studio during development, unless manually configured to use IIS, and is restricted to localhost requests only. You should see this answer as to how to configure IIS Express to allow non-local access as well.
This tutorial by Scott Hanselman is also very good, and provides great step-by-step instructions for configuring IIS Express.
IIS:
You can confirm the IP addresses that you server is configure to listen on by following these instructions. They provide instructions for both IIS6 and IIS7+.
Firewall:
Your computer may have a firewall preventing you accessing that port, or accepting outside traffic. Note your firewall may be built into antivirus software you run. You should add an exception rule for http traffic on port 62938.
Correct IP:
You are trying to access on 192.168.1.7. You should confirm that IP address is in fact correct. Most home networks are configured to provide a dynamic IP address by the network router. The IP address may have changed since you last checked it. You should try running a ping to the IP from your development machine.
Until you can successfully access the service through your web browser on your development machine, at the local network IP starting 192.168.1.X then I wouldn't attempt to access from Android. It's not an Android issue if other systems can't access your service also.
I hope that helps. If you provide more information about your specific environment, I may be able to provide more specific instructions. If I had to guess, I would say IIS Express issue.
Edit:
Now that you can access the service in the web browser of your android device but not in the application, we know the service is remotely accessible. This means your connectivity issue is isolated now to your application. The first thing I would check, is that your application has permission to make network requests. In your AndroidManifest.xml you need to ensure that android.permission.INTERNET is included
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
If you have that permission then you should be able to make the request successfully. If it continues to fail, then the reason need to be diagnosed from the exception that is causing the application to crash. In which case you should wrap the data request in a try { ... } catch(Exception exception) { } and log the exception.
As the Android emulator is considered to be running on a different device, to refer to the loopback IP (127.0.0.1) on our local development machine we need to use the special 10.0.2.2 alias.
Other special device IP's can be found in Andorid's documentation.

ServiceHost is binding to multiple hostnames/base addresses

I'm running Windows 7 and Visual C# Express 2010.
I have the following rule in my ACL:
Reserved URL : http://www.example.com:8020/gamerecords/
User: Myricae\Dario
Listen: Yes
Delegate: No
SDDL: D:(A;;GX;;;S-1-5-21-3389095862-38437692-3014067205-1001)
Not that it really matters, but I also have an appropriate entry in my hosts file:
127.0.0.1 www.example.com
I'm trying to self-host a WCF service within a console application:
var baseAddress = new Uri("http://www.example.com:8020/gamerecords/");
using (ServiceHost host = new ServiceHost(typeof(Acme.Gaming.GameRecordsImpl), baseAddress))
{
...
}
I get the following exception:
Unhandled Exception: System.ServiceModel.AddressAccessDeniedException: HTTP could not register URL http://+:8020/gamerecords/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details). ---> System.Net.HttpListenerException: Access is denied
The reason is that ServiceHost tries to bind to any hostname (+), but the ACL rule only authorizes the current user for hostname www.example.com. If I change the rule to:
Reserved URL : http://+:8020/gamerecords/
User: Myricae\Dario
Listen: Yes
Delegate: No
SDDL: D:(A;;GX;;;S-1-5-21-3389095862-38437692-3014067205-1001)
everything works fine. However I don't think that ServiceHost should really try to bind to any hostname; instead it should only publish the service at www.example.com. Why WCF attempts to bind to multiple hostnames?.
I found a page which describes a similar issue.
Did you start your application via "Run-as-Administrator"?

Self hosted OWIN and urlacl

I've created a self hosted Nancy/SignalR application self-hosted in OWIN using Microsoft.Owin.Host.HttpListener and Microsoft.Owin.Hosting
Things work perfectly fine locally but as soon as I try to use anything but localhost to access the app I get a HTTP Error 503. The service is unavailable error. I can't even access the app using 127.0.0.1 or the machine name.
I've tried adding the port to urlacl using
http add urlacl http://*:8989/ user=EVERYONE but doesn't seem to do anything.
here are the OWIN start options that I've tried,
var options = new StartOptions
{
Url = "127.0.0.1",
App = GetType().AssemblyQualifiedName,
Port = _configFileProvider.Port
};
var options = new StartOptions
{
App = GetType().AssemblyQualifiedName,
Port = _configFileProvider.Port
};
Here is the source code for the file that starts and stops the server.
so it turns out you need to pass in a url into StartOptions in the same format as the urlacl.
Changing the start options to the code below fixed the problem. now the app is accessible across the network.
var options = new StartOptions("http://*:8989")
{
ServerFactory = "Microsoft.Owin.Host.HttpListener"
};
I spend many hours solving similar issue on Windows 8.1.
StartOptions options = new StartOptions();
options.Urls.Add("http://localhost:9000");
options.Urls.Add("http://127.0.0.1:9000");
options.Urls.Add("http://192.168.0.102:9000");
options.Urls.Add(string.Format("http://{0}:9000", Environment.MachineName));
WebApp.Start<Startup>(options);
I could not listen or was getting 503 error...
If you want to listen on several IP addresses, each address needs its own urlacl record:
Does NOT work:
netsh http>add urlacl http://+:9000/ user=EveryOne
OK:
netsh http>add urlacl http://localhost:9000/ user=EveryOne
netsh http>add urlacl http://127.0.0.1:9000/ user=EveryOne
etc.
After adding reservation for each address individually, everything works fine.
Thanks to the info that #kay.one provided I was able to access my self-hosted Web API 2.2 (OWIN/Katana, console app) from the same machine via IP address. However just consolidate it into a simple step-by-step:
In Main of Program.cs (for console app): WebApp.Start<Startup>("http://*:8080");
From Windows Command Prompt (run as Administrator) enter netsh http add urlacl http://*:8080/ user=EVERYONE
Go to Windows Firewall with Advanced Security and add an Inbound Rule that opens up TCP port 8080
You should then be able to access from another machine using IP address or computer name.
Disclaimer: I'm not a security expert so I don't know the security implications of doing this.

.NET HttpListener Prefix issue with anything other than localhost

I'm trying to use C# and HttpListener with a prefix of anything other than localhost and it fails (i.e. if I give it server1, i.e.
http://localhost:1234 works, but
http://server1:1234 fails
The code is...
HttpListener listener = new HttpListener();
String prefix = #"http://server1:1234";
listener.Prefixes.Add(prefix);
listener.Start();
The failure occurs on listener.Start() with an exception of Access is denied..
I had the same issue once and i solved it by adding an URL reservation for the specified URL namespace for a user/users to the Network Shell (netsh). Here's an example on how to reserv an URL for every user, run this in the command prompt as an administrator:
netsh http add urlacl url=http://server1:1234/ user=Everyone
Here's an example on how reserv an URL for one user, run this in the command prompt as an administrator:
netsh http add urlacl url=http://server1:1234/ user=Steve
In this way you don't need to run the application as an administrator
Is your app running with elevated privilege?
Normal accounts cannot hook the Http pipeline without first making a reservation.
http://msdn.microsoft.com/en-us/library/Aa364673
It can be done programatically at install time. Let me know if this is of interest, and I'll dig out some code.
EDIT:
Actually, as I can't identify where the code came from at the moment, I can't post it here. There's a codeplex project for doing this kind of thing which is definitely worth picking apart.
/EDIT
Here's a way make the reservation on the command line:
http://www.casadehambone.com/HowToAddAURLACLAndAvoidAddressAccessDeniedExceptionInWindowsVista.aspx

Categories

Resources