I'm trying to run Nancy app without http.sys and IIS. The example https://github.com/ArloL/NancyInGate works perfectly with TinyIoC but fails with Windsor. Steps for test:
1. Pull https://github.com/ArloL/NancyInGate project
2. Add NuGet dependency Nancy.Bootstrappers.Windsor
3. Add empty bootstrapper inherited from WindsorNancyBootstrapper
4. Run application
5. Try to access it by http://localhost:8081
After this steps I get:
Nancy.RequestExecutionException: Oh noes! ---> System.NullReferenceException: Object reference not set to an instance of an object.
at Castle.MicroKernel.Lifestyle.Scoped.CallContextLifetimeScope.GetCachedInstance(ComponentModel instance, ScopedInstanceActivationCallback createInstance)
at Castle.MicroKernel.Lifestyle.ScopedLifestyleManager.Resolve(CreationContext context, IReleasePolicy releasePolicy)
at Castle.MicroKernel.Handlers.DefaultHandler.ResolveCore(CreationContext context, Boolean requiresDecommission, Boolean instanceRequired, Burden& burden)
at Castle.MicroKernel.Handlers.DefaultHandler.Resolve(CreationContext context, Boolean instanceRequired)
at Castle.MicroKernel.Handlers.AbstractHandler.Resolve(CreationContext context)
at Castle.MicroKernel.DefaultKernel.ResolveComponent(IHandler handler, Type service, IDictionary additionalArguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Castle.MicroKernel.IKernelInternal.Resolve(String key, Type service, IDictionary arguments, IReleasePolicy policy)
at Castle.MicroKernel.DefaultKernel.Resolve(String key, Type service, IDictionary arguments)
at Castle.Windsor.WindsorContainer.Resolve[T](String key)
at Nancy.Bootstrappers.Windsor.WindsorNancyBootstrapper.GetModuleByKey(String moduleKey, NancyContext context)
at Nancy.Routing.DefaultRouteResolver.GetInitializedModuleForMatch(NancyContext context, Tuple`4 routeMatchToReturn)
at Nancy.Routing.DefaultRouteResolver.CreateRouteAndParametersFromMatch(NancyContext context, Tuple`4 routeMatchToReturn)
at Nancy.Routing.DefaultRouteResolver.Resolve(String path, NancyContext context, IRouteCache routeCache)
at Nancy.Routing.DefaultRouteResolver.Resolve(NancyContext context)
at Nancy.NancyEngine.ResolveAndInvokeRoute(NancyContext context)
at Nancy.NancyEngine.InvokeRequestLifeCycle(NancyContext context, IPipelines pipelines)
--- End of inner exception stack trace ---
at Nancy.NancyEngine.InvokeOnErrorHook(NancyContext context, ErrorPipeline pipeline, Exception ex)
My brief examination shows that there's problem with private cache in CallContextLifetimeScope instance. On first call for WindsorNancyBootstrapper.GetModuleByKey object of type CallContextLifetimeScope exists and returns with CallContextLifetimeScope.ObtainCurrentScope(). But it seems to be disposed - cache is null already.
You're probably the first to really test this bootstrapper without ASP.NET and HttpContext. The CallContext is supposed to scope things to the current call chain, but doesn't look like it got called. I don't see the call to HandleRequest in there, so perhaps something changed in Nancy here.
If you look at the interceptor (https://github.com/NancyFx/Nancy.Bootstrappers.Windsor/blob/master/src/Nancy.BootStrappers.Windsor/NancyRequestScopeInterceptor.cs) you can see that it only wraps HandleRequest in that call context (that is what BeginScope() is supposed to do). You might trace through and see what's happening there and if that is indeed being called to create the CallContextLifetimeScope.
Well, I've tested this bootstrapper with Nancy.Hosting.Self and it works perfectly.
Ok, I'll find a way to trace through there projects. Am I right that there should be _container.BeginScope for every route through interceptor that uses scoped modules?
I've traced a little bit, but no luck.
I think that I do not completely understand some basic principles, but I see following:
1. Interceptor catches invocation of HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError) method on Nancy.NancyEngine. This method calls real processing (method NancyContext HandleRequest(Request request) on Nancy.NancyEngine in other thread. I do not think there's a place to intercept second HandleRequest.
2. Method Nancy.NancyEngine.HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError) is directly called from Gate.Adapters.Nancy.NancyAdapter.App(INancyBootstrapper bootstrapper) at line 78.
HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError)
NancyContext HandleRequest(Request request)
Nancy.NancyEngine.HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError)
Maybe correct solution is using method NancyContext HandleRequest(Request request) instead of void HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError) in Gate.Adapters.Nancy.NancyAdapter.App(INancyBootstrapper bootstrapper)?
void HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError)
Also I check Nancy.Hosting.Owin and got the same problem - call for HandleRequest(Request request) is not intercepted and leads to same exception with same stackdump.
AFAIK idea of using Nancy.NancyEngine.HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError) method is to run handling async from listening thread. Maybe there's some good solution for getting proxified NancyEngine in Nancy.NancyEngine.HandleRequest(Request request, Action<NancyContext> onComplete, Action<Exception> onError) that do not direct dependency on Windsor?
I wish I had more time to dig into this, but unfortunately I'm working on two different startups at the moment and will be for at least the next 6 months. I'll admit I built this to satisfy a specific need, but it was also exceptionally difficult. Windsor is a fairly old (though arguably very stable and reliable) container and is arguably very complex compared with some of the modern light-weight alternatives.
That isn't to say one is better or worse, but Nancy's architecture is designed around these modern containers so it is much harder to integrate Windsor seamlessly with Nancy.
Perhaps @grumpydev or @thecodejunkie might have some time to trace this in the next little while.
Thank you for comment. I sent mail to nancy-dev group already. Hope we'll come up with some working solution on this problem.
@asgerhallas since you seem to be comfortable with both Nancy and Windsor, perhaps this would be something you'd be interested in helping us look into? 😄
@thecodejunkie Sure! I it's not too much a hurry, I have my office packed in boxed these days :)
@asgerhallas been open for 3 months.. think we can managed a bit longer =)
Well, I just postponed attempts to use Nancy without HTTP.SYS. But I think I'll return to it someday.
Bon, seems I ran into an old bug with Nancy, Windsor and Owin hosting here....
I've made a small repo and thrown it on StackOverflow: http://stackoverflow.com/questions/17071287/castle-windsor-iinterceptor-in-threadpool-nancy-bug
@Lodewijk-S have you made any progress regarding this issue? My Windsor Foo is not strong enough yet, to transfer the result of the SO discussion to a solution
I have a solution here, but it needs some more testing. I completely changed the way Windsor is used by Nancy.
Thx. I'll give it a try 👍
Since the closing comment on #12 says this is fixed, I'll close this.
I'm letting you guys know that this is still an actual issue.Nancy + Windsor + owin self host + async = scope gets disposed before the request ends, so awaiting after some EF6 queries fails with disposed objectcontext.
I've solved it for our project in a similar fashion by LifestyleScoped() everything that has to be per request and adding it into the context inside a similar wrapper, rather than nearest INancyModule. It seems to work so all good.