एकता का उपयोग करके ASP.NET वेब एपीआई नियंत्रक में निर्भरता को शामिल नहीं किया जा सकता


82

क्या किसी को ASP.NET WebAPI नियंत्रकों में निर्भरता को इंजेक्ट करने के लिए IoC कंटेनर का उपयोग करके कोई सफलता मिली है? मैं इसे काम करने के लिए प्राप्त करने के लिए प्रतीत नहीं कर सकता।

यही मैं अभी कर रहा हूं।

मेरे में global.ascx.cs:

    public static void RegisterRoutes(RouteCollection routes)
    {
            // code intentionally omitted 
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = BuildUnityContainer();

        System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
            t =>
            {
                try
                {
                    return container.Resolve(t);
                }
                catch (ResolutionFailedException)
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return container.ResolveAll(t);
                }
                catch (ResolutionFailedException)
                {
                    return new System.Collections.Generic.List<object>();
                }
            });

        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 

        BundleTable.Bundles.RegisterTemplateBundles();
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer().LoadConfiguration();

        return container;
    }

मेरा नियंत्रक कारखाना:

public class UnityControllerFactory : DefaultControllerFactory
            {
                private IUnityContainer _container;

                public UnityControllerFactory(IUnityContainer container)
                {
                    _container = container;
                }

                public override IController CreateController(System.Web.Routing.RequestContext requestContext,
                                                    string controllerName)
                {
                    Type controllerType = base.GetControllerType(requestContext, controllerName);

                    return (IController)_container.Resolve(controllerType);
                }
            }

यह निर्भरता को हल करने के लिए मेरी एकता फ़ाइल में कभी नहीं लगता है, और मुझे एक त्रुटि मिलती है:

'PersonalShopper.Services.WebApi.Controllers.hoppingListController' का नियंत्रक बनाने का प्रयास करते समय एक त्रुटि हुई। सुनिश्चित करें कि नियंत्रक के पास एक पैरामीटर रहित सार्वजनिक निर्माता है।

System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create (HttpControllerContext कंट्रोलर कंट्रोलटेक्स्ट, टाइप कंट्रोलर टाइप करें) System.Web.Http.Dispatcher.DefaultHttpControllerFactory.Create (रूटर)। (HttpControllerContext नियंत्रकContext, String कंट्रोलरनाम) System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal (HttpRequestMessage अनुरोध पर, रद्द कर दिया गया है।

नियंत्रक जैसा दिखता है:

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;


        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}

मेरी एकता फ़ाइल इस प्रकार है:

<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <container>
    <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" />
  </container>
</unity>

ध्यान दें कि मेरे पास स्वयं नियंत्रक के लिए पंजीकरण नहीं है क्योंकि mvc के पिछले संस्करणों में नियंत्रक कारखाना यह पता लगाएगा कि निर्भरता को हल करने की आवश्यकता है।

ऐसा लगता है जैसे मेरे नियंत्रक कारखाने को कभी नहीं बुलाया जा रहा है।

जवाबों:


42

पता लगा लिया।

के लिए ApiControllers , MVC 4 एक का उपयोग करता है System.Web.Http.Dispatcher.IHttpControllerFactory और System.Web.Http.Dispatcher.IHttpControllerActivator नियंत्रक बनाने के लिए। यदि इनको लागू करने के लिए कोई स्थैतिक विधि दर्ज नहीं है; जब वे हल हो जाते हैं, तो निर्भरता रिज़ॉल्वर में कार्यान्वयन के लिए mvc फ्रेमवर्क दिखता है, और यदि वे नहीं मिलते हैं, तो डिफ़ॉल्ट कार्यान्वयन का उपयोग करता है।

मुझे निम्न कार्य करके नियंत्रक निर्भरता का एकता संकल्प मिला:

एक UnityHttpControllerActivator बनाया गया:

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private IUnityContainer _container;

    public UnityHttpControllerActivator(IUnityContainer container)
    {
        _container = container;
    }

    public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);
    }
}

एकता कंटेनर में कार्यान्वयन के रूप में उस नियंत्रक कार्यकर्ता को पंजीकृत किया गया:

protected void Application_Start()
{
    // code intentionally omitted

    IUnityContainer container = BuildUnityContainer();
    container.RegisterInstance<IHttpControllerActivator>(new UnityHttpControllerActivator(container));

    ServiceResolver.SetResolver(t =>
       {
         // rest of code is the same as in question above, and is omitted.
       });
}

आपने लमडा को कैसे लागू किया GlobalConfiguration.Configuration.ServiceResolver.SetResolver()?
jrummell

