openrasta / openrasta-castle-windsor

Integrates Castle Windsor with OpenRasta.
1 stars 6 forks source link

Using Castle Windsor with HttpListenerHost #6

Open scottlittlewood opened 10 years ago

scottlittlewood commented 10 years ago

I've been attempting to host an OpenRasta based project using a HttpListenerHost while also using Castle Windsor as the container.

Unfortunately I've come across an issue where Windsor is not able to resolve the IOperationFilters registered with the container as the Handler.Current State in AvailableHandlers() are seen as WaitingDependency

IEnumerable<IHandler> AvailableHandlers(IEnumerable<IHandler> handlers)
{
    return from handler in handlers
            where handler.CurrentState == HandlerState.Valid
                    && IsAvailable(handler.ComponentModel)
            select handler;
}

This is causing a (405) MethodNotAllowed response being returned to any and all requests coming in to the system.

Debugging the Windsor Container seems to indicate that it is unable to resolve IRequest because it can't resolve ICommunicationContext which in turn can't resolve System.Net.HttpListenerContext (nativeContext). I'm not too familiar with the registration of components in Windsor / OpenRasta and wondered if anyone with more insight could help.

This only happens when attempting to use Castle Windsor as the InternalDependencyResolver in OpenRasta works fine.

I've confirmed this with the test below.

public class TestHttpListenerHostWithConfig : HttpListenerHost
    {
        private readonly IConfigurationSource _source;
        public IDependencyResolver Resolver { get; private set; }

        public TestHttpListenerHostWithConfig(IConfigurationSource source)
        {
            if(source == null)
                throw new ArgumentNullException("source");

            _source = source;
        }

        public override bool ConfigureRootDependencies(IDependencyResolver resolver)
        {
            var configured = base.ConfigureRootDependencies(resolver);
            if (configured && _source != null)
            {
                resolver.AddDependencyInstance<IConfigurationSource>(_source);
            }
            Resolver = resolver;
            return configured;
        }
    }

    class TestConfigurationSource : IConfigurationSource
    {
        public void Configure()
        {
            using (OpenRastaConfiguration.Manual)
            {
                ResourceSpace.Has.ResourcesOfType<string>()
                    .AtUri("/")
                    .HandledBy<TestHandler>()
                    .TranscodedBy<TextPlainCodec>();
            }
        }
    }

    public class TestHandler
    {
        public string Get()
        {
            return "Test Response";
        }
    }

    public class WindsorDependencyResolverAccessor : IDependencyResolverAccessor
    {
        private static IWindsorContainer _container;

        public IDependencyResolver Resolver { get; private set; }

        public WindsorDependencyResolverAccessor()
        {
            Resolver = new WindsorDependencyResolver(_container);
        }

        public static void SetupWith(IWindsorContainer container)
        {
            if (container == null)
                throw new ArgumentNullException("container");

            if (_container == null)
                _container = container;
        }
    }

    public class when_creating_a_new_HttpListenerHost_with_WindsorResolver : context
    {
        TestHttpListenerHostWithConfig _host;
        private const string Prefix = "http://localhost:18981/";
        private IWindsorContainer _container;

        protected override void SetUp()
        {
            // init container
            _container = new WindsorContainer();

            _container.Register(
                Component.For<IConfigurationSource>()
                .ImplementedBy<TestConfigurationSource>()
                .LifestyleSingleton());

            _container.Register(
                Component.For<TestHttpListenerHostWithConfig>()
                .ImplementedBy<TestHttpListenerHostWithConfig>()
                .LifestyleSingleton());

            // Statically set the container for the resolver accessor type as it is created by 
            // Activator.CreateInstance(Type type) in HttpListenerHost.Initialize(...)
            WindsorDependencyResolverAccessor.SetupWith(_container);

            var resolverFactoryType = typeof(WindsorDependencyResolverAccessor);

            _host = _container.Resolve<TestHttpListenerHostWithConfig>();
            _host.Initialize(new[] { Prefix }, "/", resolverFactoryType);
            _host.StartListening();
        }

        protected override void TearDown()
        {
            _host.StopListening();
            _host.Close();
        }

        [Test]
        public void the_resolver_is_a_windsor_dependency_resolver()
        {
            Assert.That(_host.Resolver, Is.Not.Null);
            Assert.That(_host.Resolver, Is.InstanceOf<WindsorDependencyResolver>());
        }

        [Test]
        public void the_root_uri_serves_the_test_string()
        {
            var response = new WebClient().DownloadString(Prefix);
            Assert.That(response, Is.EqualTo("Test Response"));
        }
    }

Here is the debug log:

5-[2014-10-30 11:50:24Z] Information(0) Registering host of type OpenTopWind.Tests.TestHttpListenerHostWithConfig
5-[2014-10-30 11:50:24Z] Verbose(0) Using dependency resolver of type OpenRasta.DI.Windsor.WindsorDependencyResolver
5-[2014-10-30 11:50:24Z] Verbose(0) Registering host's root dependencies.
5-[2014-10-30 11:50:24Z] Information(0) Using dependency registrar of type OpenRasta.Configuration.DefaultDependencyRegistrar.
5-[2014-10-30 11:50:24Z] Verbose(0) Registering host's leaf dependencies.
5-[2014-10-30 11:50:24Z] Verbose(0) Using configuration source OpenTopWind.Tests.TestConfigurationSource
5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing the pipeline.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor ResponseEntityCodecResolverContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor ResponseEntityWriterContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor BootstrapperContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor HttpMethodOverriderContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor UriDecoratorsContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor ResourceTypeResolverContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor HandlerResolverContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationCreatorContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationFilterContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationHydratorContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationCodecSelectorContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationInvokerContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationResultInvokerContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor OperationInterceptorContributor.
    5-[2014-10-30 11:50:25Z] Verbose(0) Initialized contributor EndContributor.
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor ResponseEntityCodecResolverContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor ResponseEntityWriterContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor HttpMethodOverriderContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor UriDecoratorsContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor ResourceTypeResolverContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor HandlerResolverContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationCreatorContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationFilterContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationHydratorContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationCodecSelectorContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationInvokerContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationResultInvokerContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor OperationInterceptorContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Start(1) Entering PipelineRunner: Initializing contributor EndContributor.
    5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
    5-[2014-10-30 11:50:25Z] Information(0) Contributor call chain has been processed and results in the following pipeline:
    5-[2014-10-30 11:50:25Z] Information(0) 0 BootstrapperContributor
    5-[2014-10-30 11:50:25Z] Information(0) 1 HttpMethodOverriderContributor
    5-[2014-10-30 11:50:25Z] Information(0) 2 UriDecoratorsContributor
    5-[2014-10-30 11:50:25Z] Information(0) 3 ResourceTypeResolverContributor
    5-[2014-10-30 11:50:25Z] Information(0) 4 HandlerResolverContributor
    5-[2014-10-30 11:50:25Z] Information(0) 5 OperationCreatorContributor
    5-[2014-10-30 11:50:25Z] Information(0) 6 OperationFilterContributor
    5-[2014-10-30 11:50:25Z] Information(0) 7 OperationCodecSelectorContributor
    5-[2014-10-30 11:50:25Z] Information(0) 8 OperationHydratorContributor
    5-[2014-10-30 11:50:25Z] Information(0) 9 OperationInterceptorContributor
    5-[2014-10-30 11:50:25Z] Information(0) 10 OperationInvokerContributor
    5-[2014-10-30 11:50:25Z] Information(0) 11 OperationResultInvokerContributor
    5-[2014-10-30 11:50:25Z] Information(0) 12 ResponseEntityCodecResolverContributor
    5-[2014-10-30 11:50:25Z] Information(0) 13 ResponseEntityWriterContributor
    5-[2014-10-30 11:50:25Z] Information(0) 14 EndContributor
5-[2014-10-30 11:50:25Z] Stop(1) Exiting PipelineRunner
5-[2014-10-30 11:50:25Z] Information(0) Pipeline has been successfully initialized.
9-[2014-10-30 11:50:25Z] Verbose(0) Incoming host request for http://localhost:18981/
9-[2014-10-30 11:50:25Z] Verbose(0) Adding communication context data
'JetBrains.ReSharper.TaskRunner.CLR4.x64.exe' (Managed (v4.0.30319)): Loaded 'C:\Windows\assembly\GAC_MSIL\Microsoft.VisualStudio.Debugger.Runtime\10.0.0.0__b03f5f7f11d50a3a\Microsoft.VisualStudio.Debugger.Runtime.dll'
9-[2014-10-30 11:50:29Z] Warning(0) Contributor call for BootstrapperContributor had a null Action.
9-[2014-10-30 11:50:29Z] Start(1) Entering PipelineRunner: Executing contributor HttpMethodOverriderContributor.OverrideHttpVerb
9-[2014-10-30 11:50:29Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:29Z] Start(1) Entering PipelineRunner: Executing contributor UriDecoratorsContributor.ProcessDecorators
9-[2014-10-30 11:50:29Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:29Z] Start(1) Entering PipelineRunner: Executing contributor ResourceTypeResolverContributor.ResolveResource
9-[2014-10-30 11:50:29Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:29Z] Start(1) Entering PipelineRunner: Executing contributor HandlerResolverContributor.ResolveHandler
9-[2014-10-30 11:50:29Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:29Z] Start(1) Entering PipelineRunner: Executing contributor OperationCreatorContributor.CreateOperations
    9-[2014-10-30 11:50:32Z] Verbose(0) Created operation named Get with signature TestHandler::Get()
9-[2014-10-30 11:50:32Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:32Z] Start(1) Entering PipelineRunner: Executing contributor OperationFilterContributor.ProcessOperations
9-[2014-10-30 11:50:35Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:35Z] Verbose(0) Pipeline is in RenderNow mode.
9-[2014-10-30 11:50:35Z] Start(1) Entering PipelineRunner: Executing contributor OperationResultInvokerContributor.RunOperationResult
    9-[2014-10-30 11:50:35Z] Information(0) Executing OperationResult OperationResult: type=MethodNotAllowed, statusCode=405.
