C# 异步客户端服务设计模式
我正在尝试设计一个邮件客户端服务,它允许使用TcpClient类连接和发送/接收命令。我还想在回调每个函数时自动调用调用线程,这样调用者就不需要这样做了 我发现,为了实现这一点,我需要为每个函数编写至少三到四倍于同步编写的代码。最大的问题是,我必须为每个回调编写一个单独的try/catch 我将发布我的连接功能,希望有人能提出更好的方法:C# 异步客户端服务设计模式,c#,service,.net-4.0,tcpclient,C#,Service,.net 4.0,Tcpclient,我正在尝试设计一个邮件客户端服务,它允许使用TcpClient类连接和发送/接收命令。我还想在回调每个函数时自动调用调用线程,这样调用者就不需要这样做了 我发现,为了实现这一点,我需要为每个函数编写至少三到四倍于同步编写的代码。最大的问题是,我必须为每个回调编写一个单独的try/catch 我将发布我的连接功能,希望有人能提出更好的方法: public virtual void Connect(Action<Exception> callback, string hostname,
public virtual void Connect(Action<Exception> callback, string hostname, int port, bool ssl, RemoteCertificateValidationCallback validateCertificate)
{
if (State != ConnectionState.Disconnected)
throw new InvalidOperationException(AlreadyConnectedString);
Host = hostname;
Port = port;
Ssl = ssl;
var context = SynchronizationContext.Current;
// Callback on the caller's thread
Action<Exception> onCallback = (Exception ex) =>
{
context.Post(_ =>
{
callback(ex);
}, null);
};
// Called on any raised exceptions
Action<Exception> onFail = (Exception ex) =>
{
State = ConnectionState.Disconnected;
Cleanup();
onCallback(ex);
};
// Check for a valid response
Action<string, Exception> onConnectResponse = (string response, Exception ex) =>
{
if (ex != null)
onFail(ex);
try
{
OnConnected(response);
onCallback(ex);
}
catch (Exception responseException)
{
onFail(responseException);
}
};
// Callback after SSL authentication
AsyncCallback onAuthenticated = (IAsyncResult result) =>
{
try
{
var sslStream = (SslStream)result.AsyncState;
sslStream.EndAuthenticateAsClient(result);
State = ConnectionState.Authorization;
GetResponse(onConnectResponse);
}
catch (Exception authenticateException)
{
onFail(authenticateException);
}
};
// Callback after TcpClient connect
AsyncCallback onConnect = (IAsyncResult result) =>
{
try
{
_Connection.EndConnect(result);
_Stream = _Connection.GetStream();
if (ssl)
{
SslStream sslStream;
if (validateCertificate != null)
sslStream = new SslStream(_Stream, false, validateCertificate);
else
sslStream = new SslStream(_Stream, false);
_Stream = sslStream;
sslStream.BeginAuthenticateAsClient(hostname, onAuthenticated, sslStream);
}
else
{
State = ConnectionState.Authorization;
GetResponse(onConnectResponse);
}
}
catch (Exception connectException)
{
onFail(connectException);
}
};
try
{
_Connection = new TcpClient();
_Connection.BeginConnect(hostname, port, onConnect, null);
}
catch (Exception ex)
{
onFail(ex);
}
}
公共虚拟void Connect(操作回调、字符串主机名、int端口、bool ssl、RemoteCertificateValidationCallback validateCertificate)
{
如果(状态!=连接状态已断开)
抛出新的InvalidOperationException(AlreadyConnectedString);
主机=主机名;
端口=端口;
Ssl=Ssl;
var context=SynchronizationContext.Current;
//调用方线程上的回调
操作onCallback=(异常示例)=>
{
context.Post(=>
{
回调(ex);
},空);
};
//呼吁任何提出的例外情况
操作失败=(异常示例)=>
{
状态=连接状态。已断开连接;
清理();
onCallback(ex);
};
//检查是否有有效的响应
操作onConnectResponse=(字符串响应,异常示例)=>
{
如果(ex!=null)
onFail(ex);
尝试
{
未连接(响应);
onCallback(ex);
}
捕获(异常响应异常)
{
onFail(responseException);
}
};
//SSL身份验证后的回调
AsyncCallback onAuthenticated=(IAsyncResult结果)=>
{
尝试
{
var sslStream=(sslStream)result.AsyncState;
sslStream.endClient(结果);
状态=连接状态。授权;
GetResponse(OnConnectionResponse);
}
catch(异常authenticateException)
{
onFail(authenticateException);
}
};
//TcpClient连接后的回调
AsyncCallback onConnect=(IAsyncResult结果)=>
{
尝试
{
_连接。结束连接(结果);
_Stream=_Connection.GetStream();
如果(ssl)
{
SSL流SSL流;
if(validateCertificate!=null)
sslStream=新的sslStream(_Stream,false,validateCertificate);
其他的
sslStream=新的sslStream(_-Stream,false);
_流=SSL流;
beginauthenticatesclient(主机名,onAuthenticated,sslStream);
}
其他的
{
状态=连接状态。授权;
GetResponse(OnConnectionResponse);
}
}
捕获(异常连接异常)
{
onFail(连接异常);
}
};
尝试
{
_连接=新的TcpClient();
_Connection.BeginConnect(主机名、端口、onConnect、null);
}
捕获(例外情况除外)
{
onFail(ex);
}
}
以下是我迄今为止成功使用的代码的通用格式 它不会阻止调用线程(UI),并且总是在调用线程上调用其回调,但它在后台线程中完成每个任务的大部分工作 如果线程需要独占访问共享资源(如开放网络/SSL流),则可以使用锁定器封送此资源的使用,以便一次只有一个线程使用它
public void Connect(Action<Exception> callback, string hostname, int port, bool ssl, RemoteCertificateValidationCallback validateCertificate)
{
if (State != ConnectionState.Disconnected)
throw new InvalidOperationException(AlreadyConnectedString);
Host = hostname;
Port = port;
Ssl = ssl;
State = ConnectionState.Connecting;
var callingThread = TaskScheduler.FromCurrentSynchronizationContext();
Action connectAction = () =>
{
// Connect asynchronously in order to specify a timeout
TcpClient connection = new TcpClient();
connection.SendTimeout = SendTimeout;
connection.ReceiveTimeout = ReadTimeout;
IAsyncResult ar = connection.BeginConnect(hostname, port, null, null);
WaitHandle waitHandle = ar.AsyncWaitHandle;
try
{
if (!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromMilliseconds(ConnectTimeout), false))
throw new TimeoutException();
connection.EndConnect(ar);
}
finally
{
waitHandle.Close();
}
Stream stream = connection.GetStream();
if (ssl)
{
SslStream sslStream;
if (validateCertificate != null)
sslStream = new SslStream(stream, false, validateCertificate);
else
sslStream = new SslStream(stream, false);
sslStream.AuthenticateAsClient(hostname);
stream = sslStream;
}
lock (_locker) // Perform thread unsafe operations here
{
_connection = connection;
_stream = stream;
}
OnConnected(GetResponse());
};
Action<Task> completeAction = (Task task) =>
{
Exception ex = (task.Exception != null) ? task.Exception.InnerException : task.Exception;
if (task.Exception != null)
{
Cleanup();
}
else
{
State = ConnectionState.Authorization;
}
if (callback != null)
callback(ex);
};
Task.Factory.StartNew(connectAction, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.Default)
.ContinueWith(completeAction, callingThread);
}
public void Connect(操作回调、字符串主机名、int端口、bool ssl、RemoteCertificateValidationCallback validateCertificate)
{
如果(状态!=连接状态已断开)
抛出新的InvalidOperationException(AlreadyConnectedString);
主机=主机名;
端口=端口;
Ssl=Ssl;
状态=连接状态。正在连接;
var callingThread=TaskScheduler.FromCurrentSynchronizationContext();
动作连接动作=()=>
{
//异步连接以指定超时
TcpClient连接=新的TcpClient();
connection.SendTimeout=SendTimeout;
connection.ReceiveTimeout=ReadTimeout;
IAsyncResult ar=connection.BeginConnect(主机名、端口、null、null);
WaitHandle WaitHandle=ar.AsyncWaitHandle;
尝试
{
if(!ar.AsyncWaitHandle.WaitOne(TimeSpan.FromMillicles(ConnectTimeout),false))
抛出新的TimeoutException();
连接。端连接(ar);
}
最后
{
waitHandle.Close();
}
Stream=connection.GetStream();
如果(ssl)
{
SSL流SSL流;
if(validateCertificate!=null)
sslStream=新sslStream(流、假、validateCertificate);
其他的
SSL流=新SSL流(流,假);
sslStream.authenticatesClient(主机名);
流=SSL流;
}
lock(\u locker)//在此处执行线程不安全的操作
{
_连接=连接;
_溪流=溪流;
}
OnConnected(GetResponse());
};
操作完成操作=(任务)=>
{
异常ex=(task.Exception!=null)?task.Exception.InnerException:task.Exception;
if(task.Exception!=null)
{
清理();
}
其他的
{
状态=连接状态。授权;
}
如果(回拨=