405 Method Not Allowed SignalR with Azure App Service .NET Core

139 Views Asked by At

I have configured SignalR in my .NET Core Web API as below.

using AutoMapper;
using Azure.Storage.Blobs;
using DinkToPdf;
using DinkToPdf.Contracts;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Client;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System;
using System.Reflection;
using System.Text;

var builder = WebApplication.CreateBuilder(args);

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

builder.Services.AddScoped<IDapperWrapper, DapperWrapper>();

//Use below code for global authorization and add AllowAnonymous to login route.
//otherwise use Authorize in the required controller and/or action
builder.Services.AddControllers(options =>
{
    options.Filters.Add(new AuthorizeFilter());
});

builder.Services.AddApiVersioning(x =>
{
    x.DefaultApiVersion = new ApiVersion(1, 0);
    x.AssumeDefaultVersionWhenUnspecified = true;
    x.ReportApiVersions = true;
});

builder.Services.AddAntiforgery(antiforgeryOptions =>
{
    antiforgeryOptions.HeaderName = "X-XSRF-TOKEN";
    antiforgeryOptions.Cookie.HttpOnly = true;
    antiforgeryOptions.Cookie.SecurePolicy = CookieSecurePolicy.Always;
});

#region --> JWT Authentication

builder.Services.Configure<JWTSettings>(options =>
{
    builder.Configuration.GetSection("Jwt").Bind(options);

    var securityKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(options.Secret));
    options.ValidFor = TimeSpan.FromMinutes(Convert.ToInt32(builder.Configuration["Jwt:ValidFor"]));
    options.SigningCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
});

JWTSettings jwtSettings = builder.Configuration.GetSection("Jwt").Get<JWTSettings>();
builder.Services.AddJWTAuthentication(jwtSettings);

#endregion

builder.Services.AddSingleton<CustomIDataProtection>();

builder.Services.AddSingleton(typeof(IConverter), new SynchronizedConverter(new PdfTools()));


builder.Services.AddSignalR(o => { o.EnableDetailedErrors = true; });

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseHsts();
}

app.UseMiddleware<ExceptionMiddleware>();

app.UseHttpsRedirection();

app.UseAuthentication();

app.UseRouting();

app.UseCors("CorsPolicy");
app.UseAntiforgeryToken();

app.UseAuthorization();

app.Use(async (context, next) =>
{
    if (!context.Response.Headers.ContainsKey("X-Frame-Options"))
    {
        context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
    }
    await next();
});
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "api",
        pattern: "{controller}/{action}/{id?}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{name}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{date}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{email}");
});

if (bool.Parse(builder.Configuration["UseSwagger"]))
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
        c.DefaultModelsExpandDepth(-1);
    });
}
app.MapHub<HjsHub>("/hjsHub");
app.Run();

It works flawlessly with my localhost.

Azure App Service hosts my Web API. When I ran this code and attempted to connect SignalR, I received the error method is not allowed.

Is there any configuration needed at Azure or am I missing something in my code?

I have tried above code in local server and tried it on Azure App service.

enter image description here

1

There are 1 best solutions below

6
On

UPDATE

Please change your middleware order like below and test again.

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}
else
{
    app.UseHsts();
}

app.UseMiddleware<ExceptionMiddleware>();

app.UseHttpsRedirection();

//app.UseAuthentication();

app.UseRouting();

app.UseCors("CorsPolicy");
//app.UseAntiforgeryToken();

app.UseAuthentication();
app.UseAuthorization();
app.UseAntiforgeryToken();

app.Use(async (context, next) =>
{
    if (!context.Response.Headers.ContainsKey("X-Frame-Options"))
    {
        context.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN");
    }
    await next();
});
app.UseEndpoints(endpoints =>
{
    endpoints.MapControllerRoute(
        name: "api",
        pattern: "{controller}/{action}/{id?}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{name}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{date}");

    endpoints.MapControllerRoute(
      name: "api",
      pattern: "{controller}/{action}/{email}");
});

if (bool.Parse(builder.Configuration["UseSwagger"]))
{
    app.UseSwagger();
    app.UseSwaggerUI(c =>
    {
        c.SwaggerEndpoint("/swagger/v1/swagger.json", "API");
        c.DefaultModelsExpandDepth(-1);
    });
}
app.MapHub<HjsHub>("/hjsHub");
app.Run();

You should use below code to allow all Origins for testing.

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

If you want it works for specific url, please don't use WithOrigins and AllowAnyOrigin together.