0

Мы используем пользовательский AuthorizeAttribute для обработки нескольких аспектов авторизации пользователя. Мне нужно добавить доступ к базе данных, чтобы проверить значение во время авторизации. Этот проект использует шаблон репозитория, и все репозитории создаются в конструкторах контроллера через StructureMap.Узел установки не работает с StructureMap в ASP.NET MVC авторизационный фильтр

К сожалению, похоже, что использовать инжектор конструктора с фильтрами невозможно. Я нашел статью Джимми Богарда (http://lostechies.com/jimmybogard/2010/05/03/dependency-injection-in-asp-net-mvc-filters/), в которой объясняется, как использовать инъекцию свойств для обработки этого сценария. В основном код Jimmy перехватывает метод GetFilters в ControllerActionInvoker и запускает BuildUp на каждом фильтре для заполнения свойств. Это было как раз то, что мне было нужно, поэтому я добавил следующий класс -

public class InjectingActionInvoker : ControllerActionInvoker 
{ 
    private readonly IContainer _container; 

    public InjectingActionInvoker(IContainer container) 
    { 
     _container = container; 
    } 

    protected override FilterInfo GetFilters(
     ControllerContext controllerContext, 
     ActionDescriptor actionDescriptor) 
    { 
     var info = base.GetFilters(controllerContext, actionDescriptor); 

     info.AuthorizationFilters.ForEach(_container.BuildUp); 
     info.ActionFilters.ForEach(_container.BuildUp); 
     info.ResultFilters.ForEach(_container.BuildUp); 
     info.ExceptionFilters.ForEach(_container.BuildUp); 

     return info; 
    } 
} 

А потом проводной его в StructureMap с этими линиями -

For<IActionInvoker>().Use<InjectingActionInvoker>(); 
For<ITempDataProvider>().Use<SessionStateTempDataProvider>(); 

Policies.SetAllProperties(c => 
{ 
    c.OfType<IActionInvoker>(); 
    c.OfType<ITempDataProvider>(); 
    c.WithAnyTypeFromNamespaceContainingType<UserProfileRepository>(); 
}); 

И, наконец, я добавил государственную собственность к моему обычаю AuthorizeAttribute класс -

[SetterProperty] 
public UserProfileRepository User { get; set; } 

Когда я запускаю проект и получить доступ к защищенной странице, й e AuthorizeCore код попадает дважды. В первый раз мое свойство настроено и работает правильно. Тем не менее, второй вызов завершается с ошибкой, так как свойство имеет значение. Я установил точку останова в методе GetFilters, и он попадает только в первый раз. К сожалению, я просто недостаточно разбираюсь в StructureMap или Filters, чтобы точно знать, где это происходит в боковом направлении.

Ниже приведены стеки вызовов, в случае, если это полезно для тех, кто -

вызов # 1

AppName.dll!AppName.Filters.SiteAuthorizeAttribute.AuthorizeCore(System.Web.HttpContextBase httpContext) Line 78 C# 
[External Code] 
AppName.dll!AppName.Filters.SiteAuthorizeAttribute.OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) Line 31 C# 
[External Code] 

вызов # 2

AppName.dll!AppName.Filters.SiteAuthorizeAttribute.AuthorizeCore(System.Web.HttpContextBase httpContext) Line 69 C# 
[External Code] 
AppName.dll!AppName.Filters.SiteAuthorizeAttribute.OnAuthorization(System.Web.Mvc.AuthorizationContext filterContext) Line 31 C# 
[External Code] 
App_Web_1fnmflat.dll!ASP._Page_Views_Shared__Menu_cshtml.Execute() Line 2 C# 
[External Code] 
App_Web_1fnmflat.dll!ASP._Page_Views_Shared__Layout_cshtml.Execute() Line 51 C# 
[External Code] 

Все мастера StructureMap заботитесь поделиться мудростью ? Заранее благодарю за любую помощь!

Edit: Вот код для файла _Menu.cshtml -

@(Html.Kendo().Menu() 
     .Name("Menu") 
     .Items(items => 
     { 
      items.Add().Text("My Dashboard").Action("Dashboard", "Home"); 
      items.Add().Text("My Account").Action("Edit", "Account"); 
      items.Add().Text("Purchase/Renew").Action("Index", "Purchase"); 
      items.Add().Text("Administration") 
       .Items(children => 
       { 
        children.Add().Text("Accounts").Action("Index", "UserProfile"); 
        children.Add().Text("Coupons").Action("Index", "Coupon"); 
       }); 
      items.Add().Text("Logout").Action("Logout", "Logon"); 
     }) 
    ) 

