在 .NET Core 中安全地释放注入依赖项的 wcf 客户端



我想在.Net Core(2.2)中使用Microsoft的依赖关系注入来注入并安全地释放WCF客户端。我正在使用VS2019中的"WCF Web服务引用提供程序工具"将WCF代理类添加到我的解决方案中。使用 Microsoft.Extensions.DependencyInjection 我可以在服务集合中注册客户端,但我似乎找不到一种挂钩到发布生命周期事件的方法(就像在其他各种 IoC 框架中可以做到的那样,例如 Autofac),以根据此处描述的 Microsoft 的建议添加用于执行安全发布的代码:https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/use-close-abort-release-wcf-client-resources

在.Net Core框架附带的非常基本的依赖注入功能中,有没有办法做类似的事情?还是我被迫使用第三方 IoC 框架?

伪代码:

所以基本上我想做这样的事情:

// Register the channel factory for the service. Make it
// Singleton since you don't need a new one each time.
services.AddSingleton(p => new ChannelFactory<IWcfService>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost/WcfService")));
// Register the service interface using a lambda that creates
// a channel from the factory.
// TODO: need a way to handle proper disposal, e.g. like OnRelease().
services.AddTransient<IWcfService>(p => 
p.GetService<ChannelFactory<IWcfService>>().CreateChannel())
.OnRelease(CloseChannel); // <---This is what I would like to do
static void CloseChannel<T>(T channel)
{
var disp = (ICommunicationObject) channel;
try
{
if (disp.State == CommunicationState.Faulted)
disp.Abort();
else
disp.Close();
}
catch (TimeoutException)
{
disp.Abort();
}
catch (CommunicationException)
{
disp.Abort();
}
catch (Exception)
{
disp.Abort();
throw;
}
}

但是我需要一种方法来挂钩到服务发布生命周期事件,例如.OnRelease() 在 Autofac 中,所以我可以做适当的处置。

我不知道你是否还需要响应,但为了解决这个问题,我将处置实现到分部类中。

每次释放 wcf 客户端时,都会进行正确的清理:

public partial class MyWcfClient : IDisposable
{
protected void Dispose(bool disposing)
{
if (disposing)
{
bool success = false;
try
{
if (State != CommunicationState.Faulted)
{
Close();
}
success = true;
}
finally
{
if (!success)
{
Abort();
}
}
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}

为了解决同样的问题,我创建了一个包装类,我在 DI 中注册为中间类:

public class ChannelWrapper<T> : IDisposable
{
private readonly ILogger<ChannelWrapper<T>> _logger;
public T Channel { get; }
public ChannelWrapper(ChannelFactory<T> factory, ILogger<ChannelWrapper<T>> logger)
{
_logger = logger;
Channel = factory.CreateChannel();
}
public void Dispose()
{
if (Channel is not ICommunicationObject communicationObject)
{
return;
}
try
{
if (communicationObject.State == CommunicationState.Faulted)
{
_logger.LogDebug("Aborting faulted channel");
communicationObject.Abort();
}
else
{
_logger.LogDebug("Closing channel");
communicationObject.Close();
}
}
catch (TimeoutException)
{
_logger.LogDebug("Aborting timed out channel");
communicationObject.Abort();
}
catch (CommunicationException ex)
{
_logger.LogDebug(ex, "Aborting channel");
communicationObject.Abort();
}
catch (Exception)
{
_logger.LogDebug("Aborting channel during exception");
communicationObject.Abort();
throw;
}
}
}

并按如下方式注册:

services.AddTransient(typeof(ChannelWrapper<>));
services.AddSingleton(new ChannelFactory<ISomeService>(binding, new EndpointAddress("net.tcp://localhost:1234/someservice")));
services.AddTransient<ISomeService>(provider => provider.GetRequiredService<ChannelWrapper<ISomeService>>().Channel);

最新更新