1
votes

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);
    }
1
I'd like to see an answer for this as well. I tried for quite a some time to get Unity to behave properly with a per request, but it never worked and caused issues with EF and the DbContext. I've switched over to SimpleInjector to accomplish this when needed, but I'd really like to get Unity to work.ManOVision

1 Answers

3
votes

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.