I'm trying to use NancyFx in combination with SignalR. In order to host both, I'm using Microsoft Owin. But unfortunately I always get an 503 (Service unavailable), when trying to access the REST-API via PostMen (REST-Api Client extension for chromium browsers). So I extracted the main ingredients to a more simple program, that allows me to switch between Nancy Selfhost and Owin.
When using Nancy SelfHost, everything works fine, but using Owin I still got a 503 error.
internal class Program {
private const bool _USE_SELF_HOST = false;
private static void Main(string[] args) {
if (_USE_SELF_HOST) {
var host = "http://localhost:7084";
UseSelfHost(host);
} else {
var host = "http://localhost:7084";
UsingWebApp(host);
}
}
private static void UseSelfHost(string host) {
var webhost = new NancyHost(new Uri(host));
webhost.Start();
Console.ReadLine();
webhost.Stop();
}
private static void UsingWebApp(string host) {
var nancyHost = WebApp.Start<Startup>(host);
Console.WriteLine($"Nancy started at {host}");
Console.ReadLine();
nancyHost.Dispose();
}
}
public class MainModule : NancyModule {
public MainModule() {
Get["/"] = x => "Hello world!";
}
}
I checked:
netsh http show urlacl - I'm allowed to open this port
Visual Studio is running with Admin rights, besides this should not be needed.
A colleague of mine found an error in my netsh configuration. I had two urlacls for the same tcp port:
Reservierte URL : http://wks-user:7084/
Benutzer: DOMAIN\user
Abh▒ren: Yes
Delegieren: No
SDDL: D:(A;;GX;;;XXX)
Reservierte URL : http://+:7084/
Benutzer: DOMAIN\user
Abh▒ren: Yes
Delegieren: No
SDDL: D:(A;;GX;;;XXX)
After removing the first entry via
netsh http delete urlacl http://wks-user:7084/
everything works as expected.
Related
I am working on a .Net Core web application and we would like to be able to redirect a type of url to our custom error page. The site is hosted on Azure and it seems that this error is not being handled in the application. Here is the type of URL I am working with:
www.mywebsite.com/%22http://www.yahoo.com/%22
The error page that is presented is the following:
The page cannot be displayed because an internal server error has occurred.
In addition when I check the live HTTP traffic on Azure it does not show an error occurring.
Edit:
Apparently azure cannot handle this type request at all: https://azure.microsoft.com/%22/http://www.google.com/
It looks for the config file within the second url. Does anyone know where I can file a bug with Microsoft?
I haven't tested this on Azure, however it works on our server.
Configure exceptions handling in Startup class.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// ...
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/error");
}
// ...
app.UseStatusCodePagesWithRedirects("/error/{0}");
// ...
}
And error controller.
[Route("[controller]")]
public class ErrorController : Controller
{
[Route("")]
public IActionResult Index()
{
return View();
}
[Route("{httpStatusCode}")]
public IActionResult Index(int httpStatusCode)
{
// handle by error code
switch (httpStatusCode)
{
case (int)HttpStatusCode.NotFound:
return View("NotFound");
default:
return View();
}
}
}
When deployed to Azure SignalR doens't work works on localhost but doesn't work when deployed to Azure
It responds with a 500 internal server error response when doing the signalr/negotiate request.
Navigating manually to the negotiate url, I got a more detailed error explanation. 'CryptographicException: The data protection operation was unsuccessful...'
Everything works fine locally, using IISExpress.
How do I fix this?
I think this is the solution. This worked for me without making any code changes:
Azure WebApps is configured to not load user profile by default and this causes the exception. In Azure App Settings, create an Application Setting called WEBSITE_LOAD_USER_PROFILE and set it to 1. This will load the user profile.
https://www.magnetismsolutions.com/blog/jaredjohnson/2015/12/18/resolving-cryptography-issues-with-the-dynamics-crm-sdk-in-azure-web-apps
Got it working. I needed to use appBuilder.SetDataProtectionProvider
app.UseAppBuilder(appBuilder =>
{
appBuilder.SetDataProtectionProvider(new MachineKeyProtectionProvider());
appBuilder.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true
};
map.RunSignalR(hubConfiguration);
});
});
I use katana extension methods to bridge the IAppBuilder to IApplicationBuilder.
This allows your owin middleware to connect to asp.net core. It is important to use the RunSignalr method.
internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
internal class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
//return MachineKey.Protect(userData, _purposes);
return userData;
}
public byte[] Unprotect(byte[] protectedData)
{
//return System.Web.Security.MachineKey.Unprotect(protectedData, _purposes);
return protectedData;
}
}
SignalR works on localhost but doesn't work when is deployed in Azure
Asp.net Core 1.0.0 (.Net Framework 4.6.1)
SignalR.Core 2.2.1
public static void UseSignalR2(this IApplicationBuilder app)
{
app.UseAppBuilder(appBuilder => {
appBuilder.MapSignalR(new HubConfiguration());
});
GlobalHost.HubPipeline.AddModule(new ErrorHandlingPipelineModule());
GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
}
SignalR.js 2.2.1 with default settings
$.connection.hub.url = '/signalr';
Expected behavior
200 for url:
https://(name).azurewebsites.com/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22productsimporthub%22%7D%5D&_=1472811629592
Actual behavior
/signalr/negotiate - on localhost returns 200 but for deployed app in azure returns 404
/signalr - works on both - Protocol error: Unknown transport.
/signalr/hubs - works on both - returns the SignalR js correctly
To find out the real cause of the issue you need to navigate to the negotiate url, and look for the response.
If the response tells you something about a 'CryptographicException: The data protection operation was unsuccessful...'. This is how to fix it.
1) Create a custom IDataProtectionProvider
2) Configure signalr
internal class MachineKeyProtectionProvider : IDataProtectionProvider
{
public IDataProtector Create(params string[] purposes)
{
return new MachineKeyDataProtector(purposes);
}
}
internal class MachineKeyDataProtector : IDataProtector
{
private readonly string[] _purposes;
public MachineKeyDataProtector(string[] purposes)
{
_purposes = purposes;
}
public byte[] Protect(byte[] userData)
{
//return MachineKey.Protect(userData, _purposes);
return userData;
}
public byte[] Unprotect(byte[] protectedData)
{
//return System.Web.Security.MachineKey.Unprotect(protectedData, _purposes);
return protectedData;
}
}
I use katana extension methods to bridge the IAppBuilder to IApplicationBuilder.
This allows your owin middleware to connect to asp.net core. It is important to use the RunSignalr method
app.UseAppBuilder(appBuilder =>
{
appBuilder.SetDataProtectionProvider(new MachineKeyProtectionProvider());
appBuilder.Map("/signalr", map =>
{
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true
};
map.RunSignalR(hubConfiguration);
});
});
I'm trying to use OAuth bearer authentication in a Web API application, everything works fine on my local IIS, I'm able to get the token as you can see here:
But when I publish my project to a ApiApp in Azure it doesn't work at all. I get the response:
{
"message": "No HTTP resource was found that matches the request URI 'https://mysite.azurewebsites.net/API/login'.",
"messageDetail": "No type was found that matches the controller named 'login'."
}
As shown in here:
My Startup.Auth class looks like:
public partial class Startup
{
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
// For more information on configuring authentication, please visit http://go.microsoft.com/fwlink/?LinkId=301864
public void ConfigureAuth(IAppBuilder app)
{
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/login"),
Provider = new ApplicationOAuthProvider(),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
// In production mode set AllowInsecureHttp = false
//#if DEBUG
AllowInsecureHttp = true
//#endif
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthAuthorizationServer(OAuthOptions);
}
}
I hope you can tell me what I'm doing wrong.
I've just find out that I was using an incorrect url. I was using /api/login instead of just /login.
Here my server-side code
class Program
{
static void Main(string[] args)
{
string url = "http://localhost:8080";
using (WebApp.Start<Startup>(url))
{
Console.WriteLine("Server running on {0}", url);
}
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
};
map.RunSignalR(hubConfiguration);
});
}
}
When I run the console app and browse 'http://localhost:8080/signalr/hubs' on the server, it's show some jQuery code But when I try to browse 'http://[server-ip]/signalr/hubs', it's show error 400 on both server and clients
Is this mean than my server-side app not allow cross domain yet?
Here the solutions :
change
string url = "http://localhost:8080";
to
string url = "http://+:8080";