【问题标题】:Correct WCF service handling using a factory and service proxies in C#在 C# 中使用工厂和服务代理正确处理 WCF 服务
【发布时间】:2016-02-03 09:01:46
【问题描述】:

我的程序中有一部分会在发生某些事情时向我发送电子邮件和/或推送消息到我的 iPhone。这是通过使用 MSMQ 调用两个单独的 WCF 服务来完成的。我遵循 this 指南(模型 4.0)以使其具有通用性和测试友好性。我喜欢通用通道创建,但我的问题是代理和通道工厂是否真的关闭/正确处理,或者当它达到 10000 个用户环境时它是否会爆炸(最终会)。该代码在我的 50 个用户测试环境中完美运行。

因此,请查看以下代码:

服务代理

public class ServiceProxy<TChannel> : IServiceProxy<TChannel> where TChannel : ICommunicationObject
{
    private readonly TChannel InnerChannel;

    public ServiceProxy(TChannel innerChannel)
    {
        this.InnerChannel = innerChannel;
    }

    public void Execute(Action<TChannel> operation)
    {
        try
        {
            operation(InnerChannel);
            InnerChannel.Close();
        }
        catch (CommunicationException)
        {
            InnerChannel.Abort();
        }
        catch (TimeoutException)
        {
            InnerChannel.Abort();
        }
        catch (Exception)
        {
            InnerChannel.Abort();
            throw;
        }
    }

    public TResult Execute<TResult>(Func<TChannel, TResult> operation)
    {
        TResult result = default(TResult);

        try
        {
            result = operation(InnerChannel);
            InnerChannel.Close();
        }
        catch (CommunicationException)
        {
            InnerChannel.Abort();
        }
        catch (TimeoutException)
        {
            InnerChannel.Abort();
        }
        catch (Exception)
        {
            InnerChannel.Abort();
            throw;
        }

        return result;
    }
}

服务代理工厂

public class ServiceProxyFactory : IServiceProxyFactory
{
    public IServiceProxy<TChannel> GetProxy<TChannel>(string endpointName) where TChannel : ICommunicationObject
    {
        var factory = new ChannelFactory<TChannel>(endpointName);
        return new ServiceProxy<TChannel>(factory.CreateChannel());
    }
}

进行服务调用(为简单起见,没有返回类型)

public class MessageSender : IMessageSender
{
    private const string PushServiceEndpoint = "PushEndpointName";
    private const string MailServiceEndpoint = "MailEndpointName";

    private readonly IServiceProxyFactory ServiceProxyFactory;

    public MessageSender()
    {
        ServiceProxyFactory = new ServiceProxyFactory();
    }

    public void NotifyMe(*some args*)
    {
        ServiceProxyFactory.GetProxy<MailServiceChannel>(MailServiceEndpoint)
                     .Execute(a => a.SendEmail(*some args*));
    }

问题是:

是否应该在执行后关闭 ServiceProxy?

每次调用 GetProxy() 时都创建一个 ChannelFactory 是否明智,如果是,是否应该再次关闭此 ChannelFactory?

为每次调用生成一个 ServiceProxy 真的对性能友好吗? (这对我来说似乎很沉重,但也许有人可以证明我错了)。

我在这篇文章中省略了接口,但它们确实很简单,并且带有代理和接口的整个设置非常适合单元和集成测试。

我希望你们中的一些编码向导对此有意见,并会分享这一点。

提前致谢!

【问题讨论】:

    标签: c# performance wcf msmq service-factory


    【解决方案1】:

    主要的性能影响是创建ChannelFactory

    创建 ChannelFactory 实例会产生一些开销,因为它涉及以下操作: 构造 ContractDescription 树

    Reflecting all of the required CLR types
    
    Constructing the channel stack
    
    Disposing of resources
    

    https://msdn.microsoft.com/en-us/library/hh314046%28v=vs.110%29.aspx

    WCF 团队已经为ClientBase&lt;TChannel&gt; 类实现了缓存,当你有自动生成的代理类时它是合适的。 当您使用纯 ChannelFactory 时,您必须小心在每次调用时创建工厂,以获得更好的性能。

    一个好的解决方案是自己实现ChannelFactory&lt;TChannel&gt; 的缓存(有a good idea 说明如何做到这一点)。所以最后在你的ServiceProxyFactory 中而不是new ChannelFactory&lt;TChannel&gt;(endpointName); 你应该使用像CachedChannelFactory&lt;TChannel&gt;.GetInstance() 这样的缓存实例。

    编辑: Michele Leroux Bustamante 写了另一篇好文章,解释了To Cache or Not to Cache

    【讨论】:

    • 感谢您的意见。您指向“一个好主意”的链接非常有趣。但是有一个问题:如果创建通道工厂是一项昂贵的操作,为什么不通过构造函数注入将通道工厂传递给代理,然后为每个服务都有一个服务代理?这样服务代理可以创建通道,做一些事情并关闭通道......这样你将为每个 ServiceProxy 拥有一个通道工厂,它只创建一次。
    • 我认为,您的解决方案也是一个可行的选择,只需确保您控制实例的生命周期。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多