Autofac scope issues - c#

I am trying to get autofac to work, but having issues with my unitofwork / user manager classes.
Initially I set my unit of work up as a per request instance like this:
builder.RegisterType<UnitOfWork<DatabaseContext>>().As<IUnitOfWork>().InstancePerRequest();
But in my StartupConfig.cs I was trying to set up oAuth like this:
private static OAuthAuthorizationServerOptions ConfigureOAuthTokenGeneration(IAppBuilder app, ILifetimeScope scope)
{
var t = scope.Resolve<IPasswordHasher>();
// Get our providers
var authProvider = scope.Resolve<OAuthProvider>();
var refreshTokenProvider = scope.Resolve<IAuthenticationTokenProvider>();
// Create our OAuth options
return new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true, // TODO: Remove this line
TokenEndpointPath = new PathString("/oauth/access_token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
AccessTokenFormat = new Business.Authentication.JwtFormat("http://localhost:62668"),
Provider = authProvider,
RefreshTokenProvider = refreshTokenProvider
};
}
The scope is obtained by this:
var scope = config.DependencyResolver.GetRootLifetimeScope();
Because of this, I could not use InstancePerRequest for the UnitOfWork, instead I changed it to this:
builder.RegisterType<UnitOfWork<DatabaseContext>>().As<IUnitOfWork>().InstancePerLifetimeScope();
Now the application actually runs, but I get a new error with my UserProvider, it is instantiated like this:
builder.RegisterType<UserProvider>().As<IUserProvider>().InstancePerRequest();
But if I run that, I get this error:
No scope with a tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested.
If you see this during execution of a web application, it generally indicates that a component registered as per-HTTP request is being requested by a SingleInstance() component (or a similar scenario). Under the web integration always request dependencies from the dependency resolver or the request lifetime scope, never from the container itself.
This is actually being invoked by the line:
var authProvider = scope.Resolve<OAuthProvider>();
which is in my StartupConfig.cs. The OAuthProvider does need the UserProvider, the signature looks like this:
public OAuthProvider(IAdvancedEncryptionStandardProvider helper, IUserProvider userProvider)
{
this._helper = helper;
this._userProvider = userProvider;
}
So because this is not in the "request", I changed the UserProvider to be resolved like this:
builder.RegisterType<UserProvider>().As<IUserProvider>().InstancePerLifetimeScope();
which matches the UnitOfWork now, the project will load. But if I have an interface that tries to do 2 things (get the current user and list all users) it creates 2 requests, both creating a new instance of the UserController:
public UsersController(IUserProvider provider)
{
this._provider = provider;
}
which in turn tries to create 2 instances of the UserProvider. This throws an error:
The context cannot be used while the model is being created. This exception may be thrown if the context is used inside the OnModelCreating method or if the same context instance is accessed by multiple threads concurrently. Note that instance members of DbContext and related classes are not guaranteed to be thread safe.
So, I guess I need to know how I can resolve this.
It's like I need 2 scopes, one for the start of the application and then another for everything else.
Can anyone help me with this?

The issue
Since, at the time of the OWIN middleware registration, you need to provide an instance of OAuthAuthorizationServerOptions, there's no way to resolve the Provider and RefreshTokenProvider properties per HTTP request.
What we need is a way to create the OAuthAuthorizationServerOptions per HTTP request. By extension, the same concept would apply to the OAuthAuthorizationServerMiddleware.
A possible solution
That's exactly what AutofacMiddleware<T> does; It wraps an OWIN middleware by resolving it during the HTTP request from the lifetime scope stored in the OWIN context, then executes it. This means that we can now instantiate a new OAuthAuthorizationServerMiddleware for each HTTP request.
As explained in the documentation, when you use app.UseAutofacMiddleware(container) in your Startup class, Autofac does 2 things:
it hooks itself in the OWIN pipeline to create a nested lifetime scope for each HTTP request
it wraps all the OwinMiddleware services registered in the container with AutofacMiddleware and adds them to the OWIN pipeline
The solution is then to register OAuthAuthorizationServerMiddleware and all its dependencies in the Autofac container, and it will be automatically resolved for each request and executed.
OAuthAuthorizationServerMiddleware has 3 dependencies:
The next OWIN middleware in the pipeline, which AutofacMiddleware takes care of as it provides it to the Resolve method - TypedParameter.From(this.Next)
An instance of IAppBuilder
The OAuthAuthorizationServerOptions instance
We have to register the last two dependencies plus the middleware itself in the container. Let's have a look at what this could look like:
Disclaimer: I didn't try the code below
// Here go all the registrations associated with the `Provider`
// and `RefreshTokenProvider` properties with the appropriate lifetimes
builder
.RegisterInstance(app)
.As<IAppBuilder>();
builder
.Register(x => new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true, // TODO: Remove this line
TokenEndpointPath = new PathString("/oauth/access_token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
AccessTokenFormat = new Business.Authentication.JwtFormat("http://localhost:62668"),
Provider = x.Resolve<OAuthProvider>(),
RefreshTokenProvider = x.Resolve<IAuthenticationTokenProvider>()
})
.AsSelf()
// InstancePerDependency is same as InstancePerLifetimeScope
// in this case since the middleware will get resolved exactly one
// time per HTTP request anyway
.InstancePerDependency();
builder.RegisterType<OAuthAuthorizationServerMiddleware>();
Controlling the middleware order
While this could work, it's possible that it doesn't suit your needs since the OAuth middleware will be registered in the OWIN pipeline where you call app.UseAutofacMiddleware(container).
If you want more control over middleware order, you can separate the Autofac lifetime scope creation from the middleware registration in the OWIN pipeline:
Disclaimer: I didn't try the code below
// creates the per HTTP request lifetime scope
app.UseAutofacLifetimeScopeInjector(container);
// "usual" OWIN middlewares registrations
app.UseFoo();
// now use one from the container
app.UseMiddlewareFromContainer<OAuthAuthorizationServerMiddleware>();
// other "usual" OWIN middlewares registrations
app.UseBar();

Related

StructureMap DbContext with identity

So i have recently started using structure map. I have a web api using identity. My goal is to have a dbcontext per request. Currently i am having context issues, the context injected through structure map is different to the one being used by the user manager. I have looked around and cant find a solution even though im sure its pretty obvious.
So to start with i have my structuremap setup.
public class DefaultRegistry : Registry {
#region Constructors and Destructors
public DefaultRegistry() {
Scan(
scan => {
scan.TheCallingAssembly();
scan.AddAllTypesOf<IImporterService>().NameBy(type => type.Name);
scan.WithDefaultConventions();
});
For<IHttpContextBaseWrapper>().Use<HttpContextBaseWrapper>();
For<ApplicationDbContext>().Use(() => new ApplicationDbContext());
For<HttpContextBase>().Use(() => new HttpContextWrapper(HttpContext.Current));
}
#endregion
}
I do not need to inject the user manager for the moment as its accessed through the httpcontext in a base service, i know this will probably have to change for unit testing in the future.
Next we have the startup auth.
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
//Token Auth
var OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/account/login"),
Provider = new ApplicationOAuthProvider("self"),
AuthorizeEndpointPath = new PathString("/api/AccountApi/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(121),
RefreshTokenProvider = new ApplicationRefreshTokenProvider(),
//#if DEBUG
AllowInsecureHttp = true,
//#endif
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
I have cut down the code but i have the typical structure of service and repository layers. All inject using structuremap, the service and repositories have the correct context, the only on that does not is the user manager. I know its the line below causing the issue:
app.CreatePerOwinContext(ApplicationDbContext.Create);
However like i said i am still getting used to structure map, i previously used unity and would just resolve the instance i need from the current container. Any help or guidance is much appreciated.
Your problem with all these lines:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
First you tell a middleware to manage creation of your DbContext. Then you tell middleware to manage creation of your ApplicationUserManager and ApplicationUserManager.Create takes an instance of ApplicationDbContext managed by that middleware, not by your DI container. Same happens for your ApplicationRoleManager. At the end you have 2 ways of producing ApplicationDbContext per request - one through your DI container, another through middleware.
If you want to have only single instance of ApplicationDbContext you need to get rid of the second way of creation its' instance: ApplicationDbContext.Create. This will resolve your problem.
However your middleware still needs access to your ApplicationUserManager. So instead of all these:
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
you need to use app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());
And get rid of all other ways of creating these instances other than injection from your DI container.
Further info in my old blog post - scroll to "Clean up" part for the details about middleware registration.

Autofac and scope issues

