Инъекция зависимостей в пользовательский атрибут фильтра действий Web API с помощью Autofac
Я пытаюсь разрешить зависимости моего пользовательского AuthorizeAttribute
который я использую для украшения моих контроллеров API в приложении MVC4. Проблема в том, что я продолжаю получать NullReferenceException
о зависимости службы, которую я использую в своем пользовательском фильтре. Вот моя конфигурация Autofac:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
var builder = new ContainerBuilder();
builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerApiRequest();
builder.RegisterType<DatabaseFactory>().As<IDatabaseFactory>().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileRepository).Assembly)
.Where(t => t.Name.EndsWith("Repository"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(IUserProfileMapper).Assembly)
.Where(t => t.Name.EndsWith("Mapper"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterAssemblyTypes(typeof(UserProfileSvc).Assembly)
.Where(t => t.Name.EndsWith("Svc"))
.AsImplementedInterfaces().InstancePerApiRequest();
builder.RegisterWebApiFilterProvider(config);
var container = builder.Build();
var resolver = new AutofacWebApiDependencyResolver(container);
config.DependencyResolver = resolver;
}
}
и мой пользовательский фильтр авторизации:
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc _authenticationSvc;
protected override bool IsAuthorized(System.Web.Http.Controllers.HttpActionContext actionContext)
{
if (!base.IsAuthorized(actionContext))
{
return false;
}
var trueUserId = WebSecurity.CurrentUserId;
if (_authenticationSvc.GetUsersRoles(trueUserId).Any(x => x == "Admin")) return true;
// NullReferenceException on _authenticationSvc
}
}
по словам официальные документы все что нужно, это:
var builder = new ContainerBuilder();
builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);
но это, кажется, тоже не делает трюк. Ценю любую помощь.
4 ответов
вы должны настроить инъекцию свойств для своего атрибута
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
строитель
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
в дополнение к ответу @Toan Nguyen, если у вас есть это...
public class MyAuthorizeAttribute : AuthorizeAttribute
{
public IAuthenticationSvc AuthenticationSvc { get; set; }
}
... кажется, вам также нужна (или может понадобиться) первая строка ниже:
builder.RegisterFilterProvider();
builder.RegisterType<MyAuthorizeAttribute>().PropertiesAutowired();
ссылка: http://itprojectpool.blogspot.com.au/2014/03/autofac-di-on-action-filters.html
Я думаю, что документация Autofac предлагает гораздо более простое решение для фильтров действий WebApi.
public interface ServiceCallActionFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
// Get the request lifetime scope so you can resolve services.
var requestScope = actionContext.Request.GetDependencyScope();
// Resolve the service you want to use.
var service = requestScope.GetService(typeof(IMyService)) as IMyService;
// Do the rest of the work in the filter.
service.DoWork();
}
}
Это не "чистый DI", как он использует Service locator, но он прост и работает с областью запроса. Вам не нужно беспокоиться о регистрации конкретного фильтра действий для каждого контроллера WebApi.
в дополнение к настройке инъекции свойств, как указано в других ответах, вы также можете явно разрешить зависимости в OnActivating
обратный.
public class MyAuthorizeAttribute : AuthorizeAttribute
{
private IAuthenticationSvc _authenticationSvc;
public void SetAuthenticationSvc(IAuthenticationSvc svc)
{
this._authenticationSvc = svc;
}
}
и затем зарегистрировать тип:
builder.RegisterType<MyAuthorizeAttribute>()
.OnActivating(_ => _.Instance.SetAuthenticationSvc(_.Context.Resolve<IAuthenticationSvc>()));
Примечание: Вы можете сделать то же самое свойство, а не метод. Я решил использовать метод здесь только для иллюстрации того, что это решение не зависит от PropertiesAutowired
.