簡體   English   中英

.NET DI 內部構造函數和控制台日志記錄

[英].NET DI Internal Constructor and Console Logging

我在ProjectA中有以下類:

public class ApplicationBuilder
{
    private readonly IServiceCollection _services;
    
    internal ApplicationBuilder() => _services = new ServiceCollection();

    public ApplicationBuilder ConfigureServices(Action<IServiceCollection> services)
    {
        _services.AddSingleton<ILoggerFactory, LoggerFactory>();
        _services.AddSingleton(typeof(ILogger<>), typeof(Logger<>));
        _services
            .AddLogging(builder => builder
                .AddConsole()
                .ClearProviders()
                .SetMinimumLevel(LogLevel.Information));
        
        _services.AddSingleton<Application>();

        services.Invoke(_services);
        
        return this;
    }
    
    public Application Build()
    {
        var provider = _services.BuildServiceProvider();
        
        return provider.GetRequiredService<Application>();
    }
}

[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")]

public class Application
{
    private readonly ILogger<Application> _logger;
    internal Application(ILogger<Application> logger) => _logger = logger;
    
    public static ApplicationBuilder Create() => new();

    public void Run()
    {
        _logger.LogInformation("Application started");
        while (true)
        {
            
        }
    }
}

ProjectB中的以下內容:

Application.Create()
    .ConfigureServices(services =>
    {
        
    })
    .Build()
    .Run();

我得到以下異常: Unhandled exception. System.InvalidOperationException: A suitable constructor for type 'Application' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor. Unhandled exception. System.InvalidOperationException: A suitable constructor for type 'Application' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.

我認為[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")]將允許 DI 構造類型,但顯然不是。 有沒有辦法創建我自己的可以使用內部構造函數的構造函數解析器?

此外,如果我跳過這個問題並公開構造函數(我不想這樣做),記錄器不會記錄任何內容。 我是否遺漏了記錄器的設置?

謝謝

編輯:原來 AddLogging / ClearProviders() 是記錄器的問題,我通常在使用完整的 .NET 主機來清除默認框架消息時這樣做,但因為它們不在這里無論如何它正在清除控制台日志記錄提供程序。

編輯:我看到您的問題有所不同,但仍然認為這是對如何完成的重寫。

首先,記住Application來自System.Windows命名空間。 所以我不會使用它。 在下面,我將用其他名稱重寫代碼。


 internal Application(ILogger<Application> logger) => _logger = logger;

為什么不將internal關鍵字作為一個整體與上面的代碼一起刪除呢? 讓我們嘗試以一種你不需要做瘋狂的內部巫術的方式重寫它。


更好的方法

接口:

它們可以在Project B中設置,也可以在Project AProject B共享的獨立Abstractions項目中設置。

下面是配置服務的接口(調用ConfigureServices時返回第二個接口:

/// <summary>
/// Configures the service application and returns the service built.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
public interface IAppBuilderConfigureServices<TApplication>
    where TApplication: class
{
    /// <summary>
    /// Creates a service injection container.
    /// </summary>
    /// <param name="services">Opts for configuring services.</param>
    /// <returns>App Service Builder</returns>
    IAppBuildService<TApplication> ConfigureServices(Action<IServiceCollection> services);
}

構建服務的接口:

/// <summary>
/// Builds the configuration and gets <see cref="TApplication"/> from container.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
public interface IAppBuildService<TApplication>
    where TApplication: class
{
    /// <summary>
    /// App Service builder that returns Singleton of <see cref="TApplication"/>
    /// </summary>
    /// <returns>Instance of <see cref="TApplication"/></returns>
    TApplication Build();
}

項目一:

internal應用程序生成器:


/// <summary>
/// Internally builds the service application and returns the service built.
/// </summary>
/// <typeparam name="TApplication">Application Type</typeparam>
internal class AppBuilder<TApplication> : IAppBuilderConfigureServices<TApplication>, IAppBuildService<TApplication>
    where TApplication: class
{
    private readonly IServiceCollection _services = new ServiceCollection();
    
    public IAppBuildService<TApplication> ConfigureServices(Action<IServiceCollection> services)
    {
        _services.AddLogging(s => s.ClearProviders().AddConsole().SetMinimumLevel(LogLevel.Debug));
        _services.AddSingleton<TApplication>();

        services.Invoke(_services);
        return this;
    }

    public TApplication Build() => _services.BuildServiceProvider().GetRequiredService<TApplication>();
}

public static class AppBuilder
{
    /// <summary>
    /// Creates an instance of <see cref="IAppBuilderConfigureServices{TApplication}"/>
    /// </summary>
    /// <typeparam name="TApplication">Application Type</typeparam>
    /// <returns>Application builder</returns>
    public static IAppBuilderConfigureServices<TApplication> Create<TApplication>()
        where TApplication : class =>
        new AppBuilder<TApplication>();
}

項目B:

只是一個如何配置MyApp的示例。


public static class ProjectB
{
    public static MyApp Initialize()
    {
        return AppBuilder.Create<MyApp>()
            .ConfigureServices(config =>
            {
                // ...
            })
            .Build();
    }
}

最后,您的應用程序代碼:

public class MyApp
{
    private readonly ILogger<MyApp> _logger;

    public MyApp(ILogger<MyApp> logger) => _logger = logger;

    public void HelloWorld()
    {
        _logger.LogInformation("Hello, World!");
    }
}

這是一個草稿,但我想你明白了。 我正在使用接口使其更具可讀性,對摘要感到抱歉,因為我想演示將要做什么。


用法:

ProjectB.Initialize().HelloWorld();

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM