7

मैं वेबएपीआई प्रोजेक्ट में अपने नियंत्रकों के लिए आईओसी का प्रबंधन करने के लिए विंडसर का उपयोग कर रहा हूं। मुझे नियंत्रक निर्भरता को हल करने के लिए अच्छी तरह से काम कर रहे निर्भरता रिसेल्वर मिल गया है, लेकिन अब मैं प्रमाणीकरण को प्रबंधित करने के लिए उपयोग कर रहे कस्टम एक्शन फ़िल्टर में निर्भरताओं को इंजेक्ट करना चाहता हूं।मैं एएसपी.नेट 4 आरसी वेबएपीआई में एक्शन फ़िल्टर में निर्भरता इंजेक्शन कैसे कर सकता हूं?

मैंने कस्टम एक्शन इनवॉकर का उपयोग करने में देखा है लेकिन यह इंटरफ़ेस से स्पष्ट नहीं है कि वेबएपीआई इसका उपयोग कर रहा है कि मैं इसे निष्पादित करने से पहले कस्टम एक्शन फ़िल्टर विशेषता पर संपत्ति निर्भरताओं को हल करने के बारे में कैसे जाऊंगा। किसी के पास एमवीसी 4 आरसी में ऐसा करने का अच्छा उदाहरण है?

संपादित करें: मुझे पता है कि आप फिल्टर पर कन्स्ट्रक्टर इंजेक्शन नहीं कर सकते हैं, क्योंकि वे गुण हैं और इसलिए .NET ढांचे द्वारा तत्काल - लेकिन मुझे उम्मीद है कि निष्पादन जीवन चक्र में कुछ बिंदु है जो उसके बाद होता है फ़िल्टर को तत्काल किया जाता है लेकिन इससे पहले इसे निष्पादित किया जाता है, जहां मैं फ़िल्टर के सार्वजनिक गुणों में गणना करने और आवश्यक सेवाओं को इंजेक्ट करने के लिए कुछ कस्टम कोड चला सकता हूं।

+0

IMHO बहुत अच्छा decoupled संस्करण इस [प्रश्न (और उत्तर) - एएसपी.नेट एमवीसी IFilterProvider और चिंताओं को अलग करने में वर्णित है] (http://stackoverflow.com/questions/10708565/asp-net-mvc-ifilterprovider- और जुदाई के- चिंताओं)। –

उत्तर

10

एक्शन फ़िल्टर विशेषताएँ हैं। .NET विशेषता में तत्काल प्रक्रिया .NET रनटाइम द्वारा प्रबंधित की जाती है और आपके पास इसका नियंत्रण नहीं होता है। तो एक संभावना है Poor Man's Dependency Injection का उपयोग करना जो मैं व्यक्तिगत रूप से आपको सलाह दूंगा।

एक और संभावना एक मार्कर विशेषता का उपयोग करने के लिए है:

public class MyActionFilterAttribute : Attribute 
{ 

} 

और फिर निर्माता इंजेक्शन का उपयोग कर कार्रवाई फिल्टर है:

public class MyActionFilter : ActionFilterAttribute 
{ 
    private readonly IFoo _foo; 
    public MyActionFilter(IFoo foo) 
    { 
     _foo = foo; 
    } 

    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     if (actionContext.ActionDescriptor.GetCustomAttributes<MyActionFilterAttribute>().Any()) 
     { 
      // The action is decorated with the marker attribute => 
      // do something with _foo 
     } 
    } 
} 

और फिर Application_Start में एक वैश्विक कार्रवाई फिल्टर के रूप में यह रजिस्टर:

IFoo foo = .... 
GlobalConfiguration.Configuration.Filters.Add(new MyActionFilter(foo)); 
+0