7
यह पोस्ट पुराना है। एमवीसी आरसी के साथ क्लीनर समाधान के लिए कोडकटा द्वारा उत्तर देखें।
मैट रैंडल

यह पुराना है। Microsoft के पास एक Nuget पैकेज है जो Web API के साथ DI करता है। मेरा जवाब देखिए।
गारेथब

37

एक बेहतर समाधान है जो यहां सही ढंग से काम करता है

http://www.asp.net/web-api/overview/extensibility/using-the-web-api-dependency-resolver


1
एमवीसी आरसी के साथ यह एक बेहतर समाधान है। आपको IHttpControllerActivator का कार्यान्वयन प्रदान करने की आवश्यकता नहीं है। आप इसके बजाय System.Web.Http.Dependencies.ID dependencyResolver लागू करें।
मैट रैंडल

22
ब्लॉग से लिंक करने का बड़ा प्रशंसक नहीं है - क्या आप यहां संक्षेप में बता सकते हैं और लिंक डाल सकते हैं? :)
नैट-विल्किंस

3
यह एक अच्छे दृष्टिकोण की तरह दिखता है, लेकिन मुझे निम्नलिखित जैसी कई त्रुटियां हो रही हैं। ऐसा लगता है कि नई रिज़ॉल्वर कई प्रकारों को हल नहीं कर सकती है। निर्भरता का संकल्प विफल हुआ, टाइप करें = "System.Web.Http.Hosting.IHostBufferPolicySelector", name = "(none)"। अपवाद तब हुआ जब: समाधान करते समय। अपवाद है: InvalidOperationException - IHostBufferPolicySelector प्रकार में एक सुलभ कंस्ट्रक्टर नहीं है। --- अपवाद के समय, कंटेनर था: हल System.Web.Http.Hosting.IHostBufferPolicySelector, (
ATHER

Microsoft के पास एक Nuget पैकेज है जो Web API के साथ DI करता है। मेरा जवाब देखिए।
गारेथ

24

आप Unity.WebApi NuGet पैकेज पर एक नज़र डालना चाहते हैं, जो इन सभी को छाँटेगा और आईडीआरोप्लोबिन घटकों को भी पूरा करेगा।

देख

http://nuget.org/packages/Unity.WebAPI

या

http://www.devtrends.co.uk/blog/introducing-the-unity.webapi-nuget-package


2
यहाँ एक अच्छा ब्लॉग पोस्ट है ( netmvc.blogspot.com/2012/04/… ) जिसमें Unity.mvc3 (MVC4 के साथ काम करता है), और Unit.WebApi के संयोजन का उपयोग करने का एक पूर्वाभ्यास है जो DI को बहुत सफाई से लागू करता है।
फ्रेड मेनहर्ट 20

1
टिप्पणी में उल्लिखित लिंक अद्यतन किए गए एपीआई को दर्शाता है, जो भी इस समय आता है: GlobalConfiguration.Configuration.ServiceResolver.SetResolver (new Unity.WebApi.UnityD dependencyResortver (कंटेनर)); अब GlobalConfiguration.Configuration.D dependencyResolver = new Unity.WebApi.UnityD dependencyResolver (कंटेनर) है;
रॉबर्ट ज़ह्म

ध्यान दें, यह कस्टम की तुलना में बेहतर डीबगिंग संदेश भी प्रदान करता है UnityResolver
आयोनिस करदीमास

9

Microsoft ने इसके लिए एक पैकेज बनाया है।

पैकेज मैनेजर कंसोल से निम्न कमांड चलाएँ।

स्थापना-पैकेज Unity.AspNet.WebApi

यदि आपके पास पहले से एकता स्थापित है, तो यह पूछेगा कि क्या आप App_Start \ UnityConfig.cs को अधिलेखित करना चाहते हैं। उत्तर दें और जारी रखें।

किसी अन्य कोड को बदलने की आवश्यकता नहीं है और डीआई (एकता के साथ) काम करेगा।


क्या आप मुझे बता सकते हैं कि क्यों हम 'नहीं' का जवाब देते हैं जब नगेट यूनिटीकोन्फिग.क को अधिलेखित करने का संकेत देता है? प्रश्न 2: Unity.AspNet.WebApi का उपयोग करने के लिए कुछ नमूना कोड हैं?
थॉमस.बेंक

क्षमा करें, मैं ऑटोफ़ैक में बदल गया हूं क्योंकि मुझे कुछ चीजें चाहिए थीं जो एकता ने आसानी से नहीं की और ऑटोफैक बॉक्स से बाहर हो गया। लेकिन स्मृति से आपको यह कहने की आवश्यकता नहीं है कि यदि आपके पास पहले से ही एकता स्थापित है, जैसा कि आप अपने पहले से काम कर रहे एकता कॉन्फ़िगरेशन को अधिलेखित नहीं करना चाहते हैं, तो यूओ केवल एकता वेबपीआई कॉन्फ़िगरेशन को जोड़ना चाहते हैं। वेबपी में एकता का उपयोग करने के लिए आप वास्तव में इसका उपयोग कैसे करेंगे। यदि यह आपकी निर्भरता को इंजेक्शन नहीं देता है जैसा कि यह आपके अन्य वर्गों के लिए करता है, तो मैं एक प्रश्न पोस्ट करने का सुझाव दूंगा। अन्य वर्गों (जैसे नियंत्रक) की तुलना में वेबैपी में इंजेक्शन लगाने का कोई अलग तरीका नहीं है
गैरेथ

@garethb: मैं unity.webapi का उपयोग कर रहा हूं, लेकिन कंट्रोलर कॉन्टेक्स्ट को हल करने के लिए यूनिट परीक्षणों में कोड की कुछ पंक्तियों को जोड़ना होगा जो मुझे पसंद नहीं है। मान लीजिए, अगर मैं Unity.AspNet.WebApi का उपयोग करता हूं, तो क्या UnitTech प्रोजेक्ट के भीतर कंट्रोलर कोनटेक्स्ट को स्वचालित रूप से हल करने वाला वह पता होगा? कृपया सुझाव दें
सैम

मुझे ऐसा नहीं लगता। यकीन है कि दोनों एक ही तरह से काम करते हैं। मैं अपनी इकाई परीक्षणों में एक नया नकली संदर्भ बनाता हूं।
गारेथब

@garethb: आपकी त्वरित प्रतिक्रिया के लिए धन्यवाद। मजाक का काम किया। मैं UrlHelper को Unity.WebApi या Unity.Aspnet.webapi का उपयोग करके इंजेक्ट करने में असमर्थ हूं। क्या आपको याद है कि जब आपने एकता का इस्तेमाल किया था तब आपने इसे कैसे किया था? अग्रिम धन्यवाद
सैम

3

मेरे पास एक ही त्रुटि थी और कुछ घंटों के लिए समाधान के लिए इंटरनेट खोज रहा था। आखिरकार यह सामने आया कि मुझे Unity BEFORE रजिस्टर करना था, जिसे मैं WebApiConfig.Register कह रहा था। मेरा Global.asax अब दिखता है

public class WebApiApplication : System.Web.HttpApplication
{
   protected void Application_Start()
   {
       UnityConfig.RegisterComponents();
       AreaRegistration.RegisterAllAreas();
       GlobalConfiguration.Configure(WebApiConfig.Register);
       FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
       RouteConfig.RegisterRoutes(RouteTable.Routes);
       BundleConfig.RegisterBundles(BundleTable.Bundles);
   }
}

मेरे लिए यह समस्या हल हो गई कि एकता मेरे नियंत्रकों में निर्भरता को हल नहीं कर सकती है


2

हाल ही में एक आरसी में, मुझे पता चला है कि अब कोई SetResolver विधि नहीं है। नियंत्रक और वेबपी दोनों के लिए IoC सक्षम करने के लिए, मैं Unity.WebApi (NuGet) और निम्न कोड का उपयोग करता हूं:

public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();

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

        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator()));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.Configure(c => c.Scan(scan =>
        {
            scan.AssembliesInBaseDirectory();
            scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes();
        }));

        return container;
    }
}

