Сбой компонента UnityConfig.Resolve при использовании перехвата единиц - PullRequest
0 голосов
/ 05 мая 2018

У меня проблема с разрешением компонента с Unity в моем приложении .NET MVC 5. В моей папке App_Start я сгенерировал UnityConfig.cs и UnityMvcActivator.cs, который выглядит следующим образом:

public static class UnityConfig
{
    #region Unity Container
    private static Lazy<IUnityContainer> container =
      new Lazy<IUnityContainer>(() =>
      {
          var container = new UnityContainer();
          RegisterTypes(container);
          return container;
      });
    public static IUnityContainer Container => container.Value;
    #endregion

    public static void RegisterTypes(IUnityContainer container)
    {
        // NOTE: To load from web.config uncomment the line below.
        // Make sure to add a Unity.Configuration to the using statements.
        // container.LoadConfiguration();

        container.AddNewExtension<Interception>();

        container.RegisterType<ILogger, EntLibFileLogger>(new ContainerControlledLifetimeManager(),
            new InjectionConstructor(ConfigurationManager.AppSettings["logTrace"],
                int.Parse(ConfigurationManager.AppSettings["logSize"])));
        container.RegisterType<IUserRepository, UserRepository>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<LoggingInterceptionBehavior>());
        container.RegisterType<IUserProvider, UserProvider>(new Interceptor<InterfaceInterceptor>(), new InterceptionBehavior<LoggingInterceptionBehavior>());
        ...
    }
}

public static class UnityMvcActivator
{
    /// <summary>
    /// Integrates Unity when the application starts.
    /// </summary>
    public static void Start() 
    {
        FilterProviders.Providers.Remove(FilterProviders.Providers.OfType<FilterAttributeFilterProvider>().First());
        FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(UnityConfig.Container));

        DependencyResolver.SetResolver(new UnityDependencyResolver(UnityConfig.Container));

        // TODO: Uncomment if you want to use PerRequestLifetimeManager
        // Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    }

    /// <summary>
    /// Disposes the Unity container when the application is shut down.
    /// </summary>
    public static void Shutdown()
    {
        UnityConfig.Container.Dispose();
    }
}

Перехват выглядит так:

class LoggingInterceptionBehavior : IInterceptionBehavior
{
    private readonly ILogger _logger;

    public LoggingInterceptionBehavior(ILogger logger)
    {
        _logger = logger;
    }

    public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
    {
        var methodDesc = $"{input.MethodBase.DeclaringType.Name}.{input.MethodBase.Name}";
        var args = input.Arguments == null || input.Arguments.Count == 0
            ? "null"
            : JsonConvert.SerializeObject(input.Arguments);
        // Before invoking the method on the original target.
        _logger.Log($"{methodDesc} start. Arguments: {args}", LogLevel.Info);

        // Invoke the next behavior in the chain.
        var result = getNext()(input, getNext);

        // After invoking the method on the original target.
        if (result.Exception != null)
        {
            _logger.Log($"{methodDesc} threw exception. {result.Exception.GetBaseException()}", LogLevel.Error);
        }
        else
        {
            _logger.Log($"{methodDesc} end", LogLevel.Info);
        }

        return result;
    }

    public IEnumerable<Type> GetRequiredInterfaces()
    {
        return Type.EmptyTypes;
    }

    public bool WillExecute
    {
        get { return true; }
    }
}

Я также настроил фильтр авторизации, где следующий код:

public class SayDoAuthorizeAttribute : AuthorizeAttribute
{
    private readonly string[] allowedRoles;

    public SayDoAuthorizeAttribute() : base()
    {
    }

    public SayDoAuthorizeAttribute(params string[] roles)
    {
        allowedRoles = roles;
    }

    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var userRoles = SayDoAuthorizeHelper.GetRolesAndCacheThem(httpContext);
        bool authorize = false;
        foreach (var role in allowedRoles)
        {
            if (userRoles.Contains(role))
            {
                authorize = true;
                break;
            }
        }
        return authorize;
    }

    ...
}

