此解决方案适用于 Windsor 3.0 及更高版本。它基于 PerWebRequest Lifestyle 的实现,并利用 Windsor 3.0 中引入的新 Scoped Lifestyle。
你需要两节课...
IHttpModule
处理会话管理的实现。将ILifetimeScope
对象添加到会话中,并在会话到期时再次处理它。这对于确保正确发布组件至关重要。到目前为止,这里给出的其他解决方案都没有考虑到这一点。
public class PerWebSessionLifestyleModule : IHttpModule
{
private const string key = "castle.per-web-session-lifestyle-cache";
public void Init(HttpApplication context)
{
var sessionState = ((SessionStateModule)context.Modules["Session"]);
sessionState.End += SessionEnd;
}
private static void SessionEnd(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var scope = GetScope(app.Context.Session, false);
if (scope != null)
{
scope.Dispose();
}
}
internal static ILifetimeScope GetScope()
{
var current = HttpContext.Current;
if (current == null)
{
throw new InvalidOperationException("HttpContext.Current is null. PerWebSessionLifestyle can only be used in ASP.Net");
}
return GetScope(current.Session, true);
}
internal static ILifetimeScope YieldScope()
{
var context = HttpContext.Current;
if (context == null)
{
return null;
}
var scope = GetScope(context.Session, true);
if (scope != null)
{
context.Session.Remove(key);
}
return scope;
}
private static ILifetimeScope GetScope(HttpSessionState session, bool createIfNotPresent)
{
var lifetimeScope = (ILifetimeScope)session[key];
if (lifetimeScope == null && createIfNotPresent)
{
lifetimeScope = new DefaultLifetimeScope(new ScopeCache(), null);
session[key] = lifetimeScope;
return lifetimeScope;
}
return lifetimeScope;
}
public void Dispose()
{
}
}
您需要的第二个类是IScopeAccessor
. 这用于弥合 HttpModule 和内置 WindsorScopedLifestyleManager
类之间的差距。
public class WebSessionScopeAccessor : IScopeAccessor
{
public void Dispose()
{
var scope = PerWebSessionLifestyleModule.YieldScope();
if (scope != null)
{
scope.Dispose();
}
}
public ILifetimeScope GetScope(CreationContext context)
{
return PerWebSessionLifestyleModule.GetScope();
}
}
添加了两种internal static
方法PerWebSessionLifestyleModule
来支持这一点。
就是这样,期待注册它...
container.Register(Component
.For<ISometing>()
.ImplementedBy<Something>()
.LifestyleScoped<WebSessionScopeAccessor>());
或者,我将此注册包装到扩展方法中......
public static class ComponentRegistrationExtensions
{
public static ComponentRegistration<TService> LifestylePerSession<TService>(this ComponentRegistration<TService> reg)
where TService : class
{
return reg.LifestyleScoped<WebSessionScopeAccessor>();
}
}
所以可以这样称呼...
container.Register(Component
.For<ISometing>()
.ImplementedBy<Something>()
.LifestylePerSession());