CoreWCF icon indicating copy to clipboard operation
CoreWCF copied to clipboard

[Feature Request]: UseUnixDomainSocket() with HostApplicationBuilder

Open cbenard opened this issue 1 year ago • 3 comments

Is your feature request related to a problem? Please describe. Per @davidfowl, we have moved away from the ceremony of the generic host.

However, the HostApplicationBuilder returned from Host.CreateApplicationBuilder() does not have the extension classes in CoreWCF to use UseUnixDomainSocket(). It expects an IHostBuilder, which HostApplicationBuilder does not implement.

Describe the solution you'd like I'd like to be able to call UseUnixDomainSocket() on a HostApplicationBuilder.

Describe alternatives you've considered I was first going to locally add an extension class, but it won't work because of the protection level (internal) of UnixDomainSocketHostedService.

I was going to send a PR with a new extension class, but I can't reference IHostApplicationBuilder because it only targets net6.0 with 6.0 NuGets. I'd have to either multi-target the solution or upgrade the NuGets without upgrading the TFM, which I don't think would even work and wouldn't be approved.

I basically need the solution to be upgraded to net8.0 or multi-targeted before I can do anything. I doubt you want an outside PR to upgrade everything to net8.0 and I don't know what the plan is there. It's been LTS for a long time, so I assume it wasn't done for a reason.

Additional context I'm trying to avoid the extra stuff registered and the ceremony of Host.CreateDefaultBuilder()

cbenard avatar Aug 28 '24 16:08 cbenard

I have some good news for you, I have a workaround. But before that, I did some reading (really helpful discussion you linked to btw) and there's a common interface that both WebApplicationBuilder and HostApplicationBuilder both implement, and that's IHostApplicationBuilder. A new UseUnixDomainSocket extension method can be created for IHostApplicationBuilder which will cover both scenarios. There's a caveat to doing this though, we can't do it yet. To use IHostApplicationBuilder, it would require us to reference Microsoft.Extensions.Hosting.Abstractions 8.0.0. Adding this would result in upgrading a dependency on this for .NET Framework, .NET 6, and .NET 8 apps. This package comes with a broad set of transitive dependencies which would have a high chance of causing problems for an app that upgraded to a new version. This include Configuration (which then means any config providers too), DI (which shouldn't be a problem as we've had to raise that and it's not impactful), Diagnostics (including diagnostic providers and sources), and FileProviders. This work will need to wait until after .NET 6 is out of support, which is only in November so not too far away. But it can't happen right now.

But luckily there's a workaround. It will be easier if I just paste a complete Program.cs file using Minimal API below. Basically I'm creating an IHostBuilder implementation which is what UseUnixDomainSocket is an extension method of. This implementation wraps an IHostApplicationBuilder so when a configuration delegate is passed to IHostBuilder.ConfigureServices by UseUnixDomainSocket, it provides a dummy HostBuilderContext (which UseUnixDomainSocket doesn't even look at) along with the Services from the IHostApplicationBuilder. It's basically a minimal adapater with just the pieces implemented that CoreWCF needs.

var builder = Host.CreateApplicationBuilder();
builder.Services.AddServiceModelServices();
builder.Logging.AddFilter("Default", LogLevel.Debug);
builder.Logging.AddFilter("Microsoft", LogLevel.Debug);
builder.Logging.AddFilter("CoreWCF", LogLevel.Debug);
builder.Logging.SetMinimumLevel(LogLevel.Debug);
builder.Logging.AddDebug();
builder.Logging.AddConsole();

var hostBuilder = new DummyHostBuilder(builder);
var netUdsUriString = "net.uds://" + Path.Combine(Path.GetTempPath(), "udsService.svc");
hostBuilder.UseUnixDomainSocket(options =>
{
    options.Listen(new Uri(netUdsUriString));
});

var host = builder.Build();
CoreWCF.UnixDomainSocketBinding serverBinding = new UnixDomainSocketBinding();
host.UseServiceModel(builder =>
{
    builder.AddService<Service>();
    builder.AddServiceEndpoint<Service, IService>(serverBinding, netUdsUriString);
});

host.Run();

internal class DummyHostBuilder : IHostBuilder
{
    private IHostApplicationBuilder _hostApplicationBuilder;

    public DummyHostBuilder(IHostApplicationBuilder hostApplicationBuilder)
    {
        _hostApplicationBuilder = hostApplicationBuilder;
    }

    public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
    {
        if (configureDelegate != null)
        {
            configureDelegate(new HostBuilderContext(new Dictionary<object, object>()), _hostApplicationBuilder.Services);
        }

        return this;
    }

    public IDictionary<object, object> Properties { get; } = null;
    public IHost Build() => throw new NotImplementedException();
    public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate) => throw new NotImplementedException();
    public IHostBuilder ConfigureContainer<TContainerBuilder>(Action<HostBuilderContext, TContainerBuilder> configureDelegate) => throw new NotImplementedException();
    public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate) => throw new NotImplementedException();
    public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) where TContainerBuilder : notnull => throw new NotImplementedException();
    public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(Func<HostBuilderContext, IServiceProviderFactory<TContainerBuilder>> factory) where TContainerBuilder : notnull => throw new NotImplementedException();
}

mconnew avatar Aug 28 '24 21:08 mconnew

Please leave this issue open even though you have a solution so that we can track adding this for .NET 8.

mconnew avatar Aug 28 '24 21:08 mconnew

Thanks for the workaround, but I believe we will just use Host.CreateDefaultBuilder() for now for legibility and maintainability. We look forward to the .NET 8 compatibility.

cbenard avatar Aug 28 '24 22:08 cbenard