简体   繁体   中英

Modify existing WCF communication object

This is how I used to make method calls:

SvcHelper.Using<SomeWebServiceClient>(proxy =>
{
   proxy.SomeMethod();
}

public class SvcHelper
{
   public static void Using<TClient>(Action<TClient> action) where TClient : ICommunicationObject, IDisposable, new()
   {
   }
}

This is how I make method calls:

ChannelFactory<ISomethingWebService> cnFactory = new ChannelFactory<ISomethingWebService>("SomethingWebService");
ISomethingWebService client = cnFactory.CreateChannel();

using (new OperationContextScope((IContextChannel)client))
{
   client.SomeMethod();
}

My question is: Instead of replacing every instance of my original method call approach; Is there a way to modify my SvcHelper and do the creation of the channel in the SvcHelper constructor and then simply pass the interface like the following:

SvcHelper.Using<ISomethingWebService>(client =>
{
   client.SomeMethod();
}

Hope this makes sense and thanks in advance.

This should work:

public class SvcHelper
{
    public static void Using<TClient>(Action<TClient> action) where TClient : ICommunicationObject, IDisposable
    {
        ChannelFactory<TClient> cnFactory = new ChannelFactory<TClient>("SomethingWebService");
        TClient client = cnFactory.CreateChannel();
        using (new OperationContextScope((IContextChannel)client))
        {
            action(client);
        }
    }
}

First, you don't want to create a new ChannelFactory<T> every call to the Using helper method. They are the most costly thing to construct in the WCF universe. So, at bare minimum, you will want to use a caching approach there.

Second, you don't want to tie yourself to "client" types at all anymore. Just work straight with the service contract interfaces.

Starting from what you've got, here's where I'd go based on how I've done this in the past:

public class SvcHelper
{
    private static ConcurrentDictionary<ChannelFactoryCacheKey, ChannelFactory> ChannelFactories = new ConcurrentDictionary<ChannelFactoryCacheKey, ChannelFactory>();

    public static void Using<TServiceContract>(Action<TServiceContract> action) where TServiceContract : class
    {
        SvcHelper.Using<TServiceContract>(action, "*");
    }

    public static void Using<TServiceContract>(Action<TServiceContract> action, string endpointConfigurationName) where TServiceContract : class
    {
        ChannelFactoryCacheKey cacheKey = new ChannelFactoryCacheKey(typeof(TServiceContract), endpointConfigurationName);

        ChannelFactory<TServiceContract> channelFactory = (ChannelFactory<TServiceContract>)SvcHelper.ChannelFactories.GetOrAdd(
                                                                                                                                cacheKey,
                                                                                                                                missingCacheKey => new ChannelFactory<TServiceContract>(missingCacheKey.EndpointConfigurationName));

        TServiceContract typedChannel = channelFactory.CreateChannel();
        IClientChannel clientChannel = (IClientChannel)typedChannel;

        try
        {
            using(new OperationContextScope((IContextChannel)typedChannel))
            {
                action(typedChannel);
            }
        }
        finally
        {
            try
            {
                clientChannel.Close();
            }
            catch
            {
                clientChannel.Abort();
            }
        }

    }

    private sealed class ChannelFactoryCacheKey : IEquatable<ChannelFactoryCacheKey>
    {
        public ChannelFactoryCacheKey(Type channelType, string endpointConfigurationName)
        {
            this.channelType = channelType;
            this.endpointConfigurationName = endpointConfigurationName;
        }

        private Type channelType;

        public Type ChannelType
        {
            get
            {
                return this.channelType;
            }
        }

        private string endpointConfigurationName;

        public string EndpointConfigurationName
        {
            get
            {
                return this.endpointConfigurationName;
            }
        }

        public bool Equals(ChannelFactoryCacheKey compareTo)
        {
            return object.ReferenceEquals(this, compareTo)
                       ||
                   (compareTo != null
                       &&
                   this.channelType == compareTo.channelType
                       &&
                   this.endpointConfigurationName == compareTo.endpointConfigurationName);
        }

        public override bool Equals(object compareTo)
        {
            return this.Equals(compareTo as ChannelFactoryCacheKey);
        }

        public override int GetHashCode()
        {
            return this.channelType.GetHashCode() ^ this.endpointConfigurationName.GetHashCode();
        }
    }
} 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM