问题
I have a multi-tenant MVC5 webapp, which is using Autofac v3.5.2 and Autofac.Mvc5 v3.3.4.
My Autofac DI wiring takes place in a class within my MVC project. For authentication, we are using OWIN OpenId middleware to integrate with Azure B2C. In the OWIN Startup class I need a dependency to set tenantId
/clientId
using information from the current request.
I try to grab the dependency via :
DependencyResolver.Current.GetService<...>();
However, this always throws an ObjectDisposedException
Instances cannot be resolved and nested lifetimes cannot be created from this LifetimeScope as it has already been disposed.
We have an ISiteContext in our application that has a request-lifetime. It gets populated with configuration values specific to the current request. I am trying to fetch these values like this:
private OpenIdConnectAuthenticationOptions CreateOptionsFromPolicy(string policy)
{
var options = new OpenIdConnectAuthenticationOptions
{
Notifications = new OpenIdConnectAuthenticationNotifications
{
...
RedirectToIdentityProvider = SetSettingsForRequest
}
}
}
private Task SetSettingsForRequest(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
var siteContext = DependencyResolver.Current.GetService<ISiteContext>();
context.ProtocolMessage.ClientId = siteContext.ClientId;
return Task.FromResult(0);
}
The error happens when trying to use the DependencyResolver in SetSettingsForRequest. I have no clue as to what I am doing wrong here. Currently I have no Autofac DI setup in my Startup Configuration(IAppBuilder app)
method, since this is already setup in my MVC project.
回答1:
As Mickaël Derriey pointed out, the following code is a solution to being able to resolve request-scoped dependencies in OWIN:
public class Startup
{
public void Configuration(IAppBuilder app)
{
var builder = new ContainerBuilder();
// Register dependencies, then...
var container = builder.Build();
// Register the Autofac middleware FIRST. This also adds
// Autofac-injected middleware registered with the container.
app.UseAutofacMiddleware(container);
// ...then register your other middleware not registered
// with Autofac.
}
}
and then use in any later code to resolve a dependency:
// getting the OWIN context from the OWIN context parameter
var owinContext = context.OwinContext;
var lifetimeScope = owinContext.GetAutofacLifetimeScope();
var siteContext = lifetimeScope.GetService<ISiteContext>();
context.ProtocolMessage.ClientId = siteContext.ClientId;
Using this solution, I did not have any issues anymore resolving request-scoped dependencies, since Autofac seems to accord to the OWIN way of creating/disposing of a request scope.
回答2:
I'm afraid that at this point you need to set up DI in the OWIN pipeline. It's not a difficult operation.
You'll have to:
- follow the steps listed in the official documentation on OWIN integration with ASP.NET MVC
- move your existing registration code (that is most probably in
Global.asax.cs
inStartup.cs
as the documentation linked above shows
Doing this means Autofac will create the per-request lifetime scope lower in the stack, at the OWIN level. This will allow you to get hold of the HTTP request lifetime scope from the OWIN context:
private Task SetSettingsForRequest(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
{
// getting the OWIN context from the OIDC notification context
var owinContext = context.OwinContext;
// that's an extension method provided by the Autofac OWIN integration
// see https://github.com/autofac/Autofac.Owin/blob/1e6eab35b59bc3838bbd2f6c7653d41647649b01/src/Autofac.Integration.Owin/OwinContextExtensions.cs#L19
var lifetimeScope = owinContext.GetAutofacLifetimeScope();
var siteContext = lifetimeScope.GetService<ISiteContext>();
context.ProtocolMessage.ClientId = siteContext.ClientId;
return Task.FromResult(0);
}
I hope this helps you get over that issue.
来源:https://stackoverflow.com/questions/45160188/resolve-autofac-dependencies-in-owin-startup-class