3

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?

tom.dietrich
  • 8,219
  • 2
  • 39
  • 56
  • I don't understand what you mean by "the methods available under each service are a composite of that service and all the services that I mex'ed before that". What I see from the test client is three different service contracts each exposing two endpoints on different bindings (basicHttp & wsHttp). This is exactly what you've configured in the WcfFacility. Why do you expect something different? – Sixto Saez Mar 16 '12 at 15:21
  • I've got three different services with two different endpoints each. I expect to see two endpoints under any given service. – tom.dietrich Mar 16 '12 at 15:24
  • Hi @tom.dietrich, I am trying to set up a similar thing, but with a generic service. Did you have to include the .svc file to be able to publish metadata? I cannot seem to get that working, but can if I create a service channel via the ChannelFactory? – TimC Aug 01 '12 at 06:01
  • If you're using castle.windsor's wcf facility, the inclusion of the argument 'Hosted' tells it that there is a svc file out there. So make sure you're not using that. – tom.dietrich Aug 01 '12 at 11:41

1 Answers1

9

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")                       
            )
        )
)
tom.dietrich
  • 8,219
  • 2
  • 39
  • 56
  • 1
    To quote the fabio: Castle.Windsor is too sexy by far! – tom.dietrich Mar 16 '12 at 18:01
  • What does the At("Soap11") mean? – Konstantin May 26 '15 at 11:00
  • Figured it out. (it is the address the endpoint will be available from baseuri+"/AttributeService.svc"+"/Soap11" in pseudo code) – Konstantin May 26 '15 at 11:19
  • Where did the svc url registration go? Are you keeping those in web.config or is there some convention built in to WCF Facility? – Konstantin May 26 '15 at 11:21
  • It's been like 3 years, but if I remember correctly, the `.Hosted()` method tells the WCF Facility that there is an existing .svc file to use as the url base point, so adding the basepoint was not actually required. – tom.dietrich May 26 '15 at 11:50