依存性注入を処理するため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 。ウェブ。NinjectWebCommon.PerformInjectionOn(オブジェクト インスタンス) 93 行目 C# ProjectName.Web.dll!ProjectName.Web.BaseController.BaseController() 21 行目 C# [外部コード]
同期のすべてのステップのロジック (no async
、await
、 no Tasks
)