Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Safely release dependency injected wcf client in .net core

I want to use Microsoft's dependency injection in .Net Core (2.2) to inject and safely release WCF clients. I'm using the "WCF Web Service Reference Provider Tool" in VS2019 to add WCF proxy classes to my solution. Using Microsoft.Extensions.DependencyInjection I can register the clients in the services collection, but I can't seem to find a way of hooking into a release lifecycle event (as can be done in various other IoC frameworks, e.g. Autofac), to add code for doing a safe release according to Microsoft's recommendations described here: https://learn.microsoft.com/en-us/dotnet/framework/wcf/samples/use-close-abort-release-wcf-client-resources

Is there any way of doing something like that in the quite basic dependency injection functionality that comes with .Net Core framework? Or am I forced to use 3rd party IoC framework?

Pseudo code:

So basically I want to do something like this:

// 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;
    }
}

But I need a way to hook into the service release lifecycle event, e.g. something like .OnRelease() in Autofac, so I can do proper disposal.

like image 922
maze_dk Avatar asked Oct 30 '25 22:10

maze_dk


2 Answers

I dont know if you still need a response, but on my end to resolve this issue I implemented the dispose into the partial class.

Each time the wcf client is disposed the correct clean up is made:

  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);
    }
}
like image 63
Ayrton Werck Avatar answered Nov 01 '25 12:11

Ayrton Werck


To solve this same problem, I've created a wrapper class that I register as an intermediate in the 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;
        }
    }
}

And register as follows:

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);
like image 24
antmeehan Avatar answered Nov 01 '25 11:11

antmeehan



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!