我正在构建一个HealthAPI类库,它为我们的HealthMonitor服务提供统计信息列表。
我已成功完成此工作,中间件正在记录服务启动时间并记录响应时间,我们的运行状况监视器能够通过调用我们的StatusController
来解析这些值,public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddApplicationPart(Assembly.Load(new AssemblyName("HealthApiLibrary"))); //Bring in the Controller for HealthAPI;
services.AddSingleton<HealthApiService>();
}
有许多操作返回IActionResult JSON回复。
我们打算在我们的所有服务上重复使用它,因此选择将API控制器与DI服务和中间件一起保留在类库中,以使Controller可访问我最初执行以下操作。
services.AddSingleton<HealthApiService>();
然而,在重构阶段,我想通过执行以下操作来清理它:
1)将services.AddHealthApi();
重构为services.AddHealthApi();
(我们尚未对此做任何工作,但在回答此问题时仍可能相关)
2)作为public class HealthApiService
{
public HealthApiService(IMvcBuilder mvcBuilder)
{
mvcBuilder.AddApplicationPart(Assembly.Load(new AssemblyName("HealthApiLibrary"))); //Bring in the Controller for HealthAPI
ResponseTimeRecords = new Dictionary<DateTime, int>();
ServiceBootTime = DateTime.Now;
}
public DateTime ServiceBootTime { get; set; }
public Dictionary<DateTime,int> ResponseTimeRecords { get; set; }
public string ApplicationId { get; set; }
}
电话的一部分加载到我的StatusController中。
我尝试了以下内容:
InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.DependencyInjection.IMvcBuilder' while attempting to activate 'HealthApiLibrary.Services.HealthApiService'.
然而,这只会产生以下错误:
hlines
答案 0 :(得分:2)
<强> 1。依赖注入
您收到异常,因为服务集合中未注册IMvcBuilder
。将此类型添加到集合中是没有意义的,因为它仅在启动期间使用。
<强> 2。扩展方法
您可以创建一个扩展方法来实现您想要的方法。
public static class AddHealthApiExtensions
{
public static void AddHealthApi(this IServiceCollection services)
{
services.AddSingleton<HealthApiService>();
}
}
第3。 Assembly.Load 强>
查看@Tseng的评论。
答案 1 :(得分:2)
根据我收集的内容,您尝试允许最终用户向HealthApiService
提供自己的依赖项。这通常使用扩展方法和一个或多个构建器模式来完成。这不是DI问题,而是应用程序组合问题。
假设HealthApiService
有2个依赖项,IFoo
和IBar
,并且您希望用户能够为每个依赖项提供自己的实现:
public class HealthApiService : IHealthApiService
{
public HealthApiService(IFoo foo, IBar bar)
{
}
}
扩展方法对默认依赖项有一个重载,对任何自定义依赖项都有一个重载。
public static class ServiceCollectionExtensions
{
public static void AddHealthApi(this IServiceCollection services, Func<HealthApiServiceBuilder, HealthApiServiceBuilder> expression)
{
if (services == null)
throw new ArgumentNullException(nameof(services));
if (expression == null)
throw new ArgumentNullException(nameof(expression));
var starter = new HealthApiServiceBuilder();
var builder = expression(starter);
services.AddSingleton<IHealthApiService>(builder.Build());
}
public static void AddHealthApi(this IServiceCollection services)
{
AddHealthApi(services, builder => { return builder; });
}
}
构建器有助于一次构造HealthApiService
一个依赖项。它收集依赖关系,然后在流程结束时Build()
方法创建实例。
public class HealthApiServiceBuilder
{
private readonly IFoo foo;
private readonly IBar bar;
public HealthApiServiceBuilder()
// These are the default dependencies that can be overridden
// individually by the builder
: this(new DefaultFoo(), new DefaultBar())
{ }
internal HealthApiServiceBuilder(IFoo foo, IBar bar)
{
if (foo == null)
throw new ArgumentNullException(nameof(foo));
if (bar == null)
throw new ArgumentNullException(nameof(bar));
this.foo = foo;
this.bar = bar;
}
public HealthApiServiceBuilder WithFoo(IFoo foo)
{
return new HealthApiServiceBuilder(foo, this.bar);
}
public HealthApiServiceBuilder WithBar(IBar bar)
{
return new HealthApiServiceBuilder(this.foo, bar);
}
public HealthApiService Build()
{
return new HealthApiService(this.foo, this.bar);
}
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Default dependencies
services.AddHealthApi();
// Custom dependencies
//services.AddHealthApi(healthApi =>
// healthApi.WithFoo(new MyFoo()).WithBar(new MyBar()));
}
如果您的默认IFoo
或IBar
实现具有依赖关系,则可以为每个实现创建一个构建器类。例如,如果IFoo
具有依赖项IFooey
,则可以为默认的IFoo
实现创建构建器,然后使用表达式重载HealthApiServiceBuilder.WithFoo
方法:
public HealthApiServiceBuilder WithFoo(IFoo foo)
{
return new HealthApiServiceBuilder(foo, this.bar);
}
public HealthApiServiceBuilder WithFoo(Func<FooBuilder, FooBuilder> expression)
{
var starter = new FooBuilder();
var builder = expression(starter);
return new HealthApiServiceBuilder(builder.Build(), this.bar);
}
然后可以像
一样使用services.AddHealthApi(healthApi =>
healthApi.WithFoo(foo => foo.WithFooey(new MyFooey)));
您需要在应用程序启动时注册的任何其他服务(例如,控制器),您不希望最终用户与之交互,可以在扩展方法内完成。