如何为Wcf合同替代使用接口

时间:2011-08-16 21:42:47

标签: wcf inversion-of-control ninject

假设我有3个程序集,Example.Core,Example.Contracts,Example.WcfServices。在我的契约汇编中,我定义了一个接口并添加了一些操作,例如ICalculator,具有操作Add(双a,双b)。在我的WcfServices程序集中,我将ICalculator实现为Wcf服务。

现在我的问题是这个....在我的Example.Core程序集中如何对该接口进行编程,同时保持所有内容解耦(允许我有一个替代的接口实现)。如果我有一个需要ICalculator的类,我可以创建一个来自ChannelFactory并使用它,或者我可以在构造函数中注入一个实例。如果我在课堂上创建一个,那么我在ChannelFactory / Wcf中将依赖项放在我的班级中,我真的不想这样做。如果我在构造函数中注入一个实例,那么注入类将如何管理和整理wcf服务?似乎虽然我有一个界面,但我没有干净的使用方法。我看过像NInject这样的东西,但我不相信如果它出现故障会清理ChannelFactory(至少我没有找到任何文件证明它知道何时调用Abort而不是在通道上关闭)。 / p>

我最终做的是再次使用此问题中描述的方法:creating WCF ChannelFactory<T>,并且只是回想一下服务上的方法。这对我来说有点“闻起来”,因为我再次包裹所有的电话只是为了确保频道正确关闭/中止。

有没有任何模式/方法干净地有两个接口的实现,其中一个是Wcf服务?

谢谢,

麦克

1 个答案:

答案 0 :(得分:5)

我使用了答案linked in Mark's commentthis article here的变体来提出一个对我有用的解决方案。

根据您定义的服务合同,第1步将定义实现您的服务的接口IClientChannel

// Service Contract
public interface ICalculator
{
    Add(double a, double b);
}

// Interface to expose Close and Abort
public interface ICalculatorChannel : ICalculator, IClientChannel { }

第2步涉及创建可重用的代码,该代码将处理创建代理并实现代码以关闭或中止连接。

public class ServiceClient<T> where T : class, IClientChannel
{
    private ProxyGenerator _generator = new ProxyGenerator();

    public T CreateProxy(string endpointConfigurationName)
    {
        return _generator.CreateInterfaceProxyWithoutTarget<T>
            (new WcfInterceptor<T>(endpointConfigurationName));
    }
}

ServiceClient<T>中的T将采用步骤1中定义的ICalculatorChannel .ProxyGenerator是Castle项目的一部分。它的用法是允许我们拦截对WCF服务的调用并执行前后操作。

public class WcfInterceptor<T> : IInterceptor where T : IClientChannel
{
    private ChannelFactory<T> _factory = null;

    public WcfInterceptor(string endpointConfigurationName)
    {
        _factory = new ChannelFactory<T>(endpointConfigurationName);
    }

    public void Intercept(IInvocation invocation)
    {
        T channel = _factory.CreateChannel();

        try
        {
            invocation.ReturnValue = invocation.Method.Invoke
                (channel, invocation.Arguments);
        }
        finally
        {
            closeChannel(channel);
        }
    }
}

如您所见,Intercept方法封装了通道和调用以关闭通道。 closeChannel方法将决定调用Close()Abort()

    private void closeChannel(T channel)
    {
        if (channel != null)
        {
            try
            {
                if (channel.State != CommunicationState.Faulted)
                {
                    channel.Close();
                }
                else
                {
                    channel.Abort();
                }
            }
            catch
            {
                channel.Abort();
            }
        }
    }

现在我们创建一个类来包装此ServiceClient的用法。

public class Calculator : ICalculator
{
    private var _calcualtor = new ServiceClient<ICalculatorChannel>();

    public void Add(double a, double b)
    {
        var proxy = _calculator.CreateProxy("endpointConfigGoesHere");

        return proxy.Add(a, b);
    }
}

请注意,add的实现不再需要处理WCF连接问题。消费类只需了解服务合同即可。现在ServiceClient班为我们处理了处理故障连接的丑陋。

客户端现在只需要承担一个依赖关系。

public class MyClient
{
    private ICalculator _calculator;

    public MyClient(ICalculator calculator)
    {
        _calculator = calculator;
    }
}

IOC可以填充客户端:

Bind<ICalculator>().To<Calculator>();