Проблема в том, что UnityConfig.Resolve не удается разрешить компонент IUserProvider в следующем методе SayDoAuthorizeHelper.GetRolesAndCacheThem. (Я хочу, чтобы этот класс был статическим, потому что методы IsUserInRole и IsUserInRoles также используются в видах бритвы.

public static class SayDoAuthorizeHelper
{
    public static IEnumerable<string> GetRolesAndCacheThem(HttpContextBase httpContext)
    {
        var nameFromSession = httpContext.Session[Constants.SessionKeyUserPreselectSession];
        var userName = (nameFromSession != null) ? (string)nameFromSession : httpContext.User.Identity.Name;

        var rolesString = (string)httpContext.Cache.Get(userName);
        if (string.IsNullOrEmpty(rolesString))
        {
            var userProvider = UnityConfig.Container.Resolve<IUserProvider>();
            var roles = userProvider.GetUserRolesNames(userName);
            rolesString = string.Join(",", roles);
            //set absolute cache
            var minutesToCacheRoles = double.Parse(ConfigurationManager.AppSettings[Constants.KeyCacheUserRolesInMinutes]);
            httpContext.Cache.Insert(userName, rolesString, null, DateTime.Now.AddMinutes(minutesToCacheRoles), Cache.NoSlidingExpiration);
            return roles;
        }
        return rolesString.Split(',').ToList();
    }

    public static bool IsUserInRole(System.Security.Principal.IPrincipal userPrincipal, string roleName)
    {
        var userRoles = GetRolesAndCacheThem(new HttpContextWrapper(HttpContext.Current));
        return userRoles.Contains(roleName);
    }

    public static bool IsUserInRoles(System.Security.Principal.IPrincipal userPrincipal, string[] roleNames)
    {
        var userRoles = GetRolesAndCacheThem(new HttpContextWrapper(HttpContext.Current));
        foreach (var roleName in roleNames)
        {
            if (userRoles.Contains(roleName))
            {
                return true;
            }
        }
        return false;
    }
}

Когда у меня установлена ​​точка останова на линии var userProvider = UnityConfig.Container.Resolve (); затем не генерируется исключение, и код все еще продолжается, но я вижу в локальных переменных, что userProvider выдал исключение типа 'System.IO.FileNotFoundException' Abb.Czopc.SayDo.BusinessLogic.Interface.IUserProvider {System.IO.FileNotFoundException} с сообщением «Не удается загрузить сборку« 15bd37ce9f8a41d9b9916a1ebadc536a ».». Но в окне вывода я вижу, что сборка была загружена. 'iisexpress.exe' (CLR v4.0.30319: / LM / W3SVC / 2 / ROOT-1-131699797337577440): загружен '15bd37ce9f8a41d9b9916a1ebadc536a'.

Когда я регистрируюсь в UnityConfig без перехвата, все работает хорошо.

    container.RegisterType<IUserRepository, UserRepository>();
    container.RegisterType<IUserProvider, UserProvider>();

Я также пытался заменить InterfaceInterceptor на VirtualMethodInterceptor, но с тем же результатом. Кто-нибудь может помочь? Я не знаю, что не так. Спасибо за помощь. Решение написано в VS 2015, список пакетов nuget здесь:

  <package id="Abb.Czopc.Common.Log" version="1.0.1" targetFramework="net451" />
  <package id="Abb.Czopc.Common.Log.EntLibLogger" version="1.0.1" targetFramework="net451" />
  <package id="Antlr" version="3.5.0.2" targetFramework="net451" />
  <package id="AutoMapper" version="6.2.2" targetFramework="net451" />
  <package id="EnterpriseLibrary.Common" version="6.0.1304.0" targetFramework="net451" />
  <package id="EnterpriseLibrary.Logging" version="6.0.1304.0" targetFramework="net451" />
  <package id="jQuery" version="3.3.1" targetFramework="net451" />
  <package id="jQuery.Validation" version="1.17.0" targetFramework="net451" />
  <package id="Microsoft.AspNet.Mvc" version="5.2.4" targetFramework="net451" />
  <package id="Microsoft.AspNet.Razor" version="3.2.4" targetFramework="net451" />
  <package id="Microsoft.AspNet.Web.Optimization" version="1.1.3" targetFramework="net451" />
  <package id="Microsoft.AspNet.WebPages" version="3.2.4" targetFramework="net451" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.8" targetFramework="net451" />
  <package id="Microsoft.jQuery.Unobtrusive.Ajax" version="3.2.5" targetFramework="net451" />
  <package id="Microsoft.jQuery.Unobtrusive.Validation" version="3.2.9" targetFramework="net451" />
  <package id="Microsoft.Net.Compilers" version="2.7.0" targetFramework="net451" developmentDependency="true" />
  <package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net451" />
  <package id="Modernizr" version="2.8.3" targetFramework="net451" />
  <package id="Newtonsoft.Json" version="11.0.2" targetFramework="net451" />
  <package id="Respond" version="1.4.2" targetFramework="net451" />
  <package id="Unity.Abstractions" version="3.3.0" targetFramework="net451" />
  <package id="Unity.Container" version="5.8.5" targetFramework="net451" />
  <package id="Unity.Interception" version="5.5.1" targetFramework="net451" />
  <package id="Unity.Mvc" version="5.0.13" targetFramework="net451" />
  <package id="WebActivatorEx" version="2.2.0" targetFramework="net451" />
  <package id="WebGrease" version="1.6.0" targetFramework="net451" />
...