2011-11-20 25 views
8

Tại thời điểm này, tôi có một ControllerFactory tùy chỉnh vào mà tôi tiêm container của tôi Unity:Sử dụng Unity để tiêm phụ thuộc vào một tùy chỉnh ActionFilter

trong global.asax Application_Start():

var container = InitContainer(); 
DependencyResolver.SetResolver(new UnityDependencyResolver(container)); 

var factory = new UnityControllerFactory(container); 
ControllerBuilder.Current.SetControllerFactory(factory); 

Trong máy điều khiển tôi đặt bộ điều khiển của tôi để sử dụng một ActionInvoker tùy chỉnh như sau:

protected override IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType) 
{ 
    var controller = base.GetControllerInstance(requestContext, controllerType) as Controller; 

    if (controller != null) 
     controller.ActionInvoker = new UnityActionInvoker(_container); 

    return controller; 
} 

Cuối cùng trong ActionInvoker tùy chỉnh của tôi, tôi cố gắng để hành động tích tụ được gọi bằng các ActionInvokers container:

protected override ActionExecutedContext InvokeActionMethodWithFilters(
     ControllerContext controllerContext, 
     IList<IActionFilter> filters, 
     ActionDescriptor actionDescriptor, 
     IDictionary<string, object> parameters) 
{ 
    var builtUpFilters = new List<IActionFilter>(); 

    foreach (IActionFilter actionFilter in filters) 
    { 
     builtUpFilters.Add(_container.BuildUp<IActionFilter>(actionFilter)); 
    } 

    return base.InvokeActionMethodWithFilters(controllerContext, builtUpFilters, actionDescriptor, parameters); 
} 

Dưới đây là một ví dụ về một trong những ActionFilters đang được xây dựng:

public class PopulatRolesAttribute : ActionFilterAttribute, IActionFilter 
{ 
    private const string RolesKey = "roles"; 

    [Dependency] 
    public Func<IMetadataService> Service { get; set; } 

    public PopulatRolesAttribute() 
    { 
    } 

    public override void OnActionExecuting(ActionExecutingContext filterContext) 
    { 
     if (filterContext.Controller.ViewData[RolesKey] == null) 
     { 
      filterContext.Controller.ViewData[RolesKey] = Service().GetRoles(); 
     } 
    } 
} 

Vấn đề là rằng tài sản công cộng trên tùy chỉnh của tôi ActionFilterAttribute không bao giờ được tiêm với bất cứ điều gì, nó vẫn không được thực hiện! Tôi không thể thấy lý do bộ lọc của tôi không được vùng chứa tích hợp đúng cách. Loại được tiêm được đăng ký đúng cách, như vậy:

container.RegisterInstance(new ChannelFactory<IMetadataService>(
    new BasicHttpBinding(), 
    new EndpointAddress("http://example.com/ABSApplication/MetadataService.svc"))); 

container.RegisterInstance<Func<IMetadataService>>(
    () => container.Resolve<ChannelFactory<IMetadataService>>().CreateChannel()); 

Và cũng đang được tiêm ở nơi khác trong ứng dụng (Mặc dù không qua .Buildup). Đây là quá trình tương tự, tiếp theo là blog post. Tôi đang thiếu phần câu đố nào?

+0

Ngoài sự tò mò, tại sao không thực hiện việc này, xác thực yêu cầu, yêu cầu preauth, v.v ... để chúng ở đó cho mỗi yêu cầu khi người dùng đăng nhập? –

+0

Ý định ban đầu của tôi là đóng gói chức năng này để tôi có thể thêm nó bất cứ khi nào một hành động yêu cầu nó. Nếu sau khi xem xét, tôi sẽ sử dụng dữ liệu được các bộ lọc lấy ra một lượng đáng kể, tôi chắc chắn sẽ lưu trữ nó trên toàn cầu để tái sử dụng trong suốt ứng dụng. Nó thực sự là bắt đầu trông giống như đó sẽ là một giải pháp dễ dàng hơn anyway, bất kể tái sử dụng! Tôi vẫn còn rất tò mò là tại sao 'container.BuildUp' không hoạt động. –

+0

Tôi đã tìm thấy mẫu này, sẽ sớm kiểm tra nó. Các nguồn có sẵn để tải về có cũng http://msdn.microsoft.com/en-us/gg618494 –

Trả lời

8