public class ControllerActivator : IControllerActivator
{
    IController IControllerActivator.Create(RequestContext requestContext, Type controllerType)
    {
        return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController;
    }
}

मैं भी IoC जादू के लिए UnityConfiguration (NuGet से) का उपयोग करता हूं। ;)


क्या अनुरोध का उपयोग करना बेहतर नहीं होगा। Context.Configuration.D dependencyResolver.GetService ()?
अल्विन

2

उत्तरों को पढ़ने के बाद, मुझे अभी भी इस गोत्र में उतरने के लिए बहुत सारी खुदाई करनी पड़ी, इसलिए यहां यह साथियों के लाभ के लिए है: यह आपको ASP.NET 4 वेब एपीआई आरसी में करने की आवश्यकता है (8 अगस्त को) '13):

  1. "Microsoft.Practices.Unity.dll" के संदर्भ में जोड़ें [मैं संस्करण 3.0.0.0 पर हूं, NuGet के माध्यम से जोड़ा गया है]
  2. "Unity.WebApi.dll" पर एक संदर्भ जोड़ें [मैं ०.१०.०.०० संस्करण पर हूँ, NuGet के माध्यम से जोड़ा गया]
  3. कंटेनर के साथ अपने प्रकार के मैपिंग को पंजीकृत करें - Bootstrapper.cs में कोड के समान है जो Unity.WebApi परियोजना द्वारा आपकी परियोजना में जोड़ा जाता है।
  4. ApiController वर्ग से विरासत में आने वाले नियंत्रकों में, उन पैरामीटरों को बनाएं जिनके पास मैप किए गए प्रकार के रूप में उनके पैरामीटर प्रकार हैं

लो और निहारना, आप कोड की एक और लाइन के बिना अपने कंस्ट्रक्टर में इंजेक्ट की गई निर्भरताएं प्राप्त करते हैं!

नोट: मुझे यह जानकारी लेखक के इस ब्लॉग की एक टिप्पणी से मिली ।


2

ASP.NET वेब एपीआई 2 के लिए संक्षिप्त सारांश।

UnityNuGet से स्थापित करें ।

नामक एक नया वर्ग बनाएँ UnityResolver:

using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Web.Http.Dependencies;

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()
    {
        Dispose(true);
    }

    protected virtual void Dispose(bool disposing)
    {
        container.Dispose();
    }
}

नामक एक नया वर्ग बनाएँ UnityConfig:

public static class UnityConfig
{
    public static void ConfigureUnity(HttpConfiguration config)
    {
        var container = new UnityContainer();
        container.RegisterType<ISomethingRepository, SomethingRepository>();
        config.DependencyResolver = new UnityResolver(container);
    }
}

App_Start संपादित करें -> WebApiConfig.cs

public static void Register(HttpConfiguration config)
{
    UnityConfig.ConfigureUnity(config);
    ...

अब यह काम करेगा।

मूल स्रोत लेकिन थोड़ा संशोधित: https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/d dependency- injection


1

मेरे पास एक ही अपवाद था, और मेरे मामले में MVC3 और MVC4 बायनेरिज़ के बीच एक संघर्ष था। यह मेरे नियंत्रकों को मेरे आईओसी कंटेनर के साथ ठीक से पंजीकृत होने से रोक रहा था। अपने web.config की जाँच करें और सुनिश्चित करें कि यह MVC के सही संस्करणों को इंगित करता है।


इसने मेरे रेज़र इश्यूज़ को ठीक कर दिया, लेकिन एपीआई नियंत्रकों को हल करने के मुद्दे को ठीक नहीं किया।
O D D

1

यह समस्या कंट्रोलर को एकता के साथ पंजीकृत करने के कारण होती है। मैंने नीचे बताए अनुसार सम्मेलन द्वारा पंजीकरण का उपयोग करके इसे हल किया। कृपया आवश्यकतानुसार अतिरिक्त प्रकारों को फ़िल्टर करें।

    IUnityContainer container = new UnityContainer();

    // Do not register ApiControllers with Unity.
    List<Type> typesOtherThanApiControllers
        = AllClasses.FromLoadedAssemblies()
            .Where(type => (null != type.BaseType)
                           && (type.BaseType != typeof (ApiController))).ToList();

    container.RegisterTypes(
        typesOtherThanApiControllers,
        WithMappings.FromMatchingInterface,
        WithName.Default,
        WithLifetime.ContainerControlled);

इसके अलावा ऊपर दिए गए उदाहरण का उपयोग करता है AllClasses.FromLoadedAssemblies()। यदि आप आधार पथ से असेंबलियों को लोड करना देख रहे हैं, तो यह शायद एकता का उपयोग करते हुए वेब एपीआई परियोजना में अपेक्षित रूप से काम नहीं करेगा। कृपया इससे संबंधित एक अन्य प्रश्न पर मेरी प्रतिक्रिया पर एक नज़र डालें। https://stackoverflow.com/a/26624602/1350747


0

Unity.WebAPI NuGet पैकेज का उपयोग करते समय मेरे पास एक ही मुद्दा था। समस्या यह थी कि पैकेज में कभी भी कॉल नहीं जोड़ा गया थाUnityConfig.RegisterComponents() मेरे Global.asax में ।

Global.asax.cs इस तरह दिखना चाहिए:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Start()
    {
        UnityConfig.RegisterComponents();
        ...
    }
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.