Ok, this is starting to get on my nerves. I wish I had never started using Autofac, it has just become too difficult to use.
I have created a Module and I have set it up in the following way:
All services that do not require database interaction have been set
up as Singletons. These are generally the helper classes like the
EncryptionProvider, etc.
All services injected into controllers have been set up as InstancePerRequest for obvious reasons.
Any service that is injected into a controller service has been set up as InstancePerDependency.
I think that is the correct way to do things. And in theory it should work.
Now, in comes the "complications".
First off, the DbContext, I have looked about and I set this up as InstancePerDependency following my rules above.
Then I set up my OAuthProvider, UserManager and RefreshTokenService. My rules above would set the latter 2 as InstancePerRequest, but the RefreshTokenService and OAuthProvider (which has the UserManager injected into it) are needed in Startup.cs:
var config = new HttpConfiguration();
var scope = config.DependencyResolver.GetRootLifetimeScope();
// Get our providers
var authProvider = scope.Resolve<OAuthProvider>();
var refreshTokenProvider = scope.Resolve<IAuthenticationTokenProvider>();
// Create our OAuth options
return new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true, // TODO: Remove this line
TokenEndpointPath = new PathString("/oauth/access_token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
AccessTokenFormat = new Business.Authentication.JwtFormat("http://localhost:62668"),
Provider = authProvider,
RefreshTokenProvider = refreshTokenProvider
};
I did have all three set to InstancePerLifetimeScope but it was causing issues because UserManager.
So I then set them to InstancePerDependency and everything compiled, but I found that nothing was saving...
I really need to figure out how to do this before my manager tells me to remove Autofac. So, can anyone out there tell me how I should be registering the 3 problematic services?

PerHttpRequestLifeTimeManager for Unity with Web API and OWIN

