我在 .NET MVC 5 应用程序中使用 Unity 解析组件时遇到问题。在我的 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 在遵循 SayDoAuthorizeHelper.GetRolesAndCacheThem 方法时无法解析 IUserProvider 组件。(我希望这个类是静态的,因为 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>();
我也尝试用 VirtualMethodInterceptor 替换 InterfaceInterceptor,但结果相同。任何人都可以帮忙吗?我不知道出了什么问题。感谢帮助。解决方案是用 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" />