डारिन - इसके लिए धन्यवाद; मैंने पहले से ही सेवा लोकेटर दृष्टिकोण की कोशिश की है, लेकिन मैं थोड़ा क्लीनर ढूंढ रहा हूं - मेरे प्रश्न पर संपादन देखें जो उम्मीद है कि मैं जो खोज रहा हूं उसे स्पष्ट करता हूं। –

+0

@DylanBeattie, नहीं, यदि आप कन्स्ट्रक्टर इंजेक्शन (जो वर्गों में आवश्यक निर्भरताओं को इंजेक्ट करने का सही तरीका है) का उपयोग करना चाहते हैं, तो आपको कक्षा के तत्कालता पर नियंत्रण रखना होगा, दुर्भाग्य से आप गुणों के मामले में नहीं हैं। यही कारण है कि आप मेरे उत्तर में दिखाए गए मार्कर इंटरफ़ेस का उपयोग कर सकते हैं। –

+0

यदि आप अपने कंटेनर के साथ फ़िल्टर पंजीकृत करते हैं, और आप global.asax में कंटेनर बना रहे हैं तो आप फिल्टर को हल करने के लिए कंटेनर का उपयोग कर सकते हैं, उदा। _container.ResolveAll (टी) .स्ट () .EEach (GlobalConfiguration.Configuration.Filters.Add) –

4

मुझे एक ही समस्या थी, लेकिन जाने का फैसला किया आर ServiceLocator (DependencyResolver.GetService) इस के लिए, इसकी रूपरेखा में मुझे लगता है के रूप में एक वैध दृष्टिकोण

public class RequiresSessionAttribute : 
    ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var sessionService = 
      (ISessionService) actionContext 
        .ControllerContext.Configuration.DependencyResolver 
        .GetService(typeof (ISessionService)); 

     var sessionId = HttpUtility 
      .ParseQueryString(actionContext.Request.RequestUri.Query) 
      .Get("sessionId"); 

     if (sessionId == null 
      || !sessionService.IsValid(sessionId)) 
      throw new SessionException(); 

     base.OnActionExecuting(actionContext); 
    } 
} 

हो सकता है और यहां इस विशेषता के लिए एक परीक्षण है, एक दर्द का सा लेकिन संभव

public class requires_sessionId 
{ 
    [Fact] 
    void can_call_action_with_session_id() 
    { 
     var context = GetContext("http://example.com/?sessionId=blaa"); 

     var sut = new RequiresSessionAttribute(); 

     Assert.DoesNotThrow(
      () => sut.OnActionExecuting(context)); 
    } 

    [Fact] 
    void can_not_call_action_without_session_id() 
    { 
     var context = GetContext("http://example.com/"); 

     var sut = new RequiresSessionAttribute(); 

     Assert.Throws<SessionException>(
      () => sut.OnActionExecuting(context)); 
    } 

    HttpActionContext GetContext(string url) 
    { 
     var sessionServiceMock = new Mock<ISessionService>(); 
     sessionServiceMock 
      .Setup(x => x.IsValid(It.IsAny<string>())) 
      .Returns(true); 

     var dependancyResolverMock = new Mock<IDependencyResolver>(); 
     dependancyResolverMock 
      .Setup(x => x.GetService(It.IsAny<Type>())) 
      .Returns(sessionServiceMock.Object); 

     var config = new HttpConfiguration 
       { 
        DependencyResolver = dependancyResolverMock.Object 
       }; 
     var controllerContext = new HttpControllerContext 
       { 
        Configuration = config, 
        Request = new HttpRequestMessage(
           HttpMethod.Get, 
           url) 
       }; 

     return 
      new HttpActionContext 
       { 
        ControllerContext = controllerContext, 
       }; 
    } 
} 
+1

इसे एक अच्छा तरीका नहीं माना जाता है, यह –

+0

को मजाक नहीं कर सकता है, लेकिन आप –

+0

शायद सबसे अच्छा तरीका नहीं कर सकते हैं, लेकिन कुछ मामलों में यह एकमात्र तरीका हो सकता है। –