Dependency injecting UserStore in OWIN startup using Ninject OWIN middleware - c#

I am having problems creating a custom UserStore using dependency injection when creating an ApplicationUserManager using the OWIN request pipeline.
Background
I am trying to migrate the user functionality in our web application from using the SimpleMembership to the new ASP.NET Identity. When starting a new MVC 5 project, the default implementation of the single page application uses ASP.Identity, using Entity Framework to implement the UserStore functionality.
In my case, we are already using NHibernate as the ORM, and using ninject to implement the unit of work pattern so that we had one NHibernate session per request, and I wanted to make the ASP.Identity work with our existing framework.
To this end, I created a custom UserStore, which could be created by injecting the relevant repositories/nhibernate session, etc. This could then be injected into the Controller's constructor using Ninject, rather than using the default implementation's GetOwinContext functionality.
In order to do this, I had commented out the following line in the ConfigureAuth(IAppBuilder app) method of the Startup, which by default creates the UserManager class:
// app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
Instead, I used the NinjectWebCommon created when installing the Ninject.Web.Common.Webhost nuget package to create the relevant bindings.
This implementation worked fine with some of the UserManager operations, but with some operations, such as ResetPasswordAsync, it fails because the default ApplicationUserManager implementation is not called, and so the UserTokenProvider in the UserManager class is never set:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
manager.UserValidator = new UserValidator<ApplicationUser>(manager)
{
AllowOnlyAlphanumericUserNames = false,
RequireUniqueEmail = true
};
// Configure validation logic for passwords
manager.PasswordValidator = new PasswordValidator
{
RequiredLength = 6,
RequireNonLetterOrDigit = true,
RequireDigit = true,
RequireLowercase = true,
RequireUppercase = true,
};
// Register two factor authentication providers. This application uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug in here.
manager.RegisterTwoFactorProvider("PhoneCode", new PhoneNumberTokenProvider<ApplicationUser>
{
MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", new EmailTokenProvider<ApplicationUser>
{
Subject = "Security Code",
BodyFormat = "Your security code is: {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();
var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
{
manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(dataProtectionProvider.Create("ASP.NET Identity"));
}
return manager;
}
Therefore, the UserTokenProvider is not set.
Problem
I want to use the OWIN pipeline, because Visual Studio's default implementation of the ApplicationUserManager class injects the IDataProtectionProvider in its Create callback method. However, I also want to create my UserStore using dependency Injection, and I do not know how to create a UserStore within this method using dependency injection.
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
// WANT TO CREATE THE USER STORE USING NINJECT DEPENDENCY INJECTION HERE
// var userStore = ...
var manager = new ApplicationUserManager(userStore);
}
I have tried to get around this limitation by using the Ninject.Web.Common.OwinHost nuget package and creating the kernel within the Startup class.
public void ConfigureAuth(IAppBuilder app)
{
// Setup
app.UseNinjectMiddleware(CreateKernel);
}
However, the Ninject.Web.Common.OwinHost does not expose its Kernel, so I am unable to use service location pattern to inject the values into my custom UserStore in the Create callback.
I have also tried to create a singleton Kernel, and register this using app.CreatePerOwinContext(CreateKernel) with the relevant delegate, so I could later access the Kernel, but when I call context.Get() it just returns null.
Question
How can I register a callback function with CreatePerOwinContext to create a custom UserManager which uses a custom UserStore, and then use Ninject to create the custom UserStore using dependency injection in the Create callback, so that I also have access to the IdentityFactoryOptions which Owin uses to inject the user token provider?

For info:
It is possible to register the kernel as a singleton so that the same kernel can be used by the ninject middleware and also registered within the owin context.
public static StandardKernel CreateKernel()
{
if (_kernel == null)
{
_kernel = new StandardKernel();
_kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
_kernel.Load(Assembly.GetExecutingAssembly(), Assembly.Load("Super.CompositionRoot"));
}
return _kernel;
}
The callback function app.CreatePerOwinContext(ApplicationUserManager.Create), will call the ApplicationUserManager.Create rather than register it to be called at a later point during the setup. Therefore, the CreateKernel function needs to be registered before the ApplicationUserManager's Create callback or you will get a null reference exception if you try to get the kernel from the owin context within that method.
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(CreateKernel);
app.UseNinjectMiddleware(CreateKernel);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
}
This will allow you to access the kernel to create a custom UserStore within the ApplicationUserManager's Create callback:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var kernel = context.Get<StandardKernel>();
var userStore = kernel.Get<IUserStore<User, int>>();
var manager = new ApplicationUserManager(userStore);
//...
}
I know that in general dependency injection should be favoured over service location, but in this context I couldn't see a way around it - unless anybody has any better suggestions?
This will allow you to use Ninject to implement the unit of work patter leveraging Ninject's InRequestScope().OnDeactivation functionality. I'm aware that the UserManager class has a per request lifetime, but didn't know the most the most appropriate way to commit any outstanding transactions on request finish.

