2013-04-09 5 views
30

मैं सरल इंजेक्टर के साथ कुछ बुनियादी कन्स्ट्रक्टर डी करने का प्रयास कर रहा हूं, और ऐसा लगता है कि यह वेब एपीआई नियंत्रकों के लिए निर्भरताओं को हल करने में असमर्थ है।सरल इंजेक्टर वेब एपीआई नियंत्रकों में निर्भरता इंजेक्ट करने में असमर्थ

  • मेरे पास "एपीआई" फ़ोल्डर में एक एपीआई नियंत्रक है, जो "नियंत्रक" फ़ोल्डर के बाहर है।
  • मैंने इसे "नियंत्रक" फ़ोल्डर में रखने का भी प्रयास किया है, लेकिन जो कि बहुत अधिक अंतर नहीं लग रहा था। मुझे प्राप्त स्टैक ट्रेस this question में प्रस्तुत एक जैसा है।
  • मैं "सरल इंजेक्टर एमवीसी एकीकरण त्वरित प्रारंभ" NuGet पैकेज (v। 2.1.0) का एक नया इंस्टॉल उपयोग कर रहा हूं।
  • मेरे पास प्रलेखन से आधार SimpleInjectorWebApiDependencyResolver है, जो here जैसा भी है।
  • मैं इकाई फ्रेमवर्क का उपयोग कर रहा हूं, और संदर्भ को सही तरीके से लोड करने के लिए discussion thread पर परिवर्तनों के बारे में देखा है।

यह नहीं एक समस्या होने लगते है, लेकिन मैं अभी भी निम्न त्रुटि प्राप्त:

Type 'MyProject.API.ArticleController' does not have a default constructor

System.ArgumentException at

System.Linq.Expressions.Expression.New(Type type) at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)

अगर किसी ने मुझे कुछ सुझाव दे सकता है यह, की सराहना की जाएगी कि क्या कुछ भी से संशोधित किया जाना चाहिए इसका वर्तमान राज्य/कॉल ऑर्डर।

ArticleController (बुनियादी संरचना):

public class ArticleController : ApiController 
{ 
    private readonly IArticleRepository articleRepository; 
    private readonly IUserRepository userRepository; 
    private readonly IReleaseRepository releaseRepository; 

    public ArticleController(IArticleRepository articleRepository, IUserRepository userRepository, IReleaseRepository releaseRepository) 
    { 
     this.articleRepository = articleRepository; 
     this.userRepository = userRepository; 
     this.releaseRepository = releaseRepository; 
    } 

