7

Tôi đang sử dụng Windsor để quản lý IoC cho bộ điều khiển của mình trong dự án WebAPI. Tôi đã có một DependencyResolver làm việc độc đáo để giải quyết phụ thuộc điều khiển, nhưng bây giờ tôi đang tìm cách để tiêm phụ thuộc vào một bộ lọc hành động tùy chỉnh tôi đang sử dụng để quản lý xác thực.Làm thế nào tôi có thể làm phụ thuộc tiêm vào bộ lọc hành động trong ASP.NET 4 RC WebAPI?

Tôi đã xem xét sử dụng ActionInvoker tùy chỉnh nhưng không rõ ràng từ giao diện mà WebAPI đang sử dụng cách tôi sẽ giải quyết các phụ thuộc thuộc tính trên thuộc tính bộ lọc hành động tùy chỉnh trước khi nó thực hiện. Bất cứ ai cũng có một ví dụ tốt về cách làm điều này trong MVC 4 RC?

EDIT: Tôi biết bạn không thể thực hiện việc xây dựng bộ lọc trên bộ lọc, vì chúng là các thuộc tính và do đó được khởi tạo bởi .NET framework - nhưng tôi hy vọng có một số điểm trong vòng đời thực hiện xảy ra SAU KHI bộ lọc được khởi tạo nhưng TRƯỚC KHI nó được thực hiện, nơi tôi có thể chạy một số mã tùy chỉnh để liệt kê trên các thuộc tính công cộng của bộ lọc và tiêm các dịch vụ cần thiết.

+0

Phiên bản rút gọn IMHO rất tốt được mô tả trong [câu hỏi (và câu trả lời) này - ASP.NET MVC IFilterProvider và tách mối quan tâm] (http://stackoverflow.com/questions/10708565/asp-net-mvc-ifilterprovider- và tách mối quan tâm). –

Trả lời

10

Bộ lọc hành động là các thuộc tính. Trong thuộc tính .NET, quá trình instantiation được quản lý bởi .NET runtime và bạn không có quyền kiểm soát nó. Vì vậy, một khả năng là sử dụng Poor Man's Dependency Injection mà tôi sẽ tư vấn cá nhân bạn chống lại.

Một khả năng khác là sử dụng một thuộc tính marker:

public class MyActionFilterAttribute : Attribute 
{ 

} 

và sau đó có các bộ lọc hành động sử dụng constructor tiêm:

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 
     } 
    } 
} 

và sau đó đăng ký nó như một bộ lọc hành động toàn cầu trong Application_Start:

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

Darin - cảm ơn vì điều này; Tôi đã thử cách tiếp cận định vị dịch vụ nhưng tôi đang tìm kiếm một thứ gì đó sạch hơn một chút - xem chỉnh sửa câu hỏi của tôi, hy vọng làm rõ những gì tôi đang tìm kiếm. –

+0

@ DylanBeattie, không, nếu bạn muốn sử dụng phương thức khởi tạo (đây là cách thích hợp để chèn các phụ thuộc cần thiết vào các lớp), bạn cần phải kiểm soát sự khởi tạo của lớp mà không may bạn không thuộc trường hợp các thuộc tính. Đó là lý do tại sao bạn có thể sử dụng giao diện điểm đánh dấu như được hiển thị trong câu trả lời của tôi. –

+0

nếu bạn đăng ký bộ lọc với vùng chứa của mình và bạn đang tạo vùng chứa trong global.asax, bạn có thể sử dụng vùng chứa để phân giải bộ lọc, ví dụ: _container.ResolveAll (t) .Cast () .ForEach (GlobalConfiguration.Configuration.Filters.Add) –

4

Tôi đã gặp vấn đề tương tự, nhưng đã quyết định đi r các ServiceLocator (DependencyResolver.GetService) cho điều này, như trong khuôn khổ có vẻ như với tôi để được một cách tiếp cận hợp lệ

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); 
    } 
} 

và đây là một thử nghiệm cho thuộc tính này, chút đau đớn nhưng có thể

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

Nó không được coi là một cách tốt, nó không thể chế nhạo –

+0

nó không dễ dàng, nhưng bạn có thể –

+0

Có lẽ không phải là cách tốt nhất, nhưng trong một số trường hợp, nó có thể là cách duy nhất. –

Các vấn đề liên quan