7

Windsor を使用して、WebAPI プロジェクトでコントローラーの IoC を管理しています。コントローラーの依存関係を解決するためにうまく機能する DependencyResolver がありますが、今は、認証を管理するために使用しているカスタム アクション フィルターに依存関係を挿入しようとしています。

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

編集:フィルターは属性であり、したがって.NETフレームワークによってインスタンス化されるため、フィルターでコンストラクターインジェクションを実行できないことは承知していますが、フィルターがインスタンス化された後に発生する実行ライフサイクルにいくつかのポイントがあることを願っていますが、実行される前に、いくつかのカスタム コードを実行して、フィルターのパブリック プロパティを列挙し、必要なサービスを挿入することができます。

4

2 に答える 2

11

アクション フィルターは属性です。.NET 属性では、インスタンス化プロセスは .NET ランタイムによって管理され、それを制御することはできません。したがって、1つの可能性は、私が個人的にアドバイスするPoor Man's Dependency Injectionを使用することです.

もう 1 つの可能性は、marker 属性を使用することです。

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));
于 2012-06-11T11:30:19.360 に答える
5

私も同じ問題を抱えていましたが、このために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,
                };
    }
}
于 2012-08-16T13:09:26.510 に答える