7

私はWindsorを使用してWebAPIプロジェクトのコントローラのIoCを管理しています。私はDependencyResolverがコントローラの依存関係を解決するうえでうまく機能していますが、認証を管理するために使用しているカスタムアクションフィルタに依存関係を注入しようとしています。ASP.NET 4 RC WebAPIのアクションフィルタに依存性注入を行うにはどうすればよいですか?

私はカスタムActionInvokerを使用しましたが、WebAPIが実行する前にカスタムアクションフィルタ属性のプロパティ依存関係を解決する方法を使用していることがインターフェイスから明確ではありません。誰でもMVC 4 RCでこれを行う方法の良い例がありますか?

EDIT:フィルターでコンストラクタインジェクションを行うことはできませんが、それは属性であり、.NETフレームワークによってインスタンス化されるためです。しかし、実行ライフサイクルの中では、フィルタはインスタンス化されますが、実行される前に、カスタムコードを実行してフィルタのパブリックプロパティを列挙し、必要なサービスを注入することができます。

+0

IMHO非常に良いデカップリングバージョンがこの[質問(および回答) - ASP.NET MVC IFilterProviderと懸念の分離]で説明されています。(http://stackoverflow.com/questions/10708565/asp-net-mvc-ifilterprovider-懸念事項の分離)が含まれます。 –

答えて

10

アクションフィルタは属性です。 .NET属性では、インスタンス化プロセスは.NETランタイムによって管理され、そのインスタンスを制御することはできません。だから1つの可能性は私が個人的にアドバイスする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(t).Cast ().ForEach(GlobalConfiguration.Configuration.Filters.Add) –

4

私は同じ問題を抱えていましたが、 Rの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

となる可能性があります。場合によっては唯一の方法かもしれません。 –

関連する問題