9-[2014-10-30 11:50:35Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:35Z] Start(1) Entering PipelineRunner: Executing contributor ResponseEntityCodecResolverContributor.FindResponseCodec
    9-[2014-10-30 11:50:35Z] Information(0) No response codec was searched for. The response entity is null or a response codec is already set.
9-[2014-10-30 11:50:35Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:35Z] Start(1) Entering PipelineRunner: Executing contributor ResponseEntityWriterContributor.WriteResponse
    9-[2014-10-30 11:50:35Z] Verbose(0) There was no response entity, not rendering.
    9-[2014-10-30 11:50:35Z] Verbose(0) Writing http headers.
9-[2014-10-30 11:50:35Z] Stop(1) Exiting PipelineRunner
9-[2014-10-30 11:50:35Z] Information(0) Pipeline finished.
9-[2014-10-30 11:50:35Z] Verbose(0) Request finished.

The error originates from the following call OpenRasta.Pipeline.Contributors.AbstractOperationProcessing.GetMethods() This calls in to the WindosrDependencyResolver.ResolveAllCore where T : IOperationFilter The (3) default handlers are returned from the Windsor Kernel but as stated previously the Windsor IHandler instances are WaitingDependency

The container itself seems to indicate there are a few potential misconfigured components (13) I can see that the ICommunicationContext, IRequest and IResponse instances are registered PerRequest in HostManager.SetupCommunicationContext(context).

While debugging in WindsorDependencyResolver.AvailableHandlers() and executing the following in the immediate window the following error is shown

_windsorContainer.Resolve<OpenRasta.Web.ICommunicationContext>();

screenshot_30-10-2014 12 12 43

holytshirt commented 10 years ago

Hi @scottlittlewood

It seems we hit the same problem, with the newer versions of windsor and how session scope works

Could you try adding this code and seeing if it helps you

_container.Register(
Component.For<HttpContext>().UsingFactoryMethod(() => (HttpContext)null),
Component.For<AspNetRequest>().UsingFactoryMethod(() => (AspNetRequest)null),
Component.For<AspNetResponse>().UsingFactoryMethod(() => (AspNetResponse)null)
);

If it works for you, I'll have to see how we can fix the issue or document the work around. Toby

serialseb commented 10 years ago

This stuff is nasty. we need to make this much much much better me thinks.

scottlittlewood commented 10 years ago

Hi @holytshirt

I tried the code you provided but that looks like AspNetHost, I'm specifically looking at HttpListenerHost.

After some trial and error and looking at the status "Potential Misconfigured Components" in the container.

The following code seems to resolve the Http Hosting / Windsor Container issue for now. I tested adding the HttpResponse but that doesn;t seem to be needed to make the above test pass.

Thanks for the suggestion. Not sure what the correct solution would be for this integration to be less painful.

_container.Register(
    Component.For<System.Net.HttpListenerContext>().UsingFactoryMethod(() => (System.Net.HttpListenerContext)null),
    Component.For<OpenRasta.Hosting.HttpListener.HttpListenerCommunicationContext>().UsingFactoryMethod(() => (OpenRasta.Hosting.HttpListener.HttpListenerCommunicationContext)null),
    Component.For<System.Net.HttpListenerRequest>().UsingFactoryMethod(() => (System.Net.HttpListenerRequest)null),
);
serialseb commented 10 years ago

We need a plan to can the iOC integration out of OR. I'll give it a go this weekend if time allows.

Sebastian Lambla - http://serialseb.com

On 31 Oct 2014, at 11:16, Scott Littlewood notifications@github.com<mailto:notifications@github.com> wrote:

Hi @holytshirthttps://github.com/holytshirt

I tried the code you provided but that looks like AspNetHost, I'm specifically looking at HttpListenerHost.

After some trial and error and looking at the status "Potential Misconfigured Components" in the container.

The following code seems to resolve the Http Hosting / Windsor Container issue for now. I tested adding the HttpResponse but that doesn;t seem to be needed to make the above test pass.

Thanks for the suggestion. Not sure what the correct solution would be for this integration to be less painful.

_container.Register( Component.For().UsingFactoryMethod(() => (System.Net.HttpListenerContext)null), Component.For().UsingFactoryMethod(() => (OpenRasta.Hosting.HttpListener.HttpListenerCommunicationContext)null), Component.For().UsingFactoryMethod(() => (System.Net.HttpListenerRequest)null), );

Reply to this email directly or view it on GitHubhttps://github.com/openrasta/openrasta-castle-windsor/issues/6#issuecomment-61246908.

holytshirt commented 10 years ago

@scottlittlewood I have had a stab at doing the integration with the new way of doing custom scopes in castle windsor. Just need to find the time to finish it, as I ran into some issues.

I'll document mine and your workarounds in the readme for the moment.

Toby

nmosafi commented 9 years ago

I added @scottlittlewood 's test and one of my own, which currently fails. See this pull request

https://github.com/openrasta/openrasta-castle-windsor/pull/7