美味!使用 DynamicTidyProxy 实现更简洁、更优雅的 WCF 代理用法!





5.00/5 (2投票s)
使用 DynamicTidyProxy 进行更干净的 WCF 代理使用
这是对我的上一篇(实际上,我的第一篇)文章“Mmmmm… 使用 TidyProxy 实现简洁、优雅的 WCF 代理用法!”的后续,该文章展示了如何安全地使用任意 WCF 代理类。
我日常开发工作的大部分时间都在使用 WCF 服务,主要是 Web 和 MSMQ。经过一些初期问题,一切都运行良好。通常,这些都是内部 Windows 到 Web 的通信,我可以控制客户端和服务器的实现,因此有很多共享类型。
然而,我最近一个快速增长的 Web 服务 API 达到了元数据限制(显然,存在最多 30 个方法的原因!),这意味着 VS2008 或 svcutil 无法可靠地生成可用的代理,而无需更改可能需要生成代理的每台机器的标准配置。
因此,在一次巨大的重构之后,我将一个服务分解为十四个(14 个! – 它怎么变得这么大!)更小、更连贯的服务 – 我现在面临着一项更艰巨的任务,即用较小的服务替换较大的服务。显然,这不会很好,因为我们需要将一个服务引用替换为十四个!由于该服务在多个项目中被使用,这可能会导致我被钉在墙上。
经过一番 Google 搜索、Reflectoring 和检查生成的代码后,我很快意识到,对于我的情况,我根本不需要生成代理!由于所有类型都使用公共库在客户端和服务器之间共享,并且 WCF 配置在配置文件中,我只需要包装 ChannelFactory<>
。这个巧妙的类完成了 WCF 中的所有繁重工作,只需要服务契约接口和端点名称!
仿佛魔法一般,代理出现了…
using System;
using System.ServiceModel;
namespace MartinOnDotNet.Helpers.WCF
{
/// <summary>
/// Dynamically create a WCF proxy class using the given interface
/// </summary>
/// <typeparam name="TServiceContract">The type of the service contract.</typeparam>
public class DynamicTidyProxy<TServiceContract> : IDisposable
{
/// <summary>
/// Initializes a new instance of the
/// <see cref="DynamicTidyProxy<TServiceContract>"/> class.
/// </summary>
public DynamicTidyProxy()
{
EndpointName = typeof(TServiceContract).Name;
}
/// <summary>
/// Initializes a new instance of the
/// <see cref="DynamicTidyProxy<TServiceContract>"/> class.
/// </summary>
/// <param name="endpointConfigurationName">Name of the endpoint configuration.
/// </param>
public DynamicTidyProxy(string endpointConfigurationName)
{
EndpointName = endpointConfigurationName;
}
/// <summary>
/// Gets or sets the name of the endpoint.
/// </summary>
/// <value>The name of the endpoint.</value>
public string EndpointName { get; set; }
private ChannelFactory<TServiceContract> _channel;
private TServiceContract _client;
/// <summary>
/// Gets the client.
/// </summary>
/// <value>The client.</value>
public TServiceContract Client
{
get
{
if (_client == null)
{
if (!typeof(TServiceContract).IsInterface)
throw new NotSupportedException("TServiceContract must be an interface!");
if (string.IsNullOrEmpty(EndpointName))
throw new NotSupportedException("EndpointName must be set prior to use!");
_channel = new ChannelFactory<TServiceContract>(EndpointName);
_client = _channel.CreateChannel();
}
return _client;
}
}
#region IDisposable Members
/// <summary>
/// Performs application-defined tasks associated with freeing,
/// releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
if (_channel != null)
{
_channel.CloseConnection();
}
GC.SuppressFinalize(this);
}
#endregion
}
}
我将默认构造函数编码为使用服务契约接口类型名称…所以请确保您的配置文件匹配!
然后,您可以使用以下代码动态创建 WCF 代理:
using (var proxy = new DynamicTidyProxy<IMagicComplexServiceContract>())
{
proxy.Client.DoSomeMagicallyComplexOperation();
}
无需 svcutil 或 VS2008 服务引用!
这也意味着我不需要花那么多时间进行重构!(至少今天…它迟早会发生 - 我保证)。
整理
您可能已经注意到 DynamicTidyProxy Dispose
方法中的微妙“_channel.CloseConnection()
”...这只是一个扩展方法,它包装了所有必需的 WCF 样板代码…
// <summary>
/// Safely closes a service client connection.
/// </summary>
/// <param name="serviceClient">The service client.</param>
public static void CloseConnection(this ICommunicationObject serviceClient)
{
if (serviceClient == null) return;
try
{
if (serviceClient.State == CommunicationState.Opened)
{
serviceClient.Close();
}
else
{
serviceClient.Abort();
}
}
catch (CommunicationException ex)
{
Logging.Logger.Log(ex);
try
{
serviceClient.Abort();
}
catch { } //nasty but nothing useful can be found
//by logging this exception as secondary issue
}
catch (TimeoutException ex)
{
Logging.Logger.Log(ex);
try
{
serviceClient.Abort();
}
catch { }//nasty but nothing useful can be found
//by logging this exception as secondary issue
}
catch (Exception ex)
{
Logging.Logger.Log(ex);
try
{
serviceClient.Abort();
}
catch { }//nasty but nothing useful can be found
//by logging this exception as secondary issue
throw;
}
}