I have a web service which is build using web API 5.23 with OWIN. I'm using Unity as IOC container.
This web service is consumed by a windows service that fires http requests every 2 seconds.
When the windows service starts, the following exception is thrown on the web service:
System.NotSupportedException occurred
HResult=-2146233067
Message=A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
From what I can tell two threads are trying to use the same instance of a DbContext, so creating a new DbContext on each request should solve my problem.
Looking at the LifeTimeManagers that Unity provides, it would seem that TransientLifetimeManager is the way to go since
TransientLifetimeManager. For this lifetime manager Unity creates and returns a new instance of the requested type for each call to the Resolve or ResolveAll method. This lifetime manager is used by default for all types registered using the RegisterType, method unless you specify a different lifetime manager.
For some reason this does not work and I am still getting the same exception.
After some more searching, I found PerRequestLifetimeManager . But I can't use it since I don't want to have a dependency of MVC. When I checked the way it is implemented I noticed that it dependes on IHttpModule. I am not sure if I can use this since I am using OWIN middleware to host my web service.
How can I implement a PerRequestLifetimeManager for Web API with OWIN?
Details just in case I am doing something wrong:
public static class MiddlewareContainer
{
public static void Register(IUnityContainer container)
{
container.RegisterType<DbContext, LicenceDbContext>(new TransientLifetimeManager());
container.RegisterType<IdentityDbContext<IdentityUser>, LicenceDbContext>(new TransientLifetimeManager());
container.RegisterType<IOAuthAuthorizationServerProvider, LicenceAuthorizationProvider>(new TransientLifetimeManager(),
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<AuthorizationProviderLoggingInterceptionBehavior>());
container.RegisterType<IDeploymentAuthRepository, DeploymentAuthRepository>(new TransientLifetimeManager());
container.RegisterType(typeof (UserManager<>), typeof (UserManager<>) ,new TransientLifetimeManager());
container.RegisterType(typeof (IUserStore<>), typeof (UserStore<>), new TransientLifetimeManager());
container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
container.RegisterType<IHttpActionResultProvider, HttpActionResultProvider>();
container.RegisterType<IClaimsIdentityFactory, ClaimsIdentityFactory>();
container.RegisterType<LoggingInterceptionBehavior, AuthorizationProviderLoggingInterceptionBehavior>();
container.RegisterType<ILogger, Logger>();
container.RegisterType<IIdentityProvider, IdentityProvider>();
container.RegisterType<IIdentityProviderFactory, IdentityProviderFactory>();
container.RegisterType<ILogger, Logger>();
container.RegisterType(typeof (IRepository<>), typeof (Repository<>));
container.RegisterType<IRepository<UserActivity>, UserActivityRepository>();
container.RegisterType<IRepository<Licence>, LicenceRepository>();
container.RegisterType<IJsonConverter, JsonConverter>();
container.RegisterType<IEqualityComparer<Message>, MessageComparer>();
container.RegisterType<System.Web.Http.ExceptionHandling.ExceptionLogger, GenericExceptionLogger>();
}
}
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
var container = new UnityContainer();
container.AddNewExtension<Interception>();
MiddlewareContainer.Register(container);
config.DependencyResolver = new UnityResolver(container);
ConfigureFilters(config, container);
ConfigureOAuth(app,container);
WebApiConfig.Register(config);
app.UseWebApi(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
Found the issue. It had nothing to do with Unity. In the Startup class I was calling
ConfigureOAuth(app,container);
From the code posted in the question, there is no way of knowing this could be an issue. (apologies for that).
Here is the content of the method.
public void ConfigureOAuth(IAppBuilder app, UnityContainer container)
{
OAuthAuthorizationServerOptions oAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(1),
Provider = container.Resolve<IOAuthAuthorizationServerProvider>()
};
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
When instantiating OAuthAuthorizationServerOptions, I have to also instantiate a Provider.
That provider is part of the OWIN pipeline and is instantiated only once, when the server starts. Each incoming request will hit that provider causing the above error. (Multiple requests are trying to use the same DbContext).
Making IOAuthAuthorizationServerProvider thread safe solved the issue, but that is not the ideal case.
The ideal solution would be to specify a providerFactory and that factory would create a new provider for each request.

Injecting a dependency into OWIN Middleware and per web-request with Simple Injector

I am trying to work out how to best inject all of my dependencies into the custom OWIN Middleware I have written for a Web API Application. A simple example would be the DbContext I am using. I have some middleware that needs to potentially query based on the request. The issue I have is that I want my DbContext to otherwise have a WebApiRequestLifestyle scope. My DbContext is registered as such:
container.Register<MobileDbContext>(Lifestyle.Scoped);
Obviously, this does not work:
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle();
Because I need the MobileDbContext in my Middleware using something like:
app.CreatePerOwinContext(() =>
{
return container.GetInstance<MobileDbContext>();
};
I tried a hybrid lifestyle, but that also didn't work because I don't think the Middleware is technically something that can fall under a "scoped" lifestyle. It is probably closer to a singleton, I would think.
Is there a better way to design my app to avoid this problem or address it with some sort of custom scoped lifestyle?
The documentation shows an example of how to wrap an OWIN request in a scope:
public void Configuration(IAppBuilder app) {
app.Use(async (context, next) => {
using (AsyncScopedLifedtyle.BeginScope (container)) {
await next();
}
});
}
What this does is wrapping an OWIN request in an execution context scope. All you have to do now is make the execution contest scope the default scoped lifestyle as follows:
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

Autofac Lifetimes and the Default Provider within a Matching Lifetime Scope

I have an ASP.NET MVC web application using Autofac for dependency injection. Occasionally, this web application will start a thread to do some work separate from the request thread. When this background thread starts up, it establishes a new Autofac lifetime scope from the root container and runs some action.
public IAsyncResult Run<T>(Action<T> action)
{
var NewTask = System.Threading.Tasks.Task.Factory.StartNew(() =>
{
using (var Scope = Runtime.Container.BeginLifetimeScope())
{
var Input = Scope.Resolve<T>();
action(Input);
}
});
return NewTask;
}
One of my dependencies registered with Autofac has two different implementations: one appropriate for http-request lifetimes and another appropriate for all other lifetimes. I tried to register them as follows:
builder
.Register(c => new Foo())
.As<IFoo>()
.InstancePerLifetimeScope();
builder
.Register(c => new FooForHttp(HttpContext.Current))
.As<IFoo>()
.InstancePerMatchingLifetimeScope(WebLifetime.Request);
Autofac selects FooForHttp for http requests (as expected). However, when my background thread spins up, any attempt to resolve IFoo results in an exception:
No scope with a Tag matching 'httpRequest' is visible from the scope
in which the instance was requested. This generally indicates that a
component registered as per-HTTP request is being reqested by a
SingleInstance() component (or a similar scenario.) Under the web
integration always request dependencies from the
DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime,
never from the container itself.
I know that Autofac always uses the last registered provider as the default provider for a particular component. I made an assumption here that it would use the last registered suitable provider.
Am I missing something, or is there a better approach to selecting a provider based on the tag of the current lifetime scope?
Register the web Foo as normal, but don't register the other Foo. When creating the lifetime scope for the async task, use the overload of BeginLifetimeScope() that takes an action on ContainerBuilder. Register the background Foo in this action (b => b.Register()) and this should override the web one. (Small keyboard here sorry :))
This can also be solved by using a tagged life time scope.
Register your fisrt Foo as instance of your tagged scope:
builder.RegisterType<Foo>().As<IFoo>.InstancePerMatchingLifetimeScope("YourScopeTag");
And create the scope with the same tag you registered your dependencie:
using (var Scope = Runtime.Container.BeginLifetimeScope("YourScopeTag"))
{
var Input = Scope.Resolve<T>();
action(Input);
}
Haven't tested it, but it should work
http://docs.autofac.org/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope

Categories