Search code examples
wcfdependency-injectioncastle-windsorioc-containercastle

Register WCF Service components in Castle Windsor


I haven't found anyone else with this issue so I'm assuming it is my own fault that this is happening. I very green when it comes to WCF and Castle Windsor IoC container so that would probably be the first reason why this is happening. Anyways, I have been struggling with this for several days and haven't found the reason for this yet.

First, I registered my services using Castle Windsor.

var baseUri = new Uri("http://localhost:49246");

_container = new WindsorContainer();

var returnFaults = new ServiceDebugBehavior
{
    IncludeExceptionDetailInFaults = true,
    HttpHelpPageEnabled = true
};
var metadata = new ServiceMetadataBehavior { HttpGetEnabled = true };

_container.Register(
    Component.For<IServiceBehavior>().Instance(returnFaults),
    Component.For<IServiceBehavior>().Instance(metadata));

var baseUri = new Uri("http://localhost:49246");

_container = new WindsorContainer();

var returnFaults = new ServiceDebugBehavior
{
    IncludeExceptionDetailInFaults = true,
    HttpHelpPageEnabled = true
};
var metadata = new ServiceMetadataBehavior { HttpGetEnabled = true };

_container.Register(
    Component.For<IServiceBehavior>().Instance(returnFaults),
    Component.For<IServiceBehavior>().Instance(metadata));

_container
    .Register(
        Component
            .For<IAccountDataAccessor>()
                .ImplementedBy<AccountDataAccessor>(),
        Component
            .For<IInstitutionDataAccessor>()
                .ImplementedBy<InstitutionDataAccessor>(),
        Component
            .For<IRelationshipDataAccessor>()
                .ImplementedBy<RelationshipDataAccessor>(),
        Component
            .For<ITransactionDataAccessor>()
                .ImplementedBy<TransactionDataAccessor>()

    );

_container.AddFacility<WcfFacility>(f => { f.CloseTimeout = TimeSpan.Zero; });
_container.Register(
    Component
        .For<IAccountDataService>()
        .ImplementedBy<AccountDataService>()
        .Named("AccountDataService")
        .LifeStyle.Is(Castle.Core.LifestyleType.Singleton)
        .AsWcfService(new DefaultServiceModel()
            .AddBaseAddresses(baseUri)
            .AddEndpoints(WcfEndpoint
                .ForContract(typeof(IAccountDataService))
                .BoundTo(new WSHttpBinding()))),
    Component
        .For<IInstitutionDataService>()
        .ImplementedBy<InstitutionDataService>()
        .Named("InstitutionDataService")
        .LifeStyle.Is(Castle.Core.LifestyleType.Singleton)
        .AsWcfService(new DefaultServiceModel()
            .AddBaseAddresses(baseUri)    
            .AddEndpoints(WcfEndpoint
                .ForContract(typeof(IInstitutionDataService))
                .BoundTo(new WSHttpBinding()))),
    Component
        .For<IRelationshipDataService>()
        .ImplementedBy<RelationshipDataService>()
        .Named("RelationshipDataService")
        .LifeStyle.Is(Castle.Core.LifestyleType.Singleton)
        .AsWcfService(new DefaultServiceModel()
            .AddBaseAddresses(baseUri)
            .AddEndpoints(WcfEndpoint
                .ForContract(typeof(IRelationshipDataService))
                .BoundTo(new WSHttpBinding()))),
    Component
        .For<ITransactionDataService>()
        .ImplementedBy<TransactionDataService>()
        .Named("TransactionDataService")
        .LifeStyle.Is(Castle.Core.LifestyleType.Singleton)
        .AsWcfService(new DefaultServiceModel()
            .AddBaseAddresses(baseUri)    
            .AddEndpoints(WcfEndpoint
                .ForContract(typeof(ITransactionDataService))
                .BoundTo(new WSHttpBinding()))));

Now when I try and get a service reference for AccountDataService, it works fine, no errors. But when I try and add a service reference to InstitutionDataService it throws an exception saying:

    Could not find a component with name InstitutionDataService, did you forget to register it?

This has been quite frustrating and I can't seem to find a straight answer in the Castle Windsor docs (or lack there of). And I have attempted to implement the solution suggested in this SO question:

SO Question

But this also did not work. None of the components appeared to be registered. Also, if it helps, this is my svc markup:

    <%@ ServiceHost Language="C#" Debug="true" Service="AccountDataService"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration" %>

And it is the same for all services.

So, my question is, why aren't my components being registered along with the AccountDataService?


Solution

  • Here's how I got this to work self hosted using an app.config file. I did it this way because this is what I am familiar with. If you want, I can modify it to be configured through code instead of through the app.config file...

    using System;
    using System.ServiceModel;
    using Castle.Facilities.WcfIntegration;
    using Castle.MicroKernel.Registration;
    using Castle.Windsor;
    
    namespace DISandbox
    {
        public class Program
        {
            private static WindsorContainer _container;
    
            public static void Main(string[] args)
            {
                _container = new WindsorContainer();
                _container.AddFacility<WcfFacility>();
    
                _container.Register(
                    Component
                        .For<IAccountDataService>()
                        .ImplementedBy<AccountDataService>()
                        .AsWcfService(),
                    Component
                        .For<IInstitutionDataService>()
                        .ImplementedBy<InstitutionDataService>()
                        .AsWcfService());
    
                Console.WriteLine("Press any key to exit...");
                Console.ReadLine();
            }
        }
    
        [ServiceContract]
        public interface IAccountDataService
        {
            [OperationContract]
            void DoStuff();
        }
    
        public class AccountDataService : IAccountDataService
        {
            public void DoStuff() { }
        }
    
        [ServiceContract]
        public interface IInstitutionDataService
        {
            [OperationContract]
            void DoStuff();
        }
    
        public class InstitutionDataService : IInstitutionDataService
        {
            public void DoStuff() { }
        }
    }
    

    And the config file...

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    
      <system.serviceModel>
        <behaviors>
          <serviceBehaviors>
            <behavior name="MyHttpServiceBehavior">
              <serviceMetadata httpGetEnabled="True" />
              <serviceDebug includeExceptionDetailInFaults="True" httpHelpPageEnabled="True"/>
            </behavior>
          </serviceBehaviors>
        </behaviors>
    
        <services>
          <service name="DISandbox.AccountDataService" behaviorConfiguration="MyHttpServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:49246/AccountDataService"/>
              </baseAddresses>
            </host>
            <endpoint binding="basicHttpBinding" contract="DISandbox.IAccountDataService" />
          </service>
    
          <service name="DISandbox.InstitutionDataService" behaviorConfiguration="MyHttpServiceBehavior">
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:49246/InstitutionDataService"/>
              </baseAddresses>
            </host>
            <endpoint binding="basicHttpBinding" contract="DISandbox.IInstitutionDataService" />
          </service>
        </services>
      </system.serviceModel>
    
    </configuration>