Unity使用参数将依赖项注入MVC​​过滤器类 [英] Unity Inject dependencies into MVC filter class with parameters

查看:37
本文介绍了Unity使用参数将依赖项注入MVC​​过滤器类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 Unity.MVC4 依赖注入来访问我的服务.注入到我的控制器构造函数时,一切正常,但我现在想做的是在过滤器类中使用属性注入,这样我就可以从内部访问我的数据库.

I'm using Unity.MVC4 dependency injection for accessing my services. Everything works as it should when injecting into my Controller constructor, but what I would like to do now is to use property injection in my filter class so I can access my database from the inside.

在我开始这个问题之前,我在谷歌上搜索并尝试了不同的例子,但我找不到适合我的解决方案..

Before I started this question I Googled around and tried different examples but I couldn't find a solution that worked for me..

Bootstrapper.cs

public static class Bootstrapper
{
    public static IUnityContainer Initialise()
    {
        var container = BuildUnityContainer();

        DependencyResolver.SetResolver(new UnityDependencyResolver(container));

        return container;
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();
        container.RegisterType<IAccountRepository, AccountRepository>();
        container.RegisterType<IAdministrationRepository, AdministrationRepository>();
        container.RegisterType<IUploadDirectlyRepository, UploadDirectlyRepository>();
        container.RegisterType<IUserRepository, UserRepository>();
        container.RegisterType<INewsRepository, NewsRepository>();
        container.RegisterType<IContactRepository, ContactRepository>();

        // register all your components with the container here
        // it is NOT necessary to register your controllers

        // e.g. container.RegisterType<ITestService, TestService>();    
        RegisterTypes(container);

        return container;
    }

    public static void RegisterTypes(IUnityContainer container)
    {

    }
}

Application_Start

public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            Bootstrapper.Initialise();
        }
    }

工作示例

public class UserController : Controller
{
    private readonly IUserRepository _userRepository;

    public UserController(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }

    public ActionResult GetUser(int userID)
    {
        var user = _userRepository.GetUser(userID)

        return View(user);
    }
}

我将要向您展示的以下代码用于我想在我的操作中使用的过滤器属性.我想传入一个字符串数组类型的参数,以便我可以验证是否允许当前用户访问该操作.

The following code that I'm about to show you is for the filter attribute that I would like to use on my actions. I want to pass in a parameter of type string array so I can validate if the current user is allowed to access the action.

在我的应用程序中有两种类型的用户,帐户所有者和访客.所有操作都对帐户所有者完全开放,但对于客人来说,它因操作而异.例如,某个操作可能要求您至少拥有三种权限之一(读取、写入和编辑).

In my application there are two types of users, Account owner and Guest. All actions are fully open for account owners, but for guests it varies from action to action. For an example, an action can require you to have atleast one of three permissions, (read, write and edit).

过滤器:

public class ClaimsAuthorizeAccountAccess : AuthorizeAttribute
{
    private IAccountRepository _accountRepository { get; set; }
    private String[] _permissions { get; set; }

    public ClaimsAuthorizeAccountAccess(IAccountRepository accountRepository, params String[] permissions)
    {
        _permissions = permissions;
        _accountRepository = accountRepository;
    }

    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (HttpContext.Current.User.IsInRole("Account Owner"))
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
            ClaimsIdentity claimsIdentity = (ClaimsIdentity)HttpContext.Current.User.Identity;
            List<AccountLinkPermissionDTO> accountLinkPermissions = new List<AccountLinkPermissionDTO>();

            int accountOwnerID = 0;
            Int32.TryParse(claimsIdentity.Claims.Where(c => c.Type == "AccountOwnerID").Select(c => c.Value).SingleOrDefault(), out accountOwnerID);
            int guestID = 0;
            Int32.TryParse(claimsIdentity.Claims.Where(c => c.Type == ClaimTypes.Sid).Select(c => c.Value).SingleOrDefault(), out guestID);

            //NULL
            accountLinkPermissions = _accountRepository.GetAccountLinkPermissions(accountOwnerID, guestID);

            if (accountLinkPermissions != null)
            {
                List<string> accountLinkPermissionsToString = accountLinkPermissions.Select(m => m.Permission.Name).ToList();
                int hits = accountLinkPermissionsToString.Where(m => _permissions.Contains(m)).Count();

                if (hits > 0)
                {
                    base.OnAuthorization(filterContext);
                }
            }
            else
            {
                //Guest doesnt have right permissions

                filterContext.Result = new RedirectToRouteResult(
                new RouteValueDictionary {
                        { "action", "AccessDenied" },
                        { "controller", "Account" }});
            }
        }
    }
}

如果我使用这个过滤器,它看起来会像..

If I were to use this filter it would look something like..

[ClaimsAuthorizeAccountAccess("File read", "File write, File edit")]
public ActionResult Files()
{
    return View();
}

但是这不起作用,因为过滤器需要两个参数(IRepository 和 string[]).显然,这里也不可能使用构造函数注入.

However this does not work because the filter expects two parameters, (IRepository and string[]). It's also not possible to use constructor injection here, obviously.

然后我尝试实施 John Allers 可以找到的解决方案 此处.它看起来很有希望,但它给了我这个错误:

I then tried implementing John Allers solution that can be found here. It looked promising but it gave me this error:

类型异常'Microsoft.Practices.Unity.ResolutionFailedException' 发生在Microsoft.Practices.Unity.dll 但未在用户代码中处理

An exception of type 'Microsoft.Practices.Unity.ResolutionFailedException' occurred in Microsoft.Practices.Unity.dll but was not handled in user code

附加信息:依赖解析失败,类型="Fildela.ClaimsAuthorizeAccountAccess", name = "(none)".

Additional information: Resolution of the dependency failed, type = "Fildela.ClaimsAuthorizeAccountAccess", name = "(none)".

异常发生时:解决时.

异常是:InvalidOperationException - 属性Fildela 类型的 _accountRepository.ClaimsAuthorizeAccountAccess 不可设置.

Exception is: InvalidOperationException - The property _accountRepository on type Fildela.ClaimsAuthorizeAccountAccess is not settable.

在发生异常时,容器是:

At the time of the exception, the container was:

解决 Fildela.ClaimsAuthorizeAccountAccess,(none)

Resolving Fildela.ClaimsAuthorizeAccountAccess,(none)

关于如何解决这个坏男孩的任何建议?

Any suggestion on how to solve this bad boy?

谢谢!

推荐答案

首先安装官方包,Unity.Mvc 而不是 Unity.MVC4.这个包会自动安装和注册UnityFilterAttributeFilterProvider,我们需要它来进行属性的依赖注入.您可以通过查看 App_Start > UnityMvcActivatorStart 方法来检查您的 Unity 是否配置良好.您必须看到以下两行:

First install official package, Unity.Mvc instead of Unity.MVC4. This package automatically installs and register UnityFilterAttributeFilterProvider which we need it for attribute's dependency injection. You could check if your Unity configured well by looking App_Start > UnityMvcActivator's Start method. You must see following two line:

public static void Start()
{
    // other codes

    FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
    FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));
}

现在您可以添加 [Dependency] 属性来过滤器的公共属性.

Now you could add [Dependency] attribute to filter's public properties.

public class ClaimsAuthorizeAccountAccess : AuthorizeAttribute
{
    [Dependency]
    public IAccountRepository AccountRepository { get; set; }
    private String[] _permissions { get; set; }

    public ClaimsAuthorizeAccountAccess(params String[] permissions)
    {
        _permissions = permissions;
    }
}

这篇关于Unity使用参数将依赖项注入MVC​​过滤器类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