tom.dietrich
tom.dietrich

Reputation: 8347

How to host multiple services using one WcfFacility

I'm trying to host multiple services using one WcfFacility and IIS, and I'm seeing some confusing results.

Here is my configuration:

        var baseUri = new Uri(HttpContext.Current.Request.Url.GetComponents(UriComponents.SchemeAndServer, UriFormat.Unescaped));

        container.AddFacility<WcfFacility>(f => { f.CloseTimeout = TimeSpan.Zero; }).Register(
            Component.For<IAttributeService>()                  
                .ImplementedBy<AttributeService>()
                .AsWcfService(
                    new DefaultServiceModel()
                        .Hosted()                           
                        .AddEndpoints(
                            WcfEndpoint.ForContract<IAttributeService>().BoundTo(new BasicHttpBinding()).At("Soap11"),
                            WcfEndpoint.ForContract<IAttributeService>().BoundTo(new WSHttpBinding()).At("Soap12")
                        )
                .AddBaseAddresses(new Uri(baseUri, "AttributeService.svc"))                 
                ),                      
            Component.For<ISessionService>()
                .ImplementedBy<SessionService>()
                .AsWcfService(
                    new DefaultServiceModel()
                        .Hosted()                           
                        .AddEndpoints(
                            WcfEndpoint.ForContract<ISessionService>().BoundTo(new BasicHttpBinding()).At("Soap11"),
                            WcfEndpoint.ForContract<ISessionService>().BoundTo(new WSHttpBinding()).At("Soap12")
                        )
                .AddBaseAddresses(new Uri(baseUri, "SessionService.svc"))
                ),          
            Component.For<ISampleService>()
                .ImplementedBy<SampleService>()
                .AsWcfService(
                    new DefaultServiceModel()
                        .Hosted()
                        .AddEndpoints(
                            WcfEndpoint.ForContract<ISampleService>().BoundTo(new BasicHttpBinding()).At("Soap11"),
                            WcfEndpoint.ForContract<ISampleService>().BoundTo(new WSHttpBinding()).At("Soap12")
                        )
                .AddBaseAddresses(new Uri(baseUri, "SampleService.svc"))
                )
        );

When I go to use the WCF Test client to check on this, it seems as though the methods available under each service are a composite of that service and all the services that I mex'ed before that. Example: looking at a service in WCF Test Client

Am I doing this wrong? You can't add the WcfFacility multiple times, and poking around on the internets, I can't seem to find an example where someone is hosting multiple services in one facility.

Any ideas?

Upvotes: 3

Views: 2217

Answers (1)

tom.dietrich
tom.dietrich

Reputation: 8347

I've figured it out. Previously, I was enabling HttpGet on MetaData using the following code:

var metadata = new ServiceMetadataBehavior { HttpGetEnabled = true };
container.Register(Component.For<IServiceBehavior>().Instance(metadata));

Which was following the code in this github example.

It seems as though this approach causes the WcfFacility to share MetaData for all services on any get request.

The solution was simple. First, remove that stuff. Second, configure each service component in this manner

Component.For<IAttributeService>()                  
.ImplementedBy<AttributeService>()
.AsWcfService(
    new DefaultServiceModel()
        .Hosted()
        .PublishMetadata(x => x.EnableHttpGet())
        .AddBaseAddresses(new Uri(baseUri, "AttributeService.svc"))             
        .AddEndpoints(
            WcfEndpoint.ForContract<IAttributeService>().BoundTo(new BasicHttpBinding()).At("Soap11"),
            WcfEndpoint.ForContract<IAttributeService>().BoundTo(new WSHttpBinding()).At("Soap12")
        )                               
),

Specifically, the trick was to add this code .PublishMetadata(x => x.EnableHttpGet()) in every component.

Now I'm seeing the expected behavior on each service.

The expected behavior! Yay!

Edit: Once I got it working, I went to work removing things that may or may not be required- I love convention over configuration. Here is the result, doesn't seem to be anything else to take away. The nice thing about this is that I can refactor further into a generic registration for all services, rather than needing one registration for each. Just sharing the goods.

        Component.For<IAttributeService>()
            .ImplementedBy<AttributeService>()
            .AsWcfService(
                new DefaultServiceModel()
                    .Hosted()
                    .PublishMetadata(x => x.EnableHttpGet())
                    .AddEndpoints(
                        WcfEndpoint.BoundTo(new BasicHttpBinding()).At("Soap11"),
                        WcfEndpoint.BoundTo(new WSHttpBinding()).At("Soap12")
                    )
        ),

And here's the generic registration.

Classes.FromThisAssembly()
.Where(t => Attribute.IsDefined(t, typeof(StandardServiceAttribute)))
.WithService.Select((t, _) => t.GetInterfaces().Where(i => Attribute.IsDefined(i, typeof(ServiceContractAttribute),false)))
.Configure
(cr => 
    cr.AsWcfService(
        new DefaultServiceModel()
            .Hosted()
            .PublishMetadata(x => x.EnableHttpGet())
            .AddEndpoints(
                WcfEndpoint.BoundTo(new BasicHttpBinding()).At("Soap11"),
                WcfEndpoint.BoundTo(new WSHttpBinding()).At("Soap12")                       
            )
        )
)

Upvotes: 9

Related Questions