团结注入依赖与参数MVC过滤器类 [英] Unity Inject dependencies into MVC filter class with parameters

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

问题描述

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

在我开始这个问题,我用Google搜索周围,尝试不同的例子,但我找不到任何为我工作的解决方案。

Bootstrapper.cs

 公共静态类引导程序
{
    公共静态初始化IUnityContainer()
    {
        变种容器= BuildUnityContainer();        DependencyResolver.SetResolver(新UnityDependencyResolver(容器));        返回容器中;
    }    私有静态IUnityContainer BuildUnityContainer()
    {
        VAR集装箱=​​新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>();        //注册所有组件与容器在这里
        //这是没有必要注册你的控制器        //例如container.RegisterType< ITestService,TestService的>();
        RegisterTypes(容器);        返回容器中;
    }    公共静态无效RegisterTypes(IUnityContainer容器)
    {    }
}

的Application_Start

 公共类MvcApplication:System.Web.HttpApplication
    {
        保护无效的Application_Start()
        {
            AreaRegistration.RegisterAllAreas();            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);            Bootstrapper.Initialise();
        }
    }

工作实例

 公共类UserController的:控制器
{
    私人只读IUserRepository _userRepository;    公共UserController的(IUserRepository userRepository)
    {
        _userRepository = userRepository;
    }    公众的ActionResult的getUser(INT用户ID)
    {
        VAR用户= _userRepository.GetUser(用户ID)        返回查看(用户);
    }
}

以下code,我是要告诉你的是,我想在我的行动使用的过滤器属性。
我想类型的字符串数组的参数来传递,所以如果当前用户被允许访问的动作我可以验证。

在我的应用程序有两种类型的用户,账户拥有者和嘉宾。所有操作都是完全开放的帐户所有者,但客人从行动对行动有所不同。举一个例子,一个动作可以要求你有三种权限用于至少一个,(读,写和编辑)。

过滤器:

 公共类ClaimsAuthorizeAccountAccess:AuthorizeAttribute
{
    私人IAccountRepository _accountRepository {搞定;组; }
    私有String [] {_permissions获得;组; }    公共ClaimsAuthorizeAccountAccess(IAccountRepository accountRepository,则params的String []的权限)
    {
        _permissions =权限;
        _accountRepository = accountRepository;
    }    公共覆盖无效OnAuthorization(AuthorizationContext filterContext)
    {
        如果(HttpContext.Current.User.IsInRole(帐户所有者))
        {
            base.OnAuthorization(filterContext);
        }
        其他
        {
            ClaimsIdentity claimsIdentity =(ClaimsIdentity)HttpContext.Current.User.Identity;
            清单< AccountLinkPermissionDTO> accountLinkPermissions =新的List< AccountLinkPermissionDTO>();            INT accountOwnerID = 0;
            Int32.TryParse(claimsIdentity.Claims.Where(C => c.Type ==AccountOwnerID)选择(C =方式> c.Value).SingleOrDefault(),出accountOwnerID);
            INT guestID = 0;
            Int32.TryParse(claimsIdentity.Claims.Where(C => c.Type == ClaimTypes.Sid​​)。选择(C => c.Value).SingleOrDefault(),出guestID);            //空值
            accountLinkPermissions = _accountRepository.GetAccountLinkPermissions(accountOwnerID,guestID);            如果(accountLinkPermissions!= NULL)
            {
                清单<串GT; accountLinkPermissionsToString = accountLinkPermissions.Select(M => m.Permission.Name).ToList();
                INT命中= accountLinkPermissionsToString.Where(M = GT; _permissions.Contains(M))。COUNT();                如果(命中大于0)
                {
                    base.OnAuthorization(filterContext);
                }
            }
            其他
            {
                //客户可是没有正确的权限                filterContext.Result =新RedirectToRouteResult(
                新RouteValueDictionary {
                        {行动,存取遭拒},
                        {控制器,帐户}});
            }
        }
    }
}

如果我是使用这种过滤器上,会看起来像..

  [ClaimsAuthorizeAccountAccess(文件读,写文件,文件编辑)]
公众的ActionResult文件()
{
    返回查看();
}

但是,这并不工作,因为过滤器需要两个参数(IRepository和string [])。它也不可能在这里使用构造器注入,效果显着。

我又试图实施约翰·阿勒斯解决方案,可以发现<一个href=\"http://stackoverflow.com/questions/6121050/mvc-3-unity-2-inject-dependencies-into-a-filter\">here.它看起来很有前途,但它给了我这个错误:


  

类型的例外
  Microsoft.P​​ractices.Unity.ResolutionFailedException发生在
  Microsoft.P​​ractices.Unity.dll但在用户code没有处理


  
  

附加信息:依赖关系解析失败,键入=
  Fildela.ClaimsAuthorizeAccountAccessNAME =(无)。


  
  在解析

而发生异常。
  
  

例外是:出现InvalidOperationException - 属性
  在类型Fildela.ClaimsAuthorizeAccountAccess _accountRepository不可设置。


  
  

  
  

目前的异常时,该容器是:


  
  

解决Fildela.ClaimsAuthorizeAccountAccess,(无)


如何解决这个坏小子?任何建议

谢谢!


解决方案

首先安装官方包, Unity.Mvc 而不是 Unity.MVC4 。这包会自动安装并注册 UnityFilterAttributeFilterProvider 这是我们需要它的属性的依赖注入。你可以检查你的统一通过查找 App_Start > UnityMvcActivator 的Start方法配置好。你必须看到以下两行:

 公共静态无效的开始()
{
    //其他codeS    FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
    FilterProviders.Providers.Add(新UnityFilterAttributeFilterProvider(容器));
}

现在你可以添加 [依赖] 属性筛选的公共属性。

 公共类ClaimsAuthorizeAccountAccess:AuthorizeAttribute
{
    [依赖]
    公共IAccountRepository AccountRepository {搞定;组; }
    私有String [] {_permissions获得;组; }    公共ClaimsAuthorizeAccountAccess(PARAMS的String []的权限)
    {
        _permissions =权限;
    }
}

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

Working example

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).

Filter:

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

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.

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

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

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

Exception occurred while: while resolving.

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


At the time of the exception, the container was:

Resolving Fildela.ClaimsAuthorizeAccountAccess,(none)

Any suggestion on how to solve this bad boy?

Thanks!

解决方案

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

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

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

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