Dashboard 404 NancyFx and Nowin

I am trying to get hangfire setup and cannot seem to get the Dashboard to work properly. I am using Nowin which I think is where the issue is, I am just not sure how to solve it.

public class HttpServer : IHttpServer
{
    private readonly ILogger<HttpServer> _logger;
    private readonly INancyBootstrapper _bootstrapper;
    private readonly IKeyValueStore _keyValueStore;
    private readonly ILifetimeScope _lifetimeScope;
    private readonly IUserManager _userManager;
    private INowinServer _nowinServer;
    private readonly CancellationTokenSource _cancelSource;

    public HttpServer(ILogger<HttpServer> logger,
        INancyBootstrapper bootstrapper,
        IKeyValueStore keyValueStore,
        ILifetimeScope lifetimeScope,
        IUserManager userManager)
    {
        if (logger == null) throw new ArgumentNullException("logger");
        if (bootstrapper == null) throw new ArgumentNullException("bootstrapper");
        if (keyValueStore == null) throw new ArgumentNullException("keyValueStore");
        if (lifetimeScope == null) throw new ArgumentNullException("lifetimeScope");
        if (userManager == null) throw new ArgumentNullException("userManager");

        _logger = logger;
        _bootstrapper = bootstrapper;
        _keyValueStore = keyValueStore;
        _lifetimeScope = lifetimeScope;
        _userManager = userManager;
        _cancelSource = new CancellationTokenSource();
    }

    public void Start()
    {
        var binding = _keyValueStore.Get("http.binding", "127.0.0.1");
        var port = _keyValueStore.Get("http.port", 7890);

        if (binding == "localhost") binding = "127.0.0.1";
        if (binding == "+") binding = "0.0.0.0";

        var address = IPAddress.Parse(binding);
        var endPoint = new IPEndPoint(address, port);

        var certificateFile = _keyValueStore.Get<string>("http.x509.file");
        var certificatePassword = _keyValueStore.Get<string>("http.x509.password");
        X509Certificate2 certificate = null;

        if (!string.IsNullOrEmpty(certificateFile))
        {
            try
            {
                certificate = string.IsNullOrEmpty(certificatePassword)
                    ? new X509Certificate2(certificateFile)
                    : new X509Certificate2(certificateFile, certificatePassword);
            }
            catch (Exception exception)
            {
                _logger.Warn(exception, "Failed to load X509 certificate.");
            }
        }

        try
        {
            var app = BuildOwinApp(_cancelSource.Token);
            var builder = ServerBuilder
                .New()
                .SetOwinApp(app.Build())
                .SetOwinCapabilities((IDictionary<string, object>)app.Properties[OwinKeys.ServerCapabilitiesKey])
                .SetEndPoint(endPoint);

            if (certificate != null) builder.SetCertificate(certificate);

            _nowinServer = builder.Build();
            Task.Run(() => _nowinServer.Start());

            var protocol = certificate != null ? "https" : "http";
            _logger.Info("HTTP server accepting connections on {Url}.",
                string.Format("{0}://{1}", protocol, endPoint));
        }
        catch (Exception exception)
        {
            _logger.Error(exception, "Failed to start HTTP server.");
        }
    }

    public void Stop()
    {
        _cancelSource.Cancel();
        _nowinServer.Dispose();
    }

    private IAppBuilder BuildOwinApp(CancellationToken token)
    {
        var builder = new AppBuilder();
        OwinServerFactory.Initialize(builder.Properties);
        var props = new AppProperties(builder.Properties) {OnAppDisposing = token};

        GlobalConfiguration.Configuration.UseSqlServerStorage("Connection String");
        builder
            .MapWebSocketRoute<EventStreamServer>("/events", _lifetimeScope, _userManager)
            .UseNancy(nancyOptions => nancyOptions.Bootstrapper = _bootstrapper)
            .UseHangfireServer()
            .UseHangfireDashboard();
        return builder;
    }

}

In order to get the UseHangfireServer call to not throw an exception I had to add the cancellation token. I assume this is because of Nowin as I couldnt find anyone else with an issue. This is why I think nowin is why I can’t access the dashboard. I get a 404 not found response. Any help would be appreciated.

Edit: I forgot to mention, if it matters this is running as a console application. With the start method being called then the console window waiting for cancel, which is when stop is called.

I had the same issue with the cancellation token in ASP.Net 5, but this is for Hangfire server (I.e. The processing component) and not the dashboard. Is Nancy setup to forward not found pages onto the next middleware rather than displaying a 404 page ? Try putting UseHangfireDashboard before UseNancy.

1 Like

I knew it was something simple. Putting UseHangfireDashboard before UseNancy did the trick. Thanks for your help.