문제

I am using Unity as my IoC framework and I am creating a type based on the value in the header of each request in a handler:

var container = new UnityContainer();

container.RegisterType<IFoo,Foo>(new InjectionConstructor(valuefromHeader));

GlobalConfiguration.Configuration.DependencyResolver = 
    new Unity.WebApi.UnityDependencyResolver(container);

The problem is that the handler's SendAsync means that the global container is getting overwritten by different requests and the controllers that use IFoo in their constructor are getting the wrong values.

1) Can I make the SendAsync sync? 2) If not, how do I create different instances for each request and have the IoC container resolve safely?

I have looked at the following articles without success:

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver http://www.strathweb.com/2012/11/asp-net-web-api-and-dependencies-in-request-scope/ http://benfoster.io/blog/per-request-dependencies-in-aspnet-web-api-using-structuremap

Thanks in advance.

도움이 되었습니까?

해결책

I agree with @Steven's approach, but that doesn't answer your more general question of how to resolve per request.

I would recommend you change to using the UnityHierarchicalDependencyResolver and then anything you register with HierarchicalLifetimeManager will be resolved per request.

Change this...

GlobalConfiguration.Configuration.DependencyResolver = 
    new Unity.WebApi.UnityDependencyResolver(container);

to this...

GlobalConfiguration.Configuration.DependencyResolver = 
    new Unity.WebApi.UnityHierarchicalDependencyResolver(container);

다른 팁

The problem you are having is caused by you mixing runtime values with design time dependencies. In general, the services you resolve from the container should not depend on runtime values in their constructor. You shouldn't do this, because components tend to live much longer than runtime values and injecting runtime values into components, makes it much harder to diagnose and verify the container's configuration.

Instead, hide that value behind a service that can provide consumers with that instance when required. For instance:

public interface IHeaderValueProvider
{
    HeaderValue GetCurrentValue();
}

You can create an implementation that can be easily registered and injected into any component that needs that value. Anytime after the construction phase, those components can call the GetCurrentValue() method on the injected IHeaderValueProvider dependency.

I managed to resolve per request by declaring my custom UnityResolver's class within the WebApiConfig class. The UnityResolver class uses the HttpConfiguration class assuming you're using an OWIN context.

public static void Register(HttpConfiguration config)
        {    
            // Web API configuration and services
            var _container = new UnityContainer();
            DependencyConfiguration.ConfigureContainer(_container);
            config.DependencyResolver = new UnityResolver(_container);
         }

The ConfigureContainer class is simply a class where I declare my IOC dependencies as shown below:

private static void RegisterReleaseEnv(IUnityContainer container)
        {
            //Repository Registration
            container             
              .RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());

        }

It is very important that you use the HierarchicalLifetimeManager lifetime manager so that you get a new instance per request.

The UnityResolver class then looks like this:

public class UnityResolver : IDependencyResolver
    {
        protected IUnityContainer container;

        public UnityResolver(IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return container.Resolve(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return container.ResolveAll(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return new List<object>();
            }
        }

        public IDependencyScope BeginScope()
        {
            var child = container.CreateChildContainer();
            return new UnityResolver(child);
        }

        public void Dispose()
        {
            container.Dispose();
        }
    }

I hope this helps.

For more information: http://www.asp.net/web-api/overview/advanced/dependency-injection

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top