Note This was for WebApi (using System.Web.Http)
Okay so I kind of cheated by using stuff from System.Web which is the namespace we're suppose to be weening ourselves off of, but while its still used, why not.
Firstly, I use some helpers from this SO question:
Configuring Ninject with Asp.Net MVC & Web Api
Within which, the resolver is registered with System.Web's global configuration. Thus, I just go grab it when I need it:
public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
var repository = System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver
.GetService(typeof(Data.Repositories.UserRepository)) as Data.Repositories.UserRepository;
var manager = new ApplicationUserManager(repository);
...
Note: I use the term Repository over Store since it matches the well-known pattern, more understandable to most people.
And the Startup.Auth looks like this, I basically move the Ninject init into here so its done in time:
public void ConfigureAuth(IAppBuilder app)
{
// Dependency Injection
Evoq.AppName.Configuration.Ninject.NinjectHttpContainer.RegisterAssembly();
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
...
I did also use a method similar to the OP where I 'attached' a callback to get the IKernel but while this keeps it all OWINy, the problem with this approach is that you have to call owinContextThing.Get<IKernel>() which means referencing Ninject deeper in my code.
There were ways around it, but it started getting more complex than my solution above.
Additional Note
This is the Identity Framework code that registers the callback. Note the call to app.GetDataProtectionProvider which is essentially the thing we originally needed to make a UserTokenProvider.
/// <summary>
/// Registers a callback that will be invoked to create an instance of type T that will be stored in the OwinContext which can fetched via context.Get
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="app"></param>
/// <param name="createCallback"></param>
/// <returns></returns>
public static IAppBuilder CreatePerOwinContext<T>(this IAppBuilder app, Func<IdentityFactoryOptions<T>, IOwinContext, T> createCallback) where T : class,IDisposable {
if (app == null) {
throw new ArgumentNullException("app");
}
if (createCallback == null) {
throw new ArgumentNullException("createCallback");
}
app.Use(typeof(IdentityFactoryMiddleware<T, IdentityFactoryOptions<T>>),
new IdentityFactoryOptions<T>() {
DataProtectionProvider = app.GetDataProtectionProvider(),
Provider = new IdentityFactoryProvider<T>() {
OnCreate = createCallback
}
});
return app;
}
I've looked and looked and reflected the libs and cannot find that method! If I knew how that worked, potentially we could find another way to create a token, i.e. wouldn't need the options instance.

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 scope issues

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();

Unity with ASP.NET Core and MVC6 (Core)

Update 09.08.2018
Unity is being developed here but I haven't had the time to test how it plays with the ASP.NET Core framework.
Update 15.03.2018
This solution is for the specific problem of using ASP.NET Core v1 with Unity while using the .NET Framework 4.5.2 NOT the .NET Core Framework. I had to use this setup since I needed some .Net 4.5.2 DLLs but for anyone starting afresh I would not recommend this approach. Also Unity is not being developed any further (to my knowlage) so I would recommend using the Autofac Framework for new projects. See this Post for more info on how to do that.
Intro
I am building a Web Application using ASP.NET with MVC. This Application depends on certain services (a WCF Service a Datastore service etc). Now to keep things nice and decoupled I want to use a DI (Dependecy Injection) Framework, specifically Unity.
Initial Research
I found this blog post but sadly its not working. The idea though is nice. It basically says that you should not register all the services registered in the ServiceCollection into your own container, but rather reference the default ServiceProvider. So. if something needs to be resolved the default ServiceProvider is called and in case it has no resolution the type will be resolved using your custom UnityContainer.
The Problems
MVC always tries to resolve the Controller with the default ServiceProvider. Also, I noticed that even if the Controller would get resolved correctly, I can never "mix" Dependencies. Now, if I want to use one of my Services but also an IOptions interface from ASP the class can never be resolved because not one of those two containers has resolutions for both types.
What I need
So to recap I need the following things:
A setup where I dont need to copy ASP.NET Dependencies into my UnityContainer
A container which can resolve my MVC Controllers
A container which can resolve "mixed" Dependencies
EDIT:
So the question is how can I achieve these points ?
Environment
project.json:
So after some research I came up with the following solutions to my problems:
Use Unity with ASP
To be able to use Unity with ASP I needed a custom IServiceProvider (ASP Documentation) so I wrote a wrapper for the IUnityContainer which looks like this
public class UnityServiceProvider : IServiceProvider
{
private IUnityContainer _container;
public IUnityContainer UnityContainer => _container;
public UnityServiceProvider()
{
_container = new UnityContainer();
}
#region Implementation of IServiceProvider
/// <summary>Gets the service object of the specified type.</summary>
/// <returns>A service object of type <paramref name="serviceType" />.-or- null if there is no service object of type <paramref name="serviceType" />.</returns>
/// <param name="serviceType">An object that specifies the type of service object to get. </param>
public object GetService(Type serviceType)
{
//Delegates the GetService to the Containers Resolve method
return _container.Resolve(serviceType);
}
#endregion
}
Also I had to change the Signature of the ConfigureServices method in my Startup class from this:
public void ConfigureServices(IServiceCollection services)
to this:
public IServiceProvider ConfigureServices(IServiceCollection services)
Now I can return my custom IServiceProvider and it will be used instead of the default one.The full ConfigureServices Method is shown in the Wire up section at the bottom.
Resolving Controllers
I found this blog post. From it I learned that MVC uses an IControllerActivator interface to handle Controller instantiation. So I wrote my own which looks like this:
public class UnityControllerActivator : IControllerActivator
{
private IUnityContainer _unityContainer;
public UnityControllerActivator(IUnityContainer container)
{
_unityContainer = container;
}
#region Implementation of IControllerActivator
public object Create(ControllerContext context)
{
return _unityContainer.Resolve(context.ActionDescriptor.ControllerTypeInfo.AsType());
}
public void Release(ControllerContext context, object controller)
{
//ignored
}
#endregion
}
Now if a Controller class is activated it will be instatiated with my UnityContainer. Therefore my UnityContainer must know how to Resolve any Controller!
Next Problem: Use the default IServiceProvider
Now if I register services such as Mvc in ASP.NET I normally would do it like this:
services.AddMvc();
Now if I use a UnityContainer all the MVC Dependencies could not be Resolved because they aren't Registered. So I can either Register them (like AutoFac) or I can create a UnityContainerExtension. I opted for the Extension and came up with following two clases :
UnityFallbackProviderExtension
public class UnityFallbackProviderExtension : UnityContainerExtension
{
#region Const
///Used for Resolving the Default Container inside the UnityFallbackProviderStrategy class
public const string FALLBACK_PROVIDER_NAME = "UnityFallbackProvider";
#endregion
#region Vars
// The default Service Provider so I can Register it to the IUnityContainer
private IServiceProvider _defaultServiceProvider;
#endregion
#region Constructors
/// <summary>
/// Creates a new instance of the UnityFallbackProviderExtension class
/// </summary>
/// <param name="defaultServiceProvider">The default Provider used to fall back to</param>
public UnityFallbackProviderExtension(IServiceProvider defaultServiceProvider)
{
_defaultServiceProvider = defaultServiceProvider;
}
#endregion
#region Overrides of UnityContainerExtension
/// <summary>
/// Initializes the container with this extension's functionality.
/// </summary>
/// <remarks>
/// When overridden in a derived class, this method will modify the given
/// <see cref="T:Microsoft.Practices.Unity.ExtensionContext" /> by adding strategies, policies, etc. to
/// install it's functions into the container.</remarks>
protected override void Initialize()
{
// Register the default IServiceProvider with a name.
// Now the UnityFallbackProviderStrategy can Resolve the default Provider if needed
Context.Container.RegisterInstance(FALLBACK_PROVIDER_NAME, _defaultServiceProvider);
// Create the UnityFallbackProviderStrategy with our UnityContainer
var strategy = new UnityFallbackProviderStrategy(Context.Container);
// Adding the UnityFallbackProviderStrategy to be executed with the PreCreation LifeCycleHook
// PreCreation because if it isnt registerd with the IUnityContainer there will be an Exception
// Now if the IUnityContainer "magically" gets a Instance of a Type it will accept it and move on
Context.Strategies.Add(strategy, UnityBuildStage.PreCreation);
}
#endregion
}
UnityFallbackProviderStrategy:
public class UnityFallbackProviderStrategy : BuilderStrategy
{
private IUnityContainer _container;
public UnityFallbackProviderStrategy(IUnityContainer container)
{
_container = container;
}
#region Overrides of BuilderStrategy
/// <summary>
/// Called during the chain of responsibility for a build operation. The
/// PreBuildUp method is called when the chain is being executed in the
/// forward direction.
/// </summary>
/// <param name="context">Context of the build operation.</param>
public override void PreBuildUp(IBuilderContext context)
{
NamedTypeBuildKey key = context.OriginalBuildKey;
// Checking if the Type we are resolving is registered with the Container
if (!_container.IsRegistered(key.Type))
{
// If not we first get our default IServiceProvider and then try to resolve the type with it
// Then we save the Type in the Existing Property of IBuilderContext to tell Unity
// that it doesnt need to resolve the Type
context.Existing = _container.Resolve<IServiceProvider>(UnityFallbackProviderExtension.FALLBACK_PROVIDER_NAME).GetService(key.Type);
}
// Otherwise we do the default stuff
base.PreBuildUp(context);
}
#endregion
}
Now if my UnityContainer has no Registration for something it just ask the default Provider for it.
I learned all of this from several different articles
MSDN Unity article
Auto-Mocking Unity Container Extension
Custom Object Factory Unity Extension
The nice thing about this approach is that I can also "mix" Dependencies now. If I need any of my Services AND an IOptions Interface from ASP my UnityContainer will resolve all of these Dependencies and Inject them into my Controller !!! The only thing to remember is that if I use any of my own Dependencies I have to register my Controller class with Unity because the default IServiceProvider can no longer Resolve my Controllers Dependencies.
Finally: Wire up
Now in my project I use different services (ASP Options, MVC with options). To make it all work my ConfigureServices Method looks like this now:
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// Add all the ASP services here
// #region ASP
services.AddOptions();
services.Configure<WcfOptions>(Configuration.GetSection("wcfOptions"));
var globalAuthFilter = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
services.AddMvc(options => { options.Filters.Add(new AuthorizeFilter(globalAuthFilter)); })
.AddJsonOptions
(
options => options.SerializerSettings.ContractResolver = new DefaultContractResolver()
);
// #endregion ASP
// Creating the UnityServiceProvider
var unityServiceProvider = new UnityServiceProvider();
IUnityContainer container = unityServiceProvider.UnityContainer;
// Adding the Controller Activator
// Caution!!! Do this before you Build the ServiceProvider !!!
services.AddSingleton<IControllerActivator>(new UnityControllerActivator(container));
//Now build the Service Provider
var defaultProvider = services.BuildServiceProvider();
// Configure UnityContainer
// #region Unity
//Add the Fallback extension with the default provider
container.AddExtension(new UnityFallbackProviderExtension(defaultProvider));
// Register custom Types here
container.RegisterType<ITest, Test>();
container.RegisterType<HomeController>();
container.RegisterType<AuthController>();
// #endregion Unity
return unityServiceProvider;
}
Since I learned most of what I know about DI in the past week I hope I didnt break any big Pricipal/Pattern if so please tell me!
For ASP.Net Core 2.0, 2.1, 2.2, 3.1 and Unity there is official solution available from Unity authors as NuGet package here: NuGetPackage
Here is Git repository with samples: Git repo
Usage is very simple (from Git repo homepage):
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseUnityServiceProvider() <---- Add this line
.UseStartup<Startup>()
.Build();
And here is example with Unity DI for ASP.Net Core.
I am using this solution in my ASP.Net Core application and works good.

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.

