user3899265
user3899265

Reputation: 31

UnityConfig.Resolve component failed when unity interception is used

I have problem with resolving component with Unity in my .NET MVC 5 app. In my App_Start folder I have generated UnityConfig.cs and UnityMvcActivator.cs, which looks like this:

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

Interception look like this:

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

I have also customized authorization filter, where is following code:

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

    ...
}

The problem is that UnityConfig.Resolve fails on resolving IUserProvider component in following SayDoAuthorizeHelper.GetRolesAndCacheThem method. (I want to have this class static, because IsUserInRole and IsUserInRoles mehthods are also used in razor views.

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

When I have breakpoint set on line var userProvider = UnityConfig.Container.Resolve(); then no exception is thrown, and code still continue, but I see in local variables that userProvider threw an exception of type 'System.IO.FileNotFoundException' Abb.Czopc.SayDo.BusinessLogic.Interface.IUserProvider {System.IO.FileNotFoundException} with message "Cannot load assembly '15bd37ce9f8a41d9b9916a1ebadc536a'.". But in output window I see that assembly was loaded. 'iisexpress.exe' (CLR v4.0.30319: /LM/W3SVC/2/ROOT-1-131699797337577440): Loaded '15bd37ce9f8a41d9b9916a1ebadc536a'.

When I have registration in UnityConfig without Interception, everything works good.

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

I also tried replace InterfaceInterceptor with VirtualMethodInterceptor, but with same result. Can anyone help? I dont know what is wrong. Thanks for help. Solution is written in VS 2015, list of nuget packages is here:

  <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" />

Upvotes: 2

Views: 700

Answers (0)

Related Questions