Tôi sẽ làm điều này hơi khác. Tôi sẽ:

  1. cài đặt NuGet gói unity.mvc3

  2. gọi các bootstrapped.initialise() như đã đề cập trong doc txt gói thêm vào dự án

  3. xác định bản đồ IMetadataService của bạn trong lần khởi tạo cho loại Bê tông của bạn

  4. thêm IMetadataService vào hàm tạo của bạn

Sự khác biệt giữa triển khai của bạn và bài viết bạn tham chiếu là bạn sử dụng Func, trong đó Im không chắc liệu điều đó có thêm vấn đề khác vào kết hợp ở đây hay không. Tôi phải tưởng tượng nó như là phương pháp trên (không có Func) hoạt động tốt cho tôi.

Chỉnh sửa: Mã Brad Wilson chỉ làm việc tốt cho tôi ở đây: http://bradwilson.typepad.com/blog/2010/07/service-location-pt4-filters.html

phần áp dụng (xin vui lòng xem link ở trên)

Global.asax.cs

 

protected void Application_Start() { 
    // ... 

    var oldProvider = FilterProviders.Providers.Single(
     f => f is FilterAttributeFilterProvider 
    ); 
    FilterProviders.Providers.Remove(oldProvider); 

    var container = new UnityContainer(); 
    var provider = new UnityFilterAttributeFilterProvider(container); 
    FilterProviders.Providers.Add(provider); 

    // ... 
} 
 

Bộ lọc chính nó:

 

using System; 
using System.Web.Mvc; 
using Microsoft.Practices.Unity; 

public class InjectedFilterAttribute : ActionFilterAttribute { 

    [Dependency] 
    public IMathService MathService { get; set; } 

    public override void OnResultExecuted(ResultExecutedContext filterContext) { 
     filterContext.HttpContext.Response.Write(
      String.Format("

The filter says 2 + 3 is {0}.

", MathService.Add(2, 3)) ); } }

và UnityFilterAttributeFilterProvider.cs

 

using System.Collections.Generic; 
using System.Web.Mvc; 
using Microsoft.Practices.Unity; 

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider { 
    private IUnityContainer _container; 

    public UnityFilterAttributeFilterProvider(IUnityContainer container) { 
     _container = container; 
    } 

    protected override IEnumerable GetControllerAttributes(
       ControllerContext controllerContext, 
       ActionDescriptor actionDescriptor) { 

     var attributes = base.GetControllerAttributes(controllerContext, 
                 actionDescriptor); 
     foreach (var attribute in attributes) { 
      _container.BuildUp(attribute.GetType(), attribute); 
     } 

     return attributes; 
    } 

    protected override IEnumerable GetActionAttributes(
       ControllerContext controllerContext, 
       ActionDescriptor actionDescriptor) { 

     var attributes = base.GetActionAttributes(controllerContext, 
                actionDescriptor); 
     foreach (var attribute in attributes) { 
      _container.BuildUp(attribute.GetType(), attribute); 
     } 

     return attributes; 
    } 
} 
 
+1

Tôi đánh giá cao hướng đến gói Unity.Mvc3 - nó đóng gói độ phân giải phụ thuộc cho Mvc3 bằng cách sử dụng Unity độc đáo. Tuy nhiên tôi không nghĩ rằng nó giải quyết được vấn đề của tôi. Nếu tôi có một phương pháp trong một bộ điều khiển được trang trí với một bộ lọc như vậy: '[PopulatRoles] public ActionResult Add() {' ​​làm thế nào để tôi đạt được tiêm khi PopulateRoles ActionFilterAttribute? Tôi không thể sử dụng constructor injection vì nó là một thuộc tính và tôi không thể sử dụng constructor của nó. Vì vậy tôi cần xây dựng thuộc tính khi nó được tạo ra. –

+0

Là một phụ lục, tôi đã thấy rằng ninject làm một cái gì đó hoàn toàn khác nhau như thế này [link] (http://www.planetgeek.ch/2010/11/13/official-ninject-mvc-extension-gets-support-for- mvc3 /) để cho phép xây dựng tiêm trên bộ lọc, tuy nhiên tôi không chắc chắn nếu điều này là đạt được với Unity. –

+0

Các bộ lọc được giải quyết nội bộ trong MVC Tôi sẽ phải thử một cách nhanh chóng tại đây. –

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