本文介绍了如何对Wcf合同使用其他接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有3个程序集,Example.Core,Example.Contracts,Example.WcfServices.在我的合同程序集中,我定义了一个接口并添加了一些操作,例如ICalculator,具有操作Add(double a,double b).在我的WcfServices程序集中,有一个ICalculator实现作为Wcf服务公开.

现在我的问题是....在我的Example.Core程序集中,我如何针对该接口进行编程,同时保持所有组件的分离(以允许我使用该接口的替代实现).如果我有一个需要ICalculator的类,则可以从ChannelFactory创建一个类并使用它,也可以在构造函数中注入一个实例.如果我在类中创建一个类,那么我会将依赖项放在ChannelFactory/Wcf的类中,而我真的不想这样做.如果我在构造函数中注入实例,那么注入类将如何管理和整理wcf服务?看来,尽管我有一个接口,但我没有使用它的干净方法.我已经看过类似NInject的东西,但是我不相信它会在出现故障时清理ChannelFactory(至少我没有找到任何文档来表明它知道何时在通道上调用Abort而不是Close). /p>

我最终要做的是再次添加我的界面,并使用此问题中描述的方法:创建WCF ChannelFactory< ; T> 并仅调用服务上的方法.当我再次打包所有电话时,这只是让我闻起来",以确保通道已正确关闭/中止.

任何人都干净利落地具有两个接口实现的模式/方法,其中之一是Wcf服务吗?

谢谢

迈克.

解决方案

我使用了链接的答案的变体在Mark的评论中此处的文章提出对我有用的解决方案.

鉴于您定义的服务合同,第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>();

Lets say I have 3 assemblies, Example.Core, Example.Contracts, Example.WcfServices. In my contracts assembly I define an interface and add some operation, e.g. ICalculator, which has operation Add(double a, double b). In my WcfServices assembly I have an implementation of ICalculator explosed as a Wcf service.

Now my question is this....in my Example.Core assembly how do I program against that interface while keeping everything decoupled (to allow me to have an alternative implementation of the interface). If I have a class that needs an ICalculator I can create one from say a ChannelFactory and use it, or I can inject an instance in the constructor. If I create one in the class then I am putting dependencies in my class on ChannelFactory/Wcf and I really don't want to do that. If I inject an instance in my constructor then how will the injecting class manage and tidy up the wcf service? It seems that although I have an interface I have no clean way of using it. I have looked at something like NInject, but I am not convinced that it would clean up the ChannelFactory if it faults (at least I haven't found any documentation that shows it knows when to call Abort rather than Close on the channel).

What I have ended up doing is implmenting my interface again and using the method described in this question: creating WCF ChannelFactory<T> and just recalling the methods on the service. This "smells" a bit to me as I am wrapping all my calls again just to ensure the channel is properly closed/aborted.

Has anyone any patterns/methods that cleanly have two implmentations of an interface, one of which is a Wcf service?

Thanks,

Mike.

解决方案

I have used a variation of the answer linked in Mark's comment and this article here to come up with a solution that has worked for me.

Given the service contract you defined, step 1 will be to define an interface implementing your service and IClientChannel.

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

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

Step 2 involves creating reusable code that will handle creating the proxies and implementing the code to close or abort connections.

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

The T in ServiceClient<T> will take the ICalculatorChannel defined in step 1. The ProxyGenerator is part of the Castle project. Its usage here is to allow us to intercept the calls to the WCF service and perform pre and post actions.

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

As you can see, the Intercept method encapsulates the channel and the call to close the channel. The closeChannel method will handle the decision to call Close() or Abort().

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

Now we create a class to wrap up the usage of this 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);
    }
}

Notice that the implementation of add no longer has to deal with the WCF connection concerns. The consuming class only has to know about the Service Contract. The ugliness of of dealing with faulted connections is now taken care of for us by the ServiceClient class.

The client need only take on one dependency now.

public class MyClient
{
    private ICalculator _calculator;

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

And IOC can populate the client:

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

这篇关于如何对Wcf合同使用其他接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-05 21:18
查看更多