[英].NET DI Internal Constructor and Console Logging
I have the following classes in ProjectA
:我在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)
{
}
}
}
And the following in ProjectB
: ProjectB
中的以下内容:
Application.Create()
.ConfigureServices(services =>
{
})
.Build()
.Run();
I get the following exception: 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.
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.
I thought [assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")]
would allow DI to construct the type but apparently not.我认为[assembly: InternalsVisibleTo("Microsoft.Extensions.DependencyInjection")]
将允许 DI 构造类型,但显然不是。 Is there some way to create my own constructor resolver that can use internal constructors?有没有办法创建我自己的可以使用内部构造函数的构造函数解析器?
Also if I skip this problem and make the constructor public (which I don't want to do), the logger doesn't log anything.此外,如果我跳过这个问题并公开构造函数(我不想这样做),记录器不会记录任何内容。 Am I missing something with the setup for the logger?我是否遗漏了记录器的设置?
Thanks谢谢
EDIT: Turns out AddLogging / ClearProviders() was the problem with the logger, I normally do this when using full .NET hosts to clear out the default framework messages but as they aren't here anyways it was clearing out the console logging provider.编辑:原来 AddLogging / ClearProviders() 是记录器的问题,我通常在使用完整的 .NET 主机来清除默认框架消息时这样做,但因为它们不在这里无论如何它正在清除控制台日志记录提供程序。
Edit: I saw your issue was different, but still, consider this a rewrite for how it can be done.编辑:我看到您的问题有所不同,但仍然认为这是对如何完成的重写。
First of all, remember Application is from System.Windows
namespace.首先,记住Application来自System.Windows
命名空间。 So I wouldn't use it.所以我不会使用它。 Further below, I'll rewrite the code with some other name.在下面,我将用其他名称重写代码。
internal Application(ILogger<Application> logger) => _logger = logger;
Why not removing the internal
keyword as a whole alongside the code above?为什么不将internal
关键字作为一个整体与上面的代码一起删除呢? Let's try rewriting it in a way you don't need to do crazy internal witchcraft.让我们尝试以一种你不需要做疯狂的内部巫术的方式重写它。
A better approach更好的方法
Interfaces:接口:
They can be set up in Project B
or in a standalone Abstractions
project shared by both Project A
and Project B
.它们可以在Project B
中设置,也可以在Project A
和Project B
共享的独立Abstractions
项目中设置。
The following is an interface for configuring services (which returns the second interface when calling ConfigureServices
:下面是配置服务的接口(调用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);
}
Interface for building the service:构建服务的接口:
/// <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();
}
Project A:项目一:
internal
application builder: 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>();
}
Project B:项目B:
Just of an example of how it MyApp
can be configured.只是一个如何配置MyApp
的示例。
public static class ProjectB
{
public static MyApp Initialize()
{
return AppBuilder.Create<MyApp>()
.ConfigureServices(config =>
{
// ...
})
.Build();
}
}
Finally, your application code:最后,您的应用程序代码:
public class MyApp
{
private readonly ILogger<MyApp> _logger;
public MyApp(ILogger<MyApp> logger) => _logger = logger;
public void HelloWorld()
{
_logger.LogInformation("Hello, World!");
}
}
This is a draft but I think you get the idea.这是一个草稿,但我想你明白了。 I'm using interfaces to make it more readable, sorry about the summaries, as I wanted to demonstrate what things were going to do.我正在使用接口使其更具可读性,对摘要感到抱歉,因为我想演示将要做什么。
Usage:用法:
ProjectB.Initialize().HelloWorld();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.