假设我有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服务?
谢谢,
麦克
答案 0 :(得分:5)
我使用了答案linked in Mark's comment和this 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>();