    // GET api/Article 
    public IEnumerable<Article> GetArticles(){ // code } 

    // GET api/Article/5 
    public Article GetArticle(int id){ // code } 

    // PUT api/Article/5 
    public HttpResponseMessage PutArticle(int id, Article article){ // code } 

    // POST api/Article 
    public HttpResponseMessage PostArticle(ArticleModel article){ // code } 

    // DELETE api/Article/5 
    public HttpResponseMessage DeleteArticle(int id){ // code } 
} 

SimpleInjectorInitializer:

public static class SimpleInjectorInitializer 
{ 
    public static void Initialize() 
    { 
     var container = new Container(); 
     InitializeContainer(container); 
     container.RegisterMvcControllers(Assembly.GetExecutingAssembly()); 
     container.RegisterMvcAttributeFilterProvider(); 
     container.Verify(); 

     DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container)); 
    } 

    private static void InitializeContainer(Container container) 
    { 
     container.Register<IArticleRepository, ArticleRepository>(); 
     container.Register<IUserRepository, UserRepository>(); 
     container.Register<IReleaseRepository, ReleaseRepository>(); 
    } 
} 

Global.asax.cs:

public class WebApiApplication : System.Web.HttpApplication 
{ 
    private void ConfigureApi() 
    { 
     // Create the container as usual. 
     var container = new Container(); 

     // Verify the container configuration 
     // container.Verify(); 

     // Register the dependency resolver. 
     GlobalConfiguration.Configuration.DependencyResolver = 
       new SimpleInjectorWebApiDependencyResolver(container); 
    } 

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

     WebApiConfig.Register(GlobalConfiguration.Configuration); 
     FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 
     RouteConfig.RegisterRoutes(RouteTable.Routes); 
     BundleConfig.RegisterBundles(BundleTable.Bundles); 
    } 
} 
+0

क्या आप वाकई 'कॉन्फ़िगरएपीआई' विधि वास्तव में चल रहे हैं? क्या आपने इसमें ब्रेक पॉइंट सेट किया था? – Steven

+0

किसी भी कारण से आप अपनी वेब एपीआई कॉन्फ़िगरेशन के लिए एक अलग 'कंटेनर' उदाहरण बनाते हैं? – Steven

+0

हां, मुझे यकीन है कि यह चल रहा है। मेरे पास लाइन पर एक ब्रेक पॉइंट सेट है जो ग्लोबल कॉन्फ़िगरेशन पर निर्भरता रीसोलवर सेट करता है। यदि आप Global.asax.cs के भीतर हैं, तो मैं इस मार्गदर्शिका का पालन कर रहा था (http://www.asp.net/web-api/overview/extensibility/using-the-web-api- निर्भरता-resolver), से देखें कि यह मेरी समस्या का समाधान करेगा या नहीं। हालांकि, ऐसा प्रतीत नहीं हुआ। – user1417835

उत्तर

33

TLTR: समस्या निहित के कारण होता है जिस तरह से वेब एपीआई नियंत्रक प्रकार का समाधान संभालती है; अपने वेब एपीआई नियंत्रकों को स्पष्ट रूप से पंजीकृत करें और आप देखेंगे कि समस्या कहां है।

यहाँ कवर के तहत हो रहा है कदम से एक कदम है:

  1. SimpleInjectorWebApiDependencyResolver में System.Web.Http.DefaultHttpControllerActivator कॉल और एक API नियंत्रक के निर्माण के अनुरोध करता है।
  2. SimpleInjectorWebApiDependencyResolver आगे जो SimpleInjector.Container उदाहरण पर कॉल करें।
  3. Container उदाहरण हालांकि, उस एपीआई नियंत्रक के लिए कोई स्पष्ट पंजीकरण नहीं है (क्योंकि आपने रिज़ॉल्वर को खाली कंटेनर प्रदान किया है)।
  4. चूंकि कोई स्पष्ट पंजीकरण नहीं है, इसलिए कंटेनर उस प्रकार के लिए अंतिम मिनट पंजीकरण करने का प्रयास करता है।
  5. वह नियंत्रक प्रकार इंटरफेस पर निर्भर करता है जिसे हल नहीं किया जा सकता क्योंकि वे कंटेनर में पंजीकृत नहीं हैं (याद रखें, आपका कंटेनर खाली है)।
  6. हालांकि कंटेनर सामान्य रूप से अपवाद फेंक देगा, इस मामले में शून्य वापस आ गया है, क्योंकि IServiceProvider.GetService विधि के माध्यम से प्रकार का अनुरोध किया गया है और प्रकार का पता लगाने के लिए तर्क नहीं दिया गया था।
  7. SimpleInjectorWebApiDependencyResolver की GetService विधि null भी वापस आ जाएगी, क्योंकि यह परिभाषा के अनुसार है कि इसे शून्य वापस करना चाहिए; जब पंजीकरण नहीं होता है तो यह शून्य हो जाना चाहिए (जो वर्तमान में मामला है)।
  8. DependencyResolver के बाद से अशक्त लौट आए, DefaultHttpControllerActivator वापस अपने डिफ़ॉल्ट व्यवहार है, जो उस प्रकार ही बनाने का मतलब तक कम हो जाएगा, लेकिन यह एक डिफ़ॉल्ट निर्माता के लिए नियंत्रक की आवश्यकता है।

लंबी कहानी छोटी, समस्या अंतर्निहित तरीके से होती है वेब एपीआई नियंत्रक प्रकारों को हल करने में संभालती है।

तो यहाँ समाधान है:

  1. अपने वेब आवेदन में केवल एक एकल Container है। यह आपकी कॉन्फ़िगरेशन की सभी प्रकार की परेशानी और जटिलता को रोकता है।
  2. कंटेनर में स्पष्ट रूप से सभी वेब एपीआई नियंत्रकों को पंजीकृत करें। नियंत्रकों को पंजीकृत करने से स्पष्ट रूप से यह सुनिश्चित होगा कि नियंत्रक को हल नहीं किया जा सकता है जब सरल इंजेक्टर एक अपवाद फेंक देगा। इसके अलावा, यह आपको container.Verify() पर कॉल करने की अनुमति देता है जो कॉन्फ़िगरेशन अमान्य होने पर स्टार्टअप के दौरान एप्लिकेशन विफल हो जाएगा (verifiable configuration is important)। और यह आपको diagnose the configuration पर भी अनुमति देता है जो आपको आपकी कॉन्फ़िगरेशन की शुद्धता के बारे में और भी अधिक विश्वास देता है।

मेरे advice is to place MVC and Web API in their own project। यह चीजों को और अधिक आसान बना देगा।

सभी वेब एपीआई नियंत्रकों का पंजीयन निम्न कोड के साथ किया जा सकता है:

container.RegisterWebApiControllers(GlobalConfiguration.Configuration); 

अद्यतन:

क्योंकि इस त्रुटि तो आम है, SimpleInjectorWebApiDependencyResolver वर्ग के नए संस्करण होगा बस कभी नहीं एक नियंत्रक प्रकार का अनुरोध होने पर null वापस करें। इसके बजाय यह एक वर्णनात्मक त्रुटि फेंक देगा। इस वजह से आपको अब तक त्रुटि दिखाई नहीं देनी चाहिए, जब तक कि आप आधिकारिक SimpleInjectorWebApiDependencyResolver का उपयोग न करें।

+0

विस्तृत उत्तर के लिए धन्यवाद! मुझे इस विधि को कहां रखना चाहिए? क्या यह निहित है कि मुझे एक नई कक्षा बनाना चाहिए, और कंटेनर की एक विस्तार विधि के रूप में इसे लागू करना चाहिए? – user1417835

+0

यह एक विस्तार विधि है। आप इसे किसी भी स्थिर वर्ग में रख सकते हैं ताकि आप अपनी संरचना रूट के भीतर से 'कंटेनर। रजिस्ट्रार एपीआई कंट्रोलर() 'कर सकें। – Steven

+0

क्या 'SimpleInitializer' के भीतर ** ग्लोबल कॉन्फ़िगरेशन **' निर्भरता रीसोलवर' सेट करना उचित होगा? या इसे Global.asax.cs में रखा जाना चाहिए? प्रलेखन (http://simpleinjector.codeplex.com/wikipage?title=Web%20API%20 इंटीग्रेशन) बताता है कि कंटेनर निर्माण और सेवा/संसाधन पंजीकरण Global.asax.cs में 'Application_Start()' के भीतर किया जाना चाहिए, लेकिन टिप्पणियां 'InitializeContainer()' में यह भी सुझाव दिया गया है कि पंजीकरण वहां होना चाहिए। – user1417835

संबंधित मुद्दे