[英].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 A
和Project 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.