I am using hangfire on an app and I have the need to do dashboard auth using my repositories. To do that, I have to resolve the repository inside Hangfire's Authorize method but, using OwinContext
I haven't been able to do so. I chose to use SimpleInjector for this project, and since it registers everything during WebApiConfig
s Register
method, I want to reach it. Recently I used a middleware
as MessageHandler
and from that, I successfully resolved a dependency using HttpRequestMessage
. But on OwinContext
I can't reach it and resolve a dependency through it using HttpRequestMessage.GetDependencyScope()
.
This is how Hangfire suggests to do the auth for Asp.net apps on their documentation;
public class MyAuthorizationFilter : IDashboardAuthorizationFilter
{
public bool Authorize(DashboardContext context)
{
// In case you need an OWIN context, use the next line, `OwinContext` class
// is the part of the `Microsoft.Owin` package.
var owinContext = new OwinContext(context.GetOwinEnvironment());
// Allow all authenticated users to see the Dashboard (potentially dangerous).
return owinContext.Authentication.User.Identity.IsAuthenticated;
}
}
Since I am using Angular
on the front-end this owinContext.Authentication.User
is null. And even if it wasn't, I only want myself to reach to the dashboard. So this wouldn't solve my problem.
How can I resolve my dependencies here inside Authorize
method?
I cannot do it through constructor injection, because for hangfire, you are saying UseHangfireDashboard
on the Startup.cs
s Configuration
as below states;
This is my Startup.cs
file
private IEnumerable<IDisposable> GetHangfireServers()
{
Hangfire.GlobalConfiguration.Configuration
.SetDataCompatibilityLevel(CompatibilityLevel.Version_170)
.UseSimpleAssemblyNameTypeSerializer()
.UseRecommendedSerializerSettings()
.UseSqlServerStorage("CONN_STR", new SqlServerStorageOptions
{
CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
QueuePollInterval = TimeSpan.Zero,
UseRecommendedIsolationLevel = true,
DisableGlobalLocks = true
});
yield return new BackgroundJobServer();
}
public void Configuration(IAppBuilder app)
{
app.UseHangfireAspNet(GetHangfireServers);
app.UseHangfireDashboard("/hangfire", new DashboardOptions {
Authorization = new [] {
new DashboardAuthorization()
/* explanation */
// for DI to work through constructor,
//I have to give my AuthRepository as a parameter here.
//And my AuthRepository also has many DIs so,
//it's not possible through here.
}
});
BackgroundJob.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
}
My project is a .Net Framework 4.7.2 project by the way.
As far as Hangfire is concerned, you are responsible for providing an instance of the class that implements IDashboardAuthorizationFilter. So if that class has dependencies that you want to inject, that will be on you to wire up. It's probably best to register that type and its dependencies with your DI container, and have it resolve you an instance. That way it takes care of injecting all the dependencies for you via Constructor Injection.
You should end up with a pattern something like this in your Startup.cs where you configure the OWIN pipeline.
public void Configuration(IAppBuilder app)
{
var container = CreateContainerWithRegisteredServices();
var dashboardFilter = container.Resolve<IDashboardAuthorizationFilter>();
app.UseHangfireDashboard("/hangfire", new DashboardOptions {
Authorization = new [] { dashboardFilter }
});
BackgroundJob.Enqueue(() => Console.WriteLine("Hello world from Hangfire!"));
// Configure Web API, SignalR, or whatever else hangs off your OWIN pipeline.
// You can pass the container into their configure methods if necessary.
}
IContainer CreateContainerWithRegisteredServices()
{
//this method will look different depending on your chosen IoC library
var container = SomeIoCLibrary.CreateContainer();
container.Register<MyAuthorizationFilter, IDashboardAuthorizationFilter>();
//register other dependencies here
return container;
}