asp.net web api - How can I use Castle Windsor's PerWebRequest lifestyle with OWIN -


i converting existing asp .net web api 2 project use owin. project uses castle windsor dependency injection framework 1 of dependencies set use perwebrequest lifestyle.

when make request server castle.microkernel.componentresolutionexception exception. exception recommends adding following system.web/httpmodules , system.webserver/modules sections in config file:

<add name="perrequestlifestyle"      type="castle.microkernel.lifestyle.perwebrequestlifestylemodule, castle.windsor" /> 

this doesn't resolve error.

taking inspiration example provided simpleinjector's owin integration, attempted set scope in owin startup class (as update dependency's lifestyle) using:

appbuilder.user(async (context, next) => {     using (config.dependencyresolver.beginscope()){     {         await next();     } } 

unfortunately hasn't worked either.

how can use castle windsor's perwebrequest lifestyle or simulate in owin?

according castle windsor documentation can implement own custom scope. have implement castle.microkernel.lifestyle.scoped.iscopeaccessor interface.

you specify scope accessor when registering component:

container.register(component.for<myscopedcomponent>().lifestylescoped<owinwebrequestscopeaccessor >()); 

the class owinwebrequestscopeaccessor implements castle.windsor's 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 can see owinwebrequestscopeaccessor delegates calls getscope , dispose perwebrequestlifestyleowinmiddleware.

the class perwebrequestlifestyleowinmiddleware owin counter part of castle windsor's asp.net ihttpmodule perwebrequestlifestylemodule.

this 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);             }                         {                 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 null. " +                     typeof(perwebrequestlifestyleowinmiddleware).fullname +" can used owin.");             }             return getscope(context, createifnotpresent: true);         }          /// <summary>         /// returns current request's scope , detaches request          /// context. not throw if scope or context not present.          /// used disposing of context.         /// </summary>         /// <returns></returns>         internal static ilifetimescope yieldscope()         {             var context = owinrequestscopecontext.current;             if (context == null)             {                 return null;             }             var scope = getscope(context, createifnotpresent: false);             if (scope != null)             {                 context.items.remove(c_key);             }             return scope;         }          private static void ensureinitialized()         {             if (_initialized)             {                 return;             }             throw new componentresolutionexception("looks forgot register owin middleware " + typeof(perwebrequestlifestyleowinmiddleware).fullname);         }          private static ilifetimescope getscope(iowinrequestscopecontext context, bool createifnotpresent)         {             ilifetimescope candidates = null;             if (context.items.containskey(c_key))             {                 candidates = (ilifetimescope)context.items[c_key];             }             else if (createifnotpresent)             {                 candidates = new defaultlifetimescope(new scopecache());                 context.items[c_key] = candidates;             }             return candidates;         }     }      public static class appbuilderperwebrequestlifestyleowinmiddlewareextensions     {         /// <summary>         /// use <see cref="perwebrequestlifestyleowinmiddleware"/>.         /// </summary>         /// <param name="app">owin app.</param>         /// <returns></returns>         public static iappbuilder useperwebrequestlifestyleowinmiddleware(this iappbuilder app)         {             return app.use(typeof(perwebrequestlifestyleowinmiddleware));         }     } } 

castle windsor's asp.net ihttpmodule perwebrequestlifestylemodule utilizes httpcontext.current storing castle windsor ilifetimescope on per-web-request basis. perwebrequestlifestyleowinmiddleware class uses owinrequestscopecontext.current. based on idea of yoshifumi kawai.

the implementation of owinrequestscopecontext below lightweight implementation of yoshifumi kawai's original owinrequestscopecontext.


note: if don't want lightweight implementation can use yoshifumi kawai's excellent original implementation running command in nuget package manager console:

pm> install-package owinrequestscopecontext


lightweight 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>();          /// <summary>         /// gets or sets <see cref="iowinrequestscopecontext"/> object          /// current http request.         /// </summary>         public static iowinrequestscopecontext current         {                         {                 var requestcontext = callcontext.logicalgetdata(c_callcontextkey) iowinrequestscopecontext;                 if (requestcontext == null)                 {                     requestcontext = new owinrequestscopecontext();                     callcontext.logicalsetdata(c_callcontextkey, requestcontext);                 }                 return requestcontext;             }             set             {                 callcontext.logicalsetdata(c_callcontextkey, value);             }         }          public void endrequest()         {             callcontext.freenameddataslot(c_callcontextkey);         }          public idictionary<string, object> items         {                         {                 return _items;             }         }          public datetime timestamp         {                         {                 return _utctimestamp.tolocaltime();             }         }     } } 

when have pieces in place can tie things up. in owin startup class call appbuilder.useperwebrequestlifestyleowinmiddleware(); extension method register owin middle ware defined above. 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();              //             // configure web api self-host.              //             httpconfiguration config = new httpconfiguration();             webapiconfig.register(config);             appbuilder.usewebapi(config);         }          public void close()         {             if (_container != null)                 _container.dispose();         }     } } 

the sample windsorinstaller class shows how can use owin per-web-request scope:

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 have laid out above based on existing /src/castle.windsor/microkernel/lifestyle/perwebrequestlifestylemodule.cs , yoshifumi kawai'soriginal owinrequestscopecontext.


Comments

Popular posts from this blog

Android : Making Listview full screen -

javascript - Parse JSON from the body of the POST -

javascript - Chrome Extension: Interacting with iframe embedded within popup -