Инъекция зависимостей с атрибутом Ninject и Filter для asp.net mvc
Я пишу настраиваемый фильтр авторизации для asp.net mvc 3. Мне нужно ввести в сервис userervice, но я понятия не имею, как это сделать.
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private IUserService userService;
private string[] roles;
public AuthorizeAttribute(params string[] roles)
{
this.roles = roles;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
throw new NotImplementedException();
}
}
Я использую ninject для инъекции зависимостей. Я не хочу использовать шаблон Factory или локатор службы.
Мои привязки выглядят так, как в global.acsx:
internal class SiteModule : NinjectModule
{
public override void Load()
{
Bind<IUserService>().To<UserService>();
}
}
Ответы
Ответ 1
Смотрите этот ответ:
Пользовательская авторизация MVC 3 и Ninject IoC
Если вы хотите использовать инсталляцию конструктора, вам нужно создать атрибут и фильтр.
///marker attribute
public class MyAuthorizeAttribute : FilterAttribute { }
//filter
public class MyAuthorizeFilter : IAuthorizationFilter
{
private readonly IUserService _userService;
public MyAuthorizeFilter(IUserService userService)
{
_userService = userService;
}
public void OnAuthorization(AuthorizationContext filterContext)
{
var validUser = _userService.CheckIsValid();
if (!validUser)
{
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary { { "action", "AccessDenied" }, { "controller", "Error" } });
}
}
}
Переплет:
this.BindFilter<MyAuthorizeFilter>(System.Web.Mvc.FilterScope.Controller, 0).WhenControllerHas<MyAuthorizeAttribute>();
Контроллер:
[MyAuthorizeAttribute]
public class YourController : Controller
{
}
НТН...
Ответ 2
Я очень рекомендую ответить B Z. НЕ использовать [Inject]!
Я использовал [Inject], как сказал Дарин Димитров, и это действительно вызвало проблемы с резьбой при высокой нагрузке, высокие конфликтные ситуации в сочетании с .InRequestScope.
B Z путь также есть в Wiki, и я видел много мест, где Remo Gloor (автор Ninject) говорит, что это правильный способ сделать это
https://github.com/ninject/ninject.web.mvc/wiki/Filter-configurations
Вниз [Inject] отвечает здесь, потому что серьезно вы сожжетесь (возможно, на производстве, если вы не загрузите тест правильно ранее!)
Ответ 3
В пути можно было бы использовать вложение свойств и украсить свойство атрибутом [Inject]
:
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
[Inject]
public IUserService UserService { get; set; }
private string[] roles;
...
}
Встраивание конструктора плохо работает с атрибутами, поскольку вы больше не сможете украшать контроллеры/действия с ними. Вы можете использовать инъекцию конструктора с синтаксисом привязки фильтра в NInject:
public class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
private readonly IUserService userService;
private string[] roles;
public AuthorizeAttribute(IUserService userService, params string[] roles)
{
this.userService = userService;
this.roles = roles;
}
...
}
а затем:
internal class SiteModule : Ninject.Modules.NinjectModule
{
public override void Load()
{
Bind<IUserService>().To<UserService>();
this.BindFilter<AuthorizeAttribute>(FilterScope.Controller, 0)
.WhenControllerType<AdminController>();
}
}
Метод расширения BindFilter<>
определяется в пространстве имен Ninject.Web.Mvc.FilterBindingSyntax
, поэтому убедитесь, что вы ввели это в область действия, прежде чем вызывать его на ядре.
Ответ 4
Я нашел простое решение для любого случая, когда конструкцией не обрабатывается Ninject:
var session = (IMyUserService)DependencyResolver.Current.GetService(typeof (IMyUserService));
На самом деле это именно то, что я использую с моим пользовательским атрибутом AuthorizeAttribute.
Намного легче, чем реализовать отдельный FilterAttribute.