Благодаря некоторым побуждая из NightOwl888, я выделил проблему на вызов меню кэндо. Если я положу точку останова на конечной строке _Menu.cshtml и сделаю шаг, я вижу, что DoGetInstance вызвал мой HomeController. Как только это будет завершено, OnAuthorization будет запущена во второй раз, и мое свойство repo будет null.

Кто-нибудь знает, что мне здесь не хватает?

+0

Я не думаю, что вы найдете ответ, если вы не можете объяснить, почему ваш атрибут авторизированным вызывается дважды, и кто создавая его второй раз. Вызывается метод GetFilters дважды? – NightOwl888

+0

Извините, второй вызов происходит от рендеринга частичного имени _Menu.cshtml внутри моего файла _Layout.cshtml (это можно увидеть в столах вызовов). –

+0

И нет, GetFilters вызывается только один раз (как указано выше). Кажется, что класс кэшируется, но кешированная версия хранится до того, как произошла сборка? Я не знаю. –

ответ

0

К сожалению, я не был в состоянии отследить, что происходит. Так вот, как я «фиксированный» вопрос сейчас -

[SetterProperty] 
    public UserProfileRepository User 
    { 
     get { return _user ?? DependencyResolver.Current.GetService<UserProfileRepository>(); } 
     set { _user = value; } 
    } 

Когда инъекции работает используется нагнетаемая значение, в противном случае я использую DependencyResolver делать грязную работу вручную. Не очень, но у меня нет других вариантов прямо сейчас.

0

Поскольку вы знаете, что GetFilters не вызывается во время второго вызова, и работает первый экземпляр AuthorizeAttribute, это явно не проблема с установкой DI. Если экземпляр AuthorizeAttribute кэшируется, тогда все зависимости будут кэшироваться, так что это не так.

Проблема сводится к тому, что ваше меню не вызывает метод FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor); перед использованием AuthorizeAttribute. Я могу только догадываться, почему, хотя из-за того, что вы не предоставили код для своего меню или его частичный метод.

Вместо этого вы можете попробовать переопределить ControllerActionInvoker.InvokeAuthorizationFilters.

+0

Спасибо. Я попробовал InvokeAuthorizationFilters, но тот же результат. Я добавил дополнительные сведения в приведенное выше изменение. –

0

Я тоже сталкивался с той же проблемой и пытался использовать разные методы, наконец, это сработало для меня после удаления [AllowMultiple = true] и теперь AuthorizeCore называется один раз. Мне любопытно, как это связано с AuthorizeCore.

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)] 
public class CompanyAuthorizeAttribute : AuthorizeAttribute 
{} 

, прежде чем он был

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)] 
public class CompanyAuthorizeAttribute : AuthorizeAttribute 
{} 
+0

Спасибо, Мохан. К несчастью, ваше исправление не помогло мне. Надеюсь, это действительно для кого-то, кто наткнулся на эту страницу! –

+0

У меня возник вопрос о неправильном. Я работал над MVC5 proj и установил StructureMap.MVC5 @GitHub. Это дает вам базовый IOC. Чтобы реализовать IOC для фильтров, я сделал следующие изменения. ActionInvoker ожидает контейнер obj. public static IContainer Initialize() { \t var _con = new Контейнер (c => c.AddRegistry ()); \t _con.Configure (c => c.AddRegistry (новый ActionFilterRegistry (_con))); \t return _con; } ActionFilterRegistry класс общественности: Registry { \t общественного ActionFilterRegistry (IContainer кон) \t { \t \t Для () Используйте (новый InjectingActionInvoker (кон));. \t \t Policies.SetAllProperties (....); \t} } –

0

я не получил эту работу с поставщиком пользовательских фильтров, как описано в этой теме:

How can you unit test an Action Filter in ASP.NET Web Api?

Я попытался кучу вариантов, но в конечном итоге инъекционного зависимость разрешающую функции в свои атрибуты , Таким образом, модульные тесты могут вводить функцию, которая возвращает фальшивый, макет или что-то еще, в то время как приложение может вводить функцию, которая разрешает зависимость с использованием контейнера IoC.

Я написал короткое сообщение в блоге о том, как я получил его на работу. Очень хотелось бы услышать, что вы думаете об этом, и если он помог вам:

http://danielsaidi.com/blog/2015/09/11/asp-net-and-webapi-attributes-with-structuremap

 Смежные вопросы

  • Нет связанных вопросов^_^