According to Castle Windsor documentation, you can implement your own area. You must implement the Castle.MicroKernel.Lifestyle.Scoped.IScopeAccessor interface.
Then you indicate your access aspect when registering your component:
Container.Register(Component.For<MyScopedComponent>().LifestyleScoped<OwinWebRequestScopeAccessor >());
The OwinWebRequestScopeAccessor class implements Castle.Windsor IScopeAccessor :
using Castle.MicroKernel.Context; using Castle.MicroKernel.Lifestyle.Scoped; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace Web.Api.Host { public class OwinWebRequestScopeAccessor : IScopeAccessor { public void Dispose() { var scope = PerWebRequestLifestyleOwinMiddleware.YieldScope(); if (scope != null) { scope.Dispose(); } } public ILifetimeScope GetScope(CreationContext context) { return PerWebRequestLifestyleOwinMiddleware.GetScope(); } } }
As you can see, OwinWebRequestScopeAccessor delegates GetScope and Dispose calls to PerWebRequestLifestyleOwinMiddleware .
The PerWebRequestLifestyleOwinMiddleware class is part of the OWIN counter in Castle Windsor ASP.NET IHttpModule PerWebRequestLifestyleModule .
This is the PerWebRequestLifestyleOwinMiddleware class:
using Castle.MicroKernel; using Castle.MicroKernel.Lifestyle.Scoped; using Owin; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Web.Api.Host { using AppFunc = Func<System.Collections.Generic.IDictionary<string, object>, System.Threading.Tasks.Task>; public class PerWebRequestLifestyleOwinMiddleware { private readonly AppFunc _next; private const string c_key = "castle.per-web-request-lifestyle-cache"; private static bool _initialized; public PerWebRequestLifestyleOwinMiddleware(AppFunc next) { _next = next; } public async Task Invoke(IDictionary<string, object> environment) { var requestContext = OwinRequestScopeContext.Current; _initialized = true; try { await _next(environment); } finally { var scope = GetScope(requestContext, createIfNotPresent: false); if (scope != null) { scope.Dispose(); } requestContext.EndRequest(); } } internal static ILifetimeScope GetScope() { EnsureInitialized(); var context = OwinRequestScopeContext.Current; if (context == null) { throw new InvalidOperationException(typeof(OwinRequestScopeContext).FullName +".Current is null. " + typeof(PerWebRequestLifestyleOwinMiddleware).FullName +" can only be used with OWIN."); } return GetScope(context, createIfNotPresent: true); }
Windsor Castle ASP.NET IHttpModule PerWebRequestLifestyleModule uses HttpContext.Current to store Castle Windsor ILifetimeScope for each web request. PerWebRequestLifestyleOwinMiddleware class uses the OwinRequestScopeContext.Current . This is based on the idea of Yoshifumi Kawai .
The implementation of the OwinRequestScopeContext below is my easy implementation of the original Yoshifumi Kawai OwinRequestScopeContext .
Note. If you do not want this easy implementation, you can use the excellent original implementation of Yoshifumi Kawai by running this command in the NuGet package manager console:
PM> Install-Package OwinRequestScopeContext
Easy implementation of OwinRequestScopeContext :
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Runtime.Remoting.Messaging; using System.Text; using System.Threading.Tasks; namespace Web.Api.Host { public interface IOwinRequestScopeContext { IDictionary<string, object> Items { get; } DateTime Timestamp { get; } void EndRequest(); } public class OwinRequestScopeContext : IOwinRequestScopeContext { const string c_callContextKey = "owin.reqscopecontext"; private readonly DateTime _utcTimestamp = DateTime.UtcNow; private ConcurrentDictionary<string, object> _items = new ConcurrentDictionary<string, object>();
When you have all the parts in place, you can knit things together. In your OWIN launch class, call the extension method appBuilder.UsePerWebRequestLifestyleOwinMiddleware(); to register the OWIN middleware defined above. Do this before appBuilder.UseWebApi(config); :
using Owin; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Web.Http; using System.Diagnostics; using Castle.Windsor; using System.Web.Http.Dispatcher; using System.Web.Http.Tracing; namespace Web.Api.Host { class Startup { private readonly IWindsorContainer _container; public Startup() { _container = new WindsorContainer().Install(new WindsorInstaller()); } public void Configuration(IAppBuilder appBuilder) { var properties = new Microsoft.Owin.BuilderProperties.AppProperties(appBuilder.Properties); var token = properties.OnAppDisposing; if (token != System.Threading.CancellationToken.None) { token.Register(Close); } appBuilder.UsePerWebRequestLifestyleOwinMiddleware();
An example WindsorInstaller class shows how you can use the OWIN scope for each web request:
using Castle.MicroKernel.Registration; using Castle.MicroKernel.SubSystems.Configuration; using Castle.Windsor; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Web.Api.Host { class WindsorInstaller : IWindsorInstaller { public void Install(IWindsorContainer container, IConfigurationStore store) { container.Register(Component .For<IPerWebRequestDependency>() .ImplementedBy<PerWebRequestDependency>() .LifestyleScoped<OwinWebRequestScopeAccessor>()); container.Register(Component .For<Controllers.V1.TestController>() .LifeStyle.Transient); } } }
The solution outlined above is based on the existing /src/Castle.Windsor/MicroKernel/Lifestyle/PerWebRequestLifestyleModule.cs and Yoshifumi Kawai'ororinal OwinRequestScopeContext .