我正在Dotnet Core 3.1中编写一个控制台应用程序。它已经配置为使用Microsoft.Extensions.DependencyInjection
通过以下方式使用依赖项注入:
public static class Program
{
public static IServiceProvider ServiceProvider { get; private set; }
public static int Main(string[] args)
{
// ...
ServiceProvider = ConfigureServices().BuildServiceProvider();
// ...
}
public static IServiceCollection ConfigureServices()
{
return new ServiceCollection()
.AddLogging(cfg =>
{
// ...
}
// ...
}
}
我正在尝试建立一个简单的HTTP API,以提供对该应用程序的一些基本控制。我想避免使用ASP.Net MVC或任何过于沉重的东西。我只需要能够发布简单的说明并获得基本状态。都是JSON-不需要Razor或类似的东西。
我还有另外两个(未完成的)课程:
public class ApiRunner
{
public IWebHost WebHost { get; }
public ApiRunner()
{
WebHost = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:5000")
.UseStartup<ApiStartup>()
.Build();
}
public void Start()
{
Task.Run(() => WebHost.Run());
}
public void Stop()
{
WebHost.StopAsync();
}
}
和
public class ApiStartup
{
public void Configure(IApplicationBuilder app)
{
app.UseRouter(r =>
{
r.MapGet("/", async (request, response, routeData) =>
{
response.Headers["content-type"] = "text/plan";
response.WriteAsync("Hello World!");
});
}
}
}
除非我添加到ApiStartup
类中,否则以上内容将无效:
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
}
但是这似乎有两个DI堆栈相互运行:一个用于主程序,一个用于API。我确实尝试将services.AddRouting();
添加到Program.cs
的主要DI配置中,但是(1)无效-我遇到了与完全没有一样的异常,导致我相信该API想要使用其自己的DI,并且(2)我不一定要使用我认为有点独立的API专用服务来污染我的主要DI。
我需要的是在控制台应用程序中运行的轻型HTTP服务器,该服务器允许我发出简单的命令并获取状态。请问有什么指示可以实现这一目标吗?谢谢。
答案 0 :(得分:0)
据我所知,如果您使用了WebHostBuilder,它将为您的应用程序添加一些通用服务。
WebHostBuilder构建方法将注册公共服务服务,例如记录器,路由或通过调用BuildCommonServices method()。
我认为,由于asp.core已经完成了相同的事情(Startup.cs配置服务),因此无需再次创建服务ServiceProvider。如果您不希望使用剃刀等其他服务,则不能仅使用services.AddControllers();
方法在“启动配置服务”方法中添加剃刀服务,也可以创建可用于Web api的自定义api服务不包含任何与剃刀相关的结果。
以下是网络托管服务商的部分源代码。
Web构建器源代码:
public IWebHost Build()
{
if (this._webHostBuilt)
throw new InvalidOperationException(Resources.WebHostBuilder_SingleInstance);
this._webHostBuilt = true;
AggregateException hostingStartupErrors;
IServiceCollection serviceCollection1 = this.BuildCommonServices(out hostingStartupErrors);
IServiceCollection serviceCollection2 = serviceCollection1.Clone();
IServiceProvider providerFromFactory = GetProviderFromFactory(serviceCollection1);
.....
WebHost webHost = new WebHost(serviceCollection2, providerFromFactory, this._options, this._config, hostingStartupErrors);
try
{
webHost.Initialize();
return (IWebHost) webHost;
}
catch
{
webHost.Dispose();
throw;
}
IServiceProvider GetProviderFromFactory(IServiceCollection collection)
{
ServiceProvider serviceProvider = collection.BuildServiceProvider();
IServiceProviderFactory<IServiceCollection> service = ((IServiceProvider) serviceProvider).GetService<IServiceProviderFactory<IServiceCollection>>();
if (service == null)
return (IServiceProvider) serviceProvider;
using (serviceProvider)
return service.CreateServiceProvider(service.CreateBuilder(collection));
}
}
BuildCommonServices:
private IServiceCollection BuildCommonServices(
out AggregateException hostingStartupErrors)
{
.....
ServiceCollection services = new ServiceCollection();
services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
services.AddTransient<IHttpContextFactory, HttpContextFactory>();
services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
services.AddOptions();
services.AddLogging();
services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>();
services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();
.....
foreach (Action<WebHostBuilderContext, IServiceCollection> servicesDelegate in this._configureServicesDelegates)
servicesDelegate(this._context, (IServiceCollection) services);
return (IServiceCollection) services;
}
如何注册startup.cs:
/// <summary>Specify the startup type to be used by the web host.</summary>
/// <param name="hostBuilder">The <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" /> to configure.</param>
/// <param name="startupType">The <see cref="T:System.Type" /> to be used.</param>
/// <returns>The <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" />.</returns>
public static IWebHostBuilder UseStartup(this IWebHostBuilder hostBuilder,Type startupType)
{
string name = startupType.GetTypeInfo().Assembly.GetName().Name;
return hostBuilder.UseSetting(WebHostDefaults.ApplicationKey, name).ConfigureServices((Action<IServiceCollection>) (services =>
{
if (typeof (IStartup).GetTypeInfo().IsAssignableFrom(startupType.GetTypeInfo()))
ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), startupType);
else
ServiceCollectionServiceExtensions.AddSingleton(services, typeof (IStartup), (Func<IServiceProvider, object>) (sp =>
{
IHostingEnvironment requiredService = sp.GetRequiredService<IHostingEnvironment>();
return (object) new ConventionBasedStartup(StartupLoader.LoadMethods(sp, startupType, requiredService.EnvironmentName));
}));
}));
}
/// <summary>Specify the startup type to be used by the web host.</summary>
/// <param name="hostBuilder">The <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" /> to configure.</param>
/// <typeparam name="TStartup">The type containing the startup methods for the application.</typeparam>
/// <returns>The <see cref="T:Microsoft.AspNetCore.Hosting.IWebHostBuilder" />.</returns>
public static IWebHostBuilder UseStartup<TStartup>(this IWebHostBuilder hostBuilder)
where TStartup : class
{
return hostBuilder.UseStartup(typeof (TStartup));
}
答案 1 :(得分:0)
首先,每个ASP.NET Core应用程序都是一个控制台应用程序,并且仅成为注册了DI和相关服务的Web应用程序。
第二,您没有遵循服务注册的标准模式;不需要自己实例化服务集合,WebHostBuilder已经首先完成了它。仅在ApiStartup类中注册服务。是的,您正在两个地方注册。参见示例,该示例具有记录配置演示的额外好处:
https://github.com/akovac35/Logging.Samples/tree/master/WebApp