对于WCF客户端,我有一个IServiceProxyFactory
接口来设置凭据。
public interface IServiceProxyFactory<T>
{
T GetServiceProxy();
}
public class ServiceProxy1 : IServiceProxyFactory<ServiceClient1>
{
public ServiceClient1 GetServiceProxy()
{
var client = new ServiceClient1();
// set credentials here
return client;
}
}
public class ServiceProxy2 : IServiceProxyFactory<ServiceClient2> {
// ...
}
从问题What is the best workaround for the WCF client `using` block issue?开始,我创建了一个帮手,如下所示:
public static class Service<TProxy, TClient>
where TProxy : IServiceProxyFactory<TClient>, new()
where TClient : ICommunicationObject
{
public static IServiceProxyFactory<TClient> proxy = new TProxy();
public static void Use(Action<TClient> codeBlock)
{
TClient client = default(TClient);
bool success = false;
try
{
client = proxy.GetServiceProxy();
codeBlock(client);
((ICommunicationObject)client).Close();
success = true;
}
finally
{
if (!success)
{
((ICommunicationObject)client).Abort();
}
}
}
}
我使用帮助器:
Service<ServiceProxy1, ServiceClient1>.Use(svc => svc.Method());
问题:
有没有办法摆脱TClient
或TProxy
(更新)类型,以便我可以使用:
Service<ServiceProxy1>.Use(svc => svc.Method());
或(已更新)
Service<ServiceClient1>.Use(svc => svc.Method());
对ICommunicationObject
和Close()
使用Abort()
是否有更好的方法?
答案 0 :(得分:3)
代码
partial class TestClass {
public static void TestMethod() {
Service<ServiceProxy1>.Use(svc => svc.Method());
Service<ServiceProxy1>.Use(svc => svc.Method());
Service<ServiceProxy1>.Use(svc => svc.Method());
Service<ServiceProxy2>.Use(svc => svc.Method());
}
}
public partial interface IServiceProxyFactory<T> {
T GetServiceProxy();
}
public partial class Service<T> where T: ServiceProxy, new() {
public static void Use(Action<T> codeBlock) {
using(var client=ServiceProxy.GetServiceProxy<T>().GetServiceProxy() as T)
try {
codeBlock(client);
}
catch {
throw;
}
}
}
public abstract partial class ServiceProxy: CommunicationObject, IDisposable {
public static T GetServiceProxy<T>() where T: ServiceProxy, new() {
var proxy=m_List.FirstOrDefault(x => typeof(T).Equals(x.GetType())) as T;
if(null==proxy) {
proxy=new T();
m_List.Add(proxy);
}
return proxy;
}
public abstract ServiceProxy GetServiceProxy();
public abstract void Method();
protected virtual void Dispose(bool disposing) {
lock(ThisLock)
if(!this.IsDisposed&&disposing) {
this.Close();
if(!this.IsDisposed)
this.Abort();
}
}
public void Dispose() {
this.Dispose(true);
GC.SuppressFinalize(this);
}
~ServiceProxy() {
this.Dispose(false);
}
static List<ServiceProxy> m_List=new List<ServiceProxy>();
}
public partial class ServiceProxy1: ServiceProxy {
protected override IAsyncResult OnBeginClose(
TimeSpan timeout, AsyncCallback callback, object state
) {
throw new NotImplementedException();
}
protected override IAsyncResult OnBeginOpen(
TimeSpan timeout, AsyncCallback callback, object state
) {
throw new NotImplementedException();
}
protected override void OnAbort() {
}
protected override void OnEndClose(IAsyncResult result) {
}
protected override void OnEndOpen(IAsyncResult result) {
}
protected override void OnClose(TimeSpan timeout) {
}
protected override void OnOpen(TimeSpan timeout) {
}
protected override TimeSpan DefaultCloseTimeout {
get {
return TimeSpan.Zero;
}
}
protected override TimeSpan DefaultOpenTimeout {
get {
return TimeSpan.Zero;
}
}
public override ServiceProxy GetServiceProxy() {
var client=new ServiceProxy1();
// set credentials here
return client;
}
public override void Method() {
}
}
public partial class ServiceProxy2: ServiceProxy1 {
public override ServiceProxy GetServiceProxy() {
var client=new ServiceProxy2();
// set credentials here
return client;
}
}
值得一提的是:
lock
可以安全重新输入
我无法完成从T
到任何Generic<T>
类型的反向推断的完全相同的声明,例如来自{{1到ServiseClient
。
根据2,ServiceProxy<ServiceClient>
和ServiceProxy
在代码中是一样的,所以没有ServiceClient
。
ServiceClient
本身就是抽象。出于方便原因,ServiceProxy
的要求需要转换为ServiceClient
且根据3加,ICommunicationObject
来自ServiceProxy
;然后对于 是否有比... 更好的方法,它实现了CommunicationObject
对于继承IDisposible
的具体类的静态实例,每个实例都只有 一个 实例,并存储在ServiceProxy
中},并调用m_List
的静态通用版本只需获取它们。这看起来更像是飞重模式。
根据5,界面GetServiceProxy<T>()
根本没有使用,只是把它放在那里看起来感觉很开心。
IServiceProxyFactory<T>
的实例版本保留了原始用法,但具体类需要覆盖它。
在GetServiceProxy()
方法中,创建的客户端与 using 语句一起使用。我已经阅读了Avoiding Problems with the Using Statement,但似乎我不知道你想要处理异常的策略,因此我只是尝试和重新抛出。
根据1,我认为通过锁定的线程安全方式以原子方式进行处理,使用继承的Use
和IsDisposed
。 ThisLock
和Close
正在相应地执行此操作。
哦,十!课程Abort
和ServiceProxy2
仅供参考,ServiceProxy1
来自ServiceProxy2
。
代码看起来很冗长,但实际上设计非常简单。请报告我的问题,我会尝试纠正它。希望帮助和好锁定!
答案 1 :(得分:1)
我是通过使用ServiceProxy1
技巧将ServiceClient1
类合并到ServiceClient1 : IServiceProxyFactory<ServiceClient1>
来实现的。
public interface IServiceProxyFactory<T>
{
// can have a better name like SetCredentials()
T GetServiceProxy();
}
// Got rid of ServiceProxy1 class
public partial class ServiceClient1 : IServiceProxyFactory<ServiceClient1>
{
public ServiceClient1 GetServiceProxy()
{
var client = this;
// set credentials here
//client.ClientCredentials = "";
return client;
}
}
public partial class ServiceClient2 : IServiceProxyFactory<ServiceClient2> { ... }
public static class ServiceMod<TClient>
where TClient : class, ICommunicationObject, IServiceProxyFactory<TClient>, new()
{
public static TReturn Use<TReturn>(Func<TClient, TReturn> codeBlock)
{
TClient client = default(TClient);
bool success = false;
try
{
client = new TClient().GetServiceProxy();
TReturn result = codeBlock(client);
client.Close();
success = true;
return result;
}
finally
{
if (!success)
{
client.Abort();
}
}
}
}
现在我可以做到:
Service<ServiceClient1>.Use(svc => svc.Method());