4
votes

On my server side I'm using web api 2 with signalr. On my client side I'm using angularjs.

Here's the http request when I initiate the signalr connection:

> GET
> http://example.com/signalr/negotiate?clientProtocol=1.4&connectionData=%5B%7B%22name%22%3A%22main%22%7D%5D&_=1416702959615 HTTP/1.1 Host: mysite.net Connection: keep-alive Pragma: no-cache
> Cache-Control: no-cache Accept: text/plain, */*; q=0.01 Origin:
> http://lh:51408 User-Agent: Mozilla/5.0 (Windows NT 6.3; WOW64)
> AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.65
> Safari/537.36 Content-Type: application/x-www-form-urlencoded;
> charset=UTF-8 Referer: http://localhost:51408/ Accept-Encoding: gzip,
> deflate, sdch Accept-Language: en-US,en;q=0.8 Cookie:
> ARRAffinity=9def17406de898acdc2839d0ec294473084bbc94a8f600c867975ede6f136080

And the response:

> HTTP/1.1 200 OK Cache-Control: no-cache Pragma: no-cache
> Transfer-Encoding: chunked Content-Type: application/json;
> charset=UTF-8 Expires: -1 Server: Microsoft-IIS/8.0
> X-Content-Type-Options: nosniff X-AspNet-Version: 4.0.30319
> X-Powered-By: ASP.NET Date: Sun, 23 Nov 2014 00:36:13 GMT
> 
> 187
> {"Url":"/signalr","ConnectionToken":"6BKcLqjNPyOw4ptdPKg8jRi7xVlPMEgFUdzeJZso2bnXliwfY4WReQWHRpmB5YEZsbg14Au7AS5k5xS5/4qVheDxYoUkOjfFW0W8eAQsasjBaSQOifIilniU/L7XQ1+Y","ConnectionId":"f2fc7c47-c84f-49b8-a080-f91346dfbda7","KeepAliveTimeout":20.0,"DisconnectTimeout":30.0,"ConnectionTimeout":110.0,"TryWebSockets":true,"ProtocolVersion":"1.4","TransportConnectTimeout":5.0,"LongPollDelay":0.0}
> 0

However, in my javascript I'm getting the following error response when connecting:

No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhos:51408' is therefore not allowed access.

On my server side my startup method looks the following:

public void Configuration(IAppBuilder app)
{
    System.Web.Mvc.AreaRegistration.RegisterAllAreas();
    ConfigureOAuth(app);
    GlobalConfiguration.Configure(WebApiConfig.Register);
    app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}

Shouldn't this make sure that cors is used in signalr too or am I missing something?

4

4 Answers

7
votes

For those who had the same issue with Angular, SignalR 2.0 and Web API 2.2,

I was able to solve this problem by adding the cors configuration in web.config and not having them in webapiconfig.cs and startup.cs

Changes Made to the web.config under <system.webServer> is as below

<httpProtocol>
  <customHeaders>
    <add name="Access-Control-Allow-Origin" value="http://localhost" />
    <add name="Access-Control-Allow-Methods" value="*" />
    <add name="Access-Control-Allow-Credentials" value="true" />
  </customHeaders>
</httpProtocol>
4
votes

You can look at this snippet from here https://github.com/louislewis2/AngularJSAuthentication/blob/master/AngularJSAuthentication.API/Startup.cs and see if it helps you out.

public void Configuration(IAppBuilder app)
    {
        HttpConfiguration config = new HttpConfiguration();

        ConfigureOAuth(app);

        app.Map("/signalr", map =>
        {
            // Setup the CORS middleware to run before SignalR.
            // By default this will allow all origins. You can 
            // configure the set of origins and/or http verbs by
            // providing a cors options with a different policy.
            map.UseCors(CorsOptions.AllowAll);
            var hubConfiguration = new HubConfiguration
            {
                // You can enable JSONP by uncommenting line below.
                // JSONP requests are insecure but some older browsers (and some
                // versions of IE) require JSONP to work cross domain
                //EnableJSONP = true
                EnableDetailedErrors = true
            };
            // Run the SignalR pipeline. We're not using MapSignalR
            // since this branch already runs under the "/signalr"
            // path.
            map.RunSignalR(hubConfiguration);
        });

        WebApiConfig.Register(config);
        app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
        app.UseWebApi(config);
        Database.SetInitializer(new MigrateDatabaseToLatestVersion<AuthContext, AngularJSAuthentication.API.Migrations.Configuration>());

    }
1
votes

I have faced the CORS issue in MVC.net

The issue is SignalR negoiate XHR request is issued with credentials = include thus request always sends user cookies

The server has to reply back with response header Access-Control-Allow-Credentials set to true

First approach and this is due the help of other people , configure it at web.config

<configuration>
    <system.webServer>
        <httpProtocol>
           <customHeaders>
              <add name= "Access-Control-Allow-Origin" value="http://yourdomain:port"/>
              <add name="Access-Control-Allow-Credentials" value = "true"/>
           </customHeaders>
        </httpProtocol>
    </system.webServer>
</configuration>

Second approach which I fought to make it work is via code using OWIN CORS

[assembly::OwinStartup(typeof(WebHub.HubStartup), "Configuration"]
namespace WebHub
{
public class HubStartUp
{
    public void Configuration(IAppBuilder app)
    {
        var corsPolicy = new CorsPolicy
        {
            AllowAnyMethod = true,
            AllowAnyHeader = true,
            SupportsCredentials = true,
        };

        corsPolicy.Origins.Add("http://yourdomain:port");

        var corsOptions = new CorsOptions
        {
            PolicyProvider = new CorsPolicyProvider
            {
                PolicyResolver = context =>
                {
                    context.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
                    return Task.FromResult(corsPolicy);
                }
            }
        };

        app.Map("/signalR", map =>
        {
            map.UseCors(corsOptions);
            var config = new HubConfiguration();
            map.RunSignalR(config);
        });
    }
}}
0
votes

In ConfigureServices-method:

services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
                 {
                    builder.AllowAnyHeader()
                           .AllowAnyMethod()
                           .SetIsOriginAllowed((host) => true)
                           .AllowCredentials();
                 }));

In Configure-method:

app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
               {
                  routes.MapHub<General>("/hubs/general");
               });