在.net core中安全释放依赖注入的wcf客户端

问题描述 投票:0回答:2

我想在.Net Core(2.2)中使用微软的依赖注入来注入并安全地释放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 框架附带的相当基本的依赖注入功能有没有办法做类似的事情?或者我被迫使用第 3 方 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;
    }
}

但是我需要一种方法来挂钩服务发布生命周期事件,例如类似 Autofac 中的 .OnRelease() 之类的东西,这样我就可以进行适当的处理。

c# wcf dependency-injection .net-core
2个回答
3
投票

我不知道您是否还需要回复,但为了解决这个问题,我将 dispose 实现到了部分类中。

每次处理 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);
    }
}

0
投票

为了解决同样的问题,我创建了一个包装类,并将其注册为 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);
© www.soinside.com 2019 - 2024. All rights reserved.