SignalR and ASP.NET Identity's UserManager class lifetime

In my MVC application, I user SignalR for communication between users. Basically, a client calls a method on the hub, which calls a method on a repository, which then saves the message to the database and the hub notifies the other client of the new message.
I had used the GetOwinContext() method during these calls from the client to get the current instance of UserManager and ApplicationDbContext, by using the GetUserManager<UserManager>() and Get<ApplicationDbcontex>() extension methods, respectively. However, I have noticed that calls from the same connection use the same context, which is, obviously, not a very good thing. I went ahead and changed my repository so it is like this now:
public XyzRepository() //constructor
{
db = ApplicationDbContext.Create(); //static method that generates a new instance
}
private ApplicatonDbContext db { get; set; }
private UserManager UserManager
{
get
{
return new UserManager(new UserStore<ApplicationUser>(db)); //returns a new UserManager using the context that is used by this instance of the repository
}
}
Since I reference the ApplicationUser objects using the UserManager (using FindByIdAsync(), etc, depending on the design), it is extremely important to use the context I currently work with for the UserStore of the UserManager's current instance. The repository is created once per request, which seems to apply to each SignalR calls as intended. While I have experienced no problems with this design so far, after reading about the issue (in this article), particularly this line:
"In the current approach, if there are two instances of the UserManager in the request that work on the same user, they would be working with two different instances of the user object.", I decided to ask the community:
Question: what is the preferred way to use ASP.NET Identity's UserManager class with SignalR, if it is imperative that I use the same instance of DbContext for my repository's methods that the UserManager's UserStore uses?
I think the preferred way is to use an Inversion of Control container and constructor-inject dependencies with some kind of lifetime scope. Here is another question that you might want to look into:
Using Simple Injector with SignalR
It is preferable that your DbContext instance live as long as the current web request. IoC containers have facilities that let you register DbContext instances with per web request lifetimes, but you need to set up the IoC container so that it can manage the construction of the Hub classes to achieve this. Some IoC containers (like SimpleInjector) will also automatically dispose of the DbContext at the end of the web request for you, so you don't need to wrap anything in a using block.
As for the UserManager, XyzRepository, etc, I think those can also have per-web-request lifetime, or even transient lifetimes. Ultimately, I don't see why you wouldn't be able to achieve something like this:
public class MyXyzHub : Hub
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly MessageRepository _messageRepository;
public MyXyzHub(UserManager<ApplicationUser> userManager,
MessageRepository messageRepository)
{
_userManager = userManager;
_messageRepository= messageRepository;
}
public void sendMessage(string message)
{
var user = _userManager.FindByIdAsync(...
_messageRepository.CreateAndSave(new Message
{
Content = message, UserId = user.Id
});
Clients.All.receiveMessage(message, user.Name);
}
}
If you wire up your IoC container the right way, then every time the Hub is constructed, it should reuse the same ApplicationDbContext instance for the current web request. Also with your current code, it looks like XyzRepository is never disposing of your ApplicationDbContext, which is another problem that an IoC container can help you out with.

Categories