HangfireIO / Hangfire

An easy way to perform background job processing in .NET and .NET Core applications. No Windows Service or separate process required
https://www.hangfire.io
Other
9.44k stars 1.71k forks source link

ASP.NET Core - Hangfire dashboard - routing configuration #1729

Open klinki opened 4 years ago

klinki commented 4 years ago

Hello,

I have problem with Hangfire dashboard returning error 500 for invalid routes.

It throws following exception:

System.InvalidOperationException: The request reached the end of the pipeline without executing the endpoint: '/hangfire/{**path}'. Please register the EndpointMid dleware using 'IApplicationBuilder.UseEndpoints(...)' if using routing. at Microsoft.AspNetCore.Builder.ApplicationBuilder.<>c.b__18_0(HttpContext context) at Hangfire.Dashboard.AspNetCoreDashboardMiddleware.Invoke(HttpContext httpContext) at Microsoft.AspNetCore.Builder.Extensions.UsePathBaseMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Inviser.Middlewares.ExceptionHandler.InvokeAsync(HttpContext context, RequestDelegate next) in C:\projects\inviser\Inviser\Middlewares\ExceptionHandler.cs:li ne 58

I believe it should return HTTP 404 not found instead and not throw any exception.

I'm using ASP.NET Core and I'm configuring dashboard with app.UseEndpoints(endpoints => endpoints.MapHangfireDashboard())

udlose commented 4 years ago

Are you using app.UseHangfireDashboard() in your Configure(IApplicationBuilder app) method in Startup?

Do you need to use both()? Disclaimer - I haven't setup the Dashboard yet myself so I'm not sure all of what's needed - but I have seen documentation noting to use app.UseHangfireDashboard() in your Configure(IApplicationBuilder app) method

ogazioglu commented 4 years ago

I was getting same error in .NET Core 3.1 with routing, and have fixed the problem by removing all app.UseHangfireXXX(...) methods in my Configure() block as mentioned here and here. My working solution with authorization has the lines below:

public IServiceProvider ConfigureServices(IServiceCollection services, ...)
{
    ...
    services.Configure<AuthorizationOptions>(options =>
    {
        options.AddPolicy("somePolicy", policy =>
        {
            policy.RequireAuthenticatedUser();
        });
    });
    services.AddHangfire(....);
    services.AddHangfireServer(....);
    ...
}

public void Configure(IApplicationBuilder app, IBackgroundJobClient backgroundJobs, ...)
{
    ...
    backgroundJobs.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
    app.UseCookiePolicy();
    app.UseSession();
    app.UseRouting();
    app.UseAuthentication();
    app.UseAuthorization();
    app.UseEndpoints(endpoints =>
    {
        ...
        endpoints.MapDefaultControllerRoute();
        endpoints.MapHangfireDashboard("", new DashboardOptions
        {
            Authorization = new[] { new HangfireAuthorizationFilter("somePolicy"), },
            ...
        });
        ...
    });
}
public class HangfireAuthorizationFilter : IDashboardAuthorizationFilter
{
    private string PolicyName { get; }

    public HangfireAuthorizationFilter(string policyName)
    {
        this.PolicyName = policyName;
    }
    public bool Authorize(DashboardContext context)
    {
        var httpContext = context.GetHttpContext();
        var authService = httpContext.RequestServices.GetRequiredService<IAuthorizationService>();
        var authorizationResult = authService.AuthorizeAsync(httpContext.User, this.PolicyName).ConfigureAwait(false).GetAwaiter().GetResult();
        var isAuthorized = authorizationResult.Succeeded;

        if (!isAuthorized)
        {
            httpContext.ChallengeAsync().ConfigureAwait(false).GetAwaiter().GetResult();
        }
        return true; //always return true
    }
}
maksimnarkevichdp commented 2 years ago

Any updates on this? I am getting the same error while using following configuration:

endpoints.MapHangfireDashboard(string.Empty, new DashboardOptions { Authorization = new List<IDashboardAuthorizationFilter>(), StatsPollingInterval = 60000 }).RequireAuthorization();

Just to highlight - when using pattern = string.Empty