【发布时间】:2018-03-18 00:14:54
【问题描述】:
我正在构建一个 HealthAPI 类库,它为我们的 HealthMonitor 服务提供统计信息列表。
我已经成功完成了这项工作,中间件正在记录服务启动时间和响应时间,我们的运行状况监视器能够通过调用 StatusController 来解析这些值,该 StatusController 有许多返回 IActionResult JSON 响应的操作.
我们打算在我们的所有服务中重用它,因此选择将 API 控制器与 DI 服务和中间件一起保留在类库中,以使控制器可访问我最初做了以下操作。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddApplicationPart(Assembly.Load(new AssemblyName("HealthApiLibrary"))); //Bring in the Controller for HealthAPI;
services.AddSingleton<HealthApiService>();
}
但是在重构阶段,我想通过执行以下操作来稍微清理一下:
1) 将services.AddSingleton<HealthApiService>(); 重构为services.AddHealthApi();(我们目前还没有做任何工作,但在回答这个问题时仍然可能是相关的)
2) 在 services.AddHealthApi(); 调用中加载我的 StatusController。
我尝试了以下方法:
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; }
}
但是这只会产生以下错误:
InvalidOperationException: Unable to resolve service for type 'Microsoft.Extensions.DependencyInjection.IMvcBuilder' while attempting to activate 'HealthApiLibrary.Services.HealthApiService'.
【问题讨论】:
-
你为什么还要通过
Assembly.Load加载它?只需将它放在一个nuget包中,引用它,然后调用注册中间件的扩展方法。只要控制器继承自 Controller 基类或引用Microsoft.AspNetCore.Mvc包,ASP.NET Core MVC 就会自动检测控制器 -
从服务中访问容器是可怕的服务定位器反模式。但是在阅读了您的问题之后,这甚至与您想要实现的目标还相差甚远。您真正追求的只是创建一个扩展方法以使您的库更易于注册。在应用程序启动时应该注册您的服务的扩展方法。
-
@Tseng,你能否提供更多细节,我在开发这个时做了一些测试,找不到任何关于 ASP.net Web 应用程序项目如何能够访问的信息位于类库中的控制器。
-
ASP.NET Core 按约定发现控制器。它查看主项目加载/引用的每个程序集。因此,如果您有一个带有控制器的类库并且这个类库引用了
Microsoft.AspNetCore.Mvc/Microsoft.AspNetCore.MvcCore,它将查找从Controller基类继承或具有@ 的所有类987654333@ 后缀(即MyController)并将它们注册为控制器。您需要做的就是引用该库 -
正确,您不应该将属性路由与库一起使用,您应该使用基于约定的路由。通过这种方式,您可以更轻松地在应用程序启动时将其绑定到宿主应用程序。
标签: c# asp.net-core .net-core asp.net-core-webapi asp.net-core-2.0