1
votes

I'm hosting a duplex wcf service using windows service with castle windsor wcffacility using TCP binding.

There is no problem with hosting, I think, when I add a service reference to a console application.I'm able to access the duplex service without any issues.

Problem arises when I use castle windsor at the client side while resolving. Below is the code am using for adding the wcf services through code based on config file.

public static IWindsorContainer RegisterWcfClients(IocBuildSettings iocBuildSettings,
        IWindsorContainer container)
    {

        //Register callback methods for duplex service first.

        container.Register(Component.For<INotificationCallback>()
            .ImplementedBy<NotificationCallbackCastle>()
            .LifestyleTransient());



        // get dictionary with key = service class, value = service interface
        var servicesWithWcfInterfaces = Assembly.GetAssembly(typeof (IApplicationService))
            .GetTypes()
            .Where(x => (x.IsInterface || x.IsClass) && HasServiceContract(x))
            .ToList();
        var registrations = new List<IRegistration>();

        //get the client section in System.ServiceModel from web.config file
        var clientSection = ConfigurationManager.GetSection("system.serviceModel/client") as ClientSection;
        //get the endpointsCollection from childSection
        var endpointCollection =
            clientSection.ElementInformation.Properties[string.Empty].Value as ChannelEndpointElementCollection;



        foreach (var serviceInterface in servicesWithWcfInterfaces)
        {
            //get the childEndpoint name from web.config file
            var endpointName = GetClientEndpointName(endpointCollection, serviceInterface);

            //register services which are declared in web.config file only.
            if (string.IsNullOrEmpty(endpointName)) continue;

            // attribute is either on the service class or the interface
            var attribute =
                (ServiceContractAttribute)
                    (Attribute.GetCustomAttribute(serviceInterface, typeof (ServiceContractAttribute)));
            if (attribute != null)
            {
                WcfClientModelBase model = null;
                // handle duplex differently
                if (attribute.CallbackContract != null)
                {
                    model = new DuplexClientModel
                    {
                        Endpoint =
                            WcfEndpoint.ForContract(serviceInterface).FromConfiguration(endpointName)
                    }.Callback(container.Resolve(attribute.CallbackContract));
                    registrations.Add(WcfClient.ForChannels(model).Configure(c => c.LifestyleSingleton()));
                }
                else
                {
                    //regular attributes
                    model = new DefaultClientModel
                    {
                        Endpoint = WcfEndpoint.ForContract(serviceInterface).FromConfiguration(endpointName)
                    };
                    registrations.Add(WcfClient.ForChannels(model).Configure(c => c.LifestyleTransient()));
                }
            }
        } 
        return container.Register(registrations.ToArray());

    }

Am hosting only one duplex service and the below are the servicecontracts -

 [ServiceContract(CallbackContract = typeof(INotificationCallback))]
public interface INotificationService
{
    [OperationContract(IsOneWay = false)]
    void Subscribe(Guid subscriptionId, string userName, string[] eventNames);
    [OperationContract(IsOneWay = true)]
    void EndSubscribe(Guid subscriptionId);
}

[ServiceContract]
public interface INotificationCallback
{
    [OperationContract(IsOneWay = true)]
    void ReceiveNotification(NotificationResultDto notificationResult);
}

[DataContract]
public class NotificationResultDto
{
    [DataMember]
    public string UserName { get; set; }
    [DataMember]
    public string NotificationMessage { get; set; }
}

When I try to resolve the duplex service using the below statement. var temp = _container.Resolve();

I get error -

WcfClientActivator: could not proxy component c2a216c2-af61-4cb2-83ba-e4d9a5cc4e68 with inner exception - The Address property on ChannelFactory.Endpoint was null. The ChannelFactory's Endpoint must have a valid Address specified.

in the web.config file under client section -

<endpoint address="net.tcp://localhost:9877/NotificationService" binding="netTcpBinding"
    bindingConfiguration="netTcpBindingConfiguration" contract="ServiceContracts.INotificationService"
    name="INotificationService_Endpoint" />
1

1 Answers

1
votes

After few hours of struggling, I found a work around for this problem. I think this could a bug in Castle Windsor, while creating DuplexClientModel, endpoint cannot be created using "FromConfiguration". It fails while resolving during runtime. However samething works fine with "DefaultClientModel".

My workaround was to read the config file and get the address, binding and contract details and use them to create Endpoint in code.

model = new DuplexClientModel
                    {
                        //Endpoint = WcfEndpoint.ForContract(serviceInterface).FromConfiguration(endpointName)
                        //FromConfiguration method is failing for some reason,could be b.u.g in castle, 
                        //so had to do this workaround by reading the web.config file and creating the Endpoint 
                        //from there manually.
                        Endpoint = WcfEndpoint.ForContract(serviceInterface)
                                    .BoundTo(CreateBindings(clientEndpoint.Binding))
                                    .At(clientEndpoint.Address)

                    }.Callback(container.Resolve(attribute.CallbackContract));