我有我的WCF客户端库中的下列计划架构:
- 使用的ChannelFactory代替SvcUtil工具生成的代理,因为我需要更多的控制,也是我想保持在一个单独的程序在客户端和避免当我WCF服务变更再生
- 需要申请一个消息检查到我的WCF端点的行为,所以每个通道可以发送自己的身份验证令牌
- 我的客户端库将从MVC前端使用,所以我得考虑可能的线程问题
- 我使用.NET 4.5(也许它有一些助手或新的方法来实现WCF客户一些更好的办法?)
我看了一下各种不同的比特很多文章,但我仍然感到困惑如何把它放在一起以正确的方式。 我有以下问题:
- 按照我的理解,建议缓存的ChannelFactory在一个静态变量,然后获取渠道出来的,对吧?
- 为终结点行为具体到整个的ChannelFactory或我能将我的认证行为分开各个通道? 如果该行为是针对整个工厂,这意味着我不能让我的终结点行为对象的任何状态信息,因为同样的身份验证令牌将被重用为每一个通道,但很明显,我想每个通道都为自己的身份验证令牌当前用户。 这意味着,我必须来计算我的终结点行为的内部令牌(我可以把它在HttpContext的,我的消息检查的行为只会把它添加到传出消息)。
- 我的客户端类是一次性的(实现IDispose)。 如何正确处置渠道,知道它可能在任何可能的状态(不开张,开张,失败...)? 难道我只是处置呢? 难道我放弃它,然后处理? 难道我关闭它(但也可能是没有打开尚未在所有),然后处理?
- 与信道工作时,如果我得到了一些故障怎么办? 仅在渠道细分或全部的ChannelFactory被打破?
我想,一行代码讲一千多字,所以这里是我的代码形式的想法。 我已经导致了我的所有问题上面“???” 在代码中。
public class MyServiceClient : IDisposable
{
// channel factory cache
private static ChannelFactory<IMyService> _factory;
private static object _lock = new object();
private IMyService _client = null;
private bool _isDisposed = false;
/// <summary>
/// Creates a channel for the service
/// </summary>
public MyServiceClient()
{
lock (_lock)
{
if (_factory == null)
{
// ... set up custom bindings here and get some config values
var endpoint = new EndpointAddress(myServiceUrl);
_factory = new ChannelFactory<IMyService>(binding, endpoint);
// ???? do I add my auth behavior for entire ChannelFactory
// or I can apply it for individual channels when I create them?
}
}
_client = _factory.CreateChannel();
}
public string MyMethod()
{
RequireClientInWorkingState();
try
{
return _client.MyMethod();
}
catch
{
RecoverFromChannelFailure();
throw;
}
}
private void RequireClientInWorkingState()
{
if (_isDisposed)
throw new InvalidOperationException("This client was disposed. Create a new one.");
// ??? is it enough to check for CommunicationState.Opened && Created?
if (state != CommunicationState.Created && state != CommunicationState.Opened)
throw new InvalidOperationException("The client channel is not ready to work. Create a new one.");
}
private void RecoverFromChannelFailure()
{
// ??? is it the best way to check if there was a problem with the channel?
if (((IChannel)_client).State != CommunicationState.Opened)
{
// ??? is it safe to call Abort? won't it throw?
((IChannel)_client).Abort();
}
// ??? and what about ChannelFactory?
// will it still be able to create channels or it also might be broken and must be thrown away?
// In that case, how do I clean up ChannelFactory correctly before creating a new one?
}
#region IDisposable
public void Dispose()
{
// ??? is it how to free the channel correctly?
// I've heard, broken channels might throw when closing
// ??? what if it is not opened yet?
// ??? what if it is in fault state?
try
{
((IChannel)_client).Close();
}
catch
{
((IChannel)_client).Abort();
}
((IDisposable)_client).Dispose();
_client = null;
_isDisposed = true;
}
#endregion
}