【问题标题】:Modify existing WCF communication object修改现有的 WCF 通信对象
【发布时间】:2012-03-29 05:50:35
【问题描述】:

这就是我以前进行方法调用的方式:

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

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

这就是我进行方法调用的方式:

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

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

我的问题是:而不是替换我原来的方法调用方法的每个实例;有没有办法修改我的SvcHelper 并在SvcHelper 构造函数中创建通道,然后简单地传递如下接口:

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

希望这是有道理的,并在此先感谢。

【问题讨论】:

    标签: c# asp.net wcf entity-framework


    【解决方案1】:

    首先,您不想在每次调用 Using 辅助方法时都创建一个新的 ChannelFactory&lt;T&gt;。它们是 WCF 世界中构建成本最高的东西。因此,至少,您需要在此处使用缓存方法。

    其次,您根本不想再将自己束缚于“客户”类型。直接使用服务契约接口即可。

    从你所拥有的开始,根据我过去的做法,这就是我要去的地方:

    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();
            }
        }
    } 
    

    【讨论】:

    • 嗯不知道为什么你必须删除它......除非你已经使方法非静态?在粘贴之前,我正在编译该示例代码。为了清楚起见,我更喜欢带前缀的方法调用,所以我总是用这个作为前缀。或类名。在静态调用的情况下。
    • 我还需要实现缓存以及此方法吗?
    • 嗯,我已经按通道类型缓存了 ChannelFactory 实例,但我忘记了我们实际上需要按类型+端点配置名称缓存才能成为完整的实现。我将更新实现以完成。
    • 也不应该public int GetHashCode()public override int GetHashCode()
    • 我只是使用 StackOverflow 来编译,所以你得原谅我的小东西。 ;P 那就是说你实际上不想改变 cacheKey 的东西,你只是想使用一个不同的变量名。如果您将其更改为您所做的,您实际上每次都会实例化 ChannelFactory。我会更新示例。
    【解决方案2】:

    这应该可行:

    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);
            }
        }
    }
    

    【讨论】:

    • 问题是传递给泛型ChannelFactory类的类型参数必须是接口类型。它说没有从接口到ICommunicationObject的转换。
    • 也许删除“where TClient:ICommunicationObject, IDisposable”是有意义的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 2019-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 1970-01-01
    相关资源
    最近更新 更多