我正在开发一个使用MVC 5 application
来处理依赖注入的Ninject
。应用程序定义了SecurityService
,它提供了有关当前登录用户的各种信息。我正在使用Windows身份验证。
好的,让我们深入了解代码。
NinjectWebCommon.cs
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
private static KernelBase kernel;
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISecurityService>().To<SecurityService>().InRequestScope();
// custom bindings are defined here
}
public static void PerformInjectionOn(object instance)
{
kernel.Inject(instance);
}
请注意安全绑定定义kernel.Bind<ISecurityService>().To<SecurityService>().InRequestScope();
。
SecurityService.cs
private AppUser _CurrentUser = null;
/// <summary>
/// gets logged user data, based on current identity username (Sam account name)
/// </summary>
/// <returns>AppUser object if windows identity maps to an existing active user. Otherwise null</returns>
public AppUser GetLoggedUserData()
{
lock(lockObj)
{
String currUsername = WindowsIdentity.GetCurrent().Name;
// comparison between current user name and actually authenticated user is needed since some requests end with different values!
if (_CurrentUser == null || !_CurrentUser.Username.Equals(currUsername))
{
_CurrentUser = _ScopedDataAccess.AppUserRepository.AllNoTracking
// some includes
.SingleOrDefault(u => u.IsEnabled && u.Username.Equals(currUsername));
if (_CurrentUser == null)
{
logger.LogEx(LogLevel.Info, "GetLoggedUserData - user {0} authentication failed", currUsername);
return null;
}
}
return _CurrentUser;
}
}
我的问题是,即使每个请求实例化SecurityService
,有时我会收到_CurrentUser.Username
与currUsername
不同的实例(即两者都是有效的A / D用户)我进行了测试。
当前的解决方法是让!_CurrentUser.Username.Equals(currUsername)
使缓存的用户实例无效,如果请求身份验证的用户与缓存的用户不同,但我想知道发生了什么。
出于好奇,我检查了InThreadScope
并遇到了同样的问题,但我认为这可以解释为IIS使用的线程池可能为另一个请求提供相同的线程。
有谁知道为什么InRequestScope的行为如此?
感谢。
[编辑]
当前用户与缓存的用户不同时调用堆栈:
ProjectName.Models.dll!ProjectName.Models.SecurityService.GetLoggedUserData()第54行C# ProjectName.Models.dll!ProjectName.Models.SecurityService.GetAndCheckUserData()第76行C# ProjectName.Models.dll!ProjectName.Models.SecurityService.IsAdmin.get()第98行C# ProjectName.Models.dll!ProjectName.Models.EntitiesCache.ProjectStatuses.get()第51行C# ProjectName.Services.dll!ProjectName.Services.ProjectService.CreateSelectorsDomain()第253行C# ProjectName.Services.dll!ProjectName.Services.ProjectService.ProjectService(ProjectName.Models.ISecurityService securityService,ProjectName.Models.IEntitiesCache entitiesCache,ProjectName.Models.IScopedDataAccess dataAccess,ProjectName.Services.IProjectTemplateService projectTemplateService)第33行C# [外部代码] ProjectName.Web.dll!ProjectName.Web.NinjectWebCommon.PerformInjectionOn(对象实例)第93行C# ProjectName.Web.dll!ProjectName.Web.BaseController.BaseController()第21行C# [外部代码]
同步所有步骤中的逻辑(无async
,await
,无Tasks
)