在.net核心应用程序中自托管HTTP(s)端点而不使用asp.net?
Posted
技术标签:
【中文标题】在.net核心应用程序中自托管HTTP(s)端点而不使用asp.net?【英文标题】:Self hosting HTTP(s) endpoints in .net core app without using asp.net? 【发布时间】:2020-07-14 06:21:15 【问题描述】:我还有一个在 Windows 和 Linux 上运行的 .net 核心应用程序(我使用 .net 核心运行时 >= 2.1)。为了获得更好的见解,我想公开一个指标端点(简单的 HTTP GET 端点),以便 Prometheus 发布我的应用程序的一些内部统计信息。
搜索万维网,所以我总是最终使用 asp.net 核心。由于我只想向现有的 .net 核心应用程序添加一个非常简单的 HTTP GET 端点,因此将整个应用程序移植到 asp.net 似乎有点过头了。
我已经考虑过的替代方案是基于 HttpListener 编写我自己的处理程序。当涉及到一个简单的 HTTP 端点时,这是非常直接的,但由于我找到的有关 SSL 和 Linux 的所有信息都是,所以目前不支持,我应该使用 asp.net。 (https://github.com/dotnet/runtime/issues/33288#issuecomment-595812935)
所以我想知道我误解了什么!我是唯一一个? 是否已经有一个很好的库为 .net 核心提供简单的 http(s) 服务器?
编辑:[已解决] 正如@ADyson 在下面的 cmets 中提到的,现有应用程序不需要移植到 asp.net core!
2.1版本自动添加dotnet new web
生成的项目文件
对"Microsoft.AspNetCore.App"
和"Microsoft.AspNetCore.Razor.Design"
的引用
当我从 .net 核心项目中引用我的 asp.net 核心项目并执行托管 Web 服务的代码时,我最终得到了一个 System.IO.FileNotFoundException
声明它 "Could not load file or assembly 'Microsoft.AspNetCore.Mvc.Core'"
。
Microsoft.AspNetCore.App
是一个元包,也引用了Microsoft.AspNetCore.MVC
!因此,执行程序集也必须引用此元包。这个观察误导了我,使用 asp.net core 会使我的整个应用程序围绕Microsoft.AspNetCore.App
构建。
删除这些引用并仅添加对 "Microsoft.AspNetCore"
的引用后,一切正常。
在 3.1 版中检查了从 dotnet new web
生成的项目文件后,这些引用没有被添加。对于使用较新版本 dotnet 的人来说,这不是问题!
【问题讨论】:
您不需要将整个应用程序移植到 asp.net。您是否尝试过使用 OWIN 在另一个应用程序中自托管?最终,尽管您编写的为 Web 应用程序服务的部分几乎肯定会依赖 asp.net 库——这是 .NET 提供 HTTP 功能的方式。你不需要创建一个完整的 MVC 设置或类似的东西。 他们添加了最新的 .net 核心WorkerServices
尚未使用它们,但它们看起来像您需要的。例如Host ASP.NET Core in a Windows Service。我建议检查一下related answer
@ADyson 我看过 OWIN。虽然 conecerns 的概念和分离在其设计中听起来很有希望,但我找不到在 .net 核心应用程序中使用它的方法,因为它仅适用于完整的 .net 框架 (github.com/aspnet/AspNetKatana/blob/dev/src/…)
@pocketbroadcast 这不是真的,as far as I can tell。这是使用 .NET Core / .NET Standard 进行自托管的working example。请记住,OWIN 只是一个标准,而 ASP.NET Core 本身就实现了很多 OWIN 标准,而不需要那么多额外的库。
@ADyson 是的,你完全正确!这都是我的错。我将 wearg nuget 包添加到我的项目中,从而将我带到了一个 asp.net 存储库,而不是适当的 asp.net 核心存储库。应该更好地仔细检查。感谢您指出这一点。
【参考方案1】:
正如@ADyson 所提到的,OWIN 是要走的路。您可以轻松地在现有应用程序中自托管 HTTP 端点。这是一个在 .Net Core 3.1 控制台应用程序中自托管它的示例。它公开了一个简单的端点,使用控制器在端口 5000 上侦听 GET 请求。您只需要安装Microsoft.AspNetCore.Owin Nuget 包即可。
代码文件结构如下:
.
├── Program.cs
├── Startup.cs
├── Controllers
├── SayHi.cs
程序.cs
using Microsoft.AspNetCore.Hosting;
namespace WebApp
class Program
static void Main(string[] args)
var host = new WebHostBuilder()
.UseKestrel()
.UseUrls("http://*:5000")
.UseStartup<Startup>()
.Build();
host.Run();
Startup.cs
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.DependencyInjection;
namespace WebApp
public class Startup
public void ConfigureServices(IServiceCollection services)
services.AddControllers();
public void Configure(IApplicationBuilder app)
app.UseRouting();
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
);
SayHi.cs
using Microsoft.AspNetCore.Mvc;
namespace WebApp.Controllers
public class SayHi : ControllerBase
[Route("sayhi/name")]
public IActionResult Get(string name)
return Ok($"Hello name");
然后一个简单的dotnet WebApp.dll
将启动应用程序和网络服务器。
如您所见,该示例使用 Kestrel。默认网络服务器。你可以查看Microsoft的相关文档。
有关更多配置和路由选项,您可以查看Microsoft 的文档。
【讨论】:
感谢您为托管在 .net 核心控制台应用程序中的 Web 应用程序发布此 PoC,并强调除了Microsoft.AspNetCore.Owin
之外不需要其他 NuGet 包。由于在 .net core 2.1 中安装此软件包失败,它让我检查了 dotnet 2.1 和 dotnet 3.1 中生成的项目文件,这最终导致了我的问题的 EDIT 部分中所述的解决方案。
很高兴为您提供帮助,很高兴您已经弄清楚了 :)
这很好用,您也可以在 WinForms 应用程序中执行此操作,因为现在.NET 5.0 支持。只需确保在单独的线程中执行上述代码中的host.Run()
调用,然后在主线程调用Application.Run(new Form1())
以运行您的主窗体。您不能在同一线程上同时运行 Application.Run()
和 host.Run()
,因为它们会阻塞调用。
@Anouar 请包括您添加到控制台应用程序的所有包...
太烦人了,我无法让 vs 配置文件使用 IIS express,然后在另一个线程中执行 WebHostBuilder
,并使用 Kestrel,所有端口都不同,太烦人了【参考方案2】:
一种选择是使用 EmbeddIo
https://unosquare.github.io/embedio/
我发现文档并不总是最好的,尤其是它们最近升级并且许多示例等无效。但你可以到达那里!
您可以像这样自行托管 REST API:
WebServer ws = new WebServer(o => o
.WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO))
.WithWebApi("/api", m => m
.WithController<ApiController>());
this.Cts = new CancellationTokenSource();
var task = Webserver.RunAsync(Cts.Token);
然后像这样定义你的 API 控制器。
class ApiController : WebApiController
public ApiController() : base()
[Route(HttpVerbs.Get, "/hello")]
public async Task HelloWorld()
string ret;
try
ret = "Hello from webserver @ " + DateTime.Now.ToLongTimeString();
catch (Exception ex)
//
await HttpContext.SendDataAsync(ret);
【讨论】:
感谢您将我指向 NancyFx。框架看起来很棒!尤其是带有.WithController<ApiController>
的部分可以很容易地跟踪哪个控制器处理哪个端点。我一定会看看的!【参考方案3】:
在 2.1 版中使用 dotnet new web
生成的项目文件自动添加了对 "Microsoft.AspNetCore.App"
和 "Microsoft.AspNetCore.Razor.Design"
的引用,当被 .net 核心项目引用并执行时,最终以 System.IO.FileNotFoundException
声明它 "Could not load file or assembly 'Microsoft.AspNetCore.Mvc.Core'"
。
在 3.1 版本中使用 dotnet new web
创建项目不会引用这些,因此可以从 .net 核心应用程序引用和执行该项目。
-> 使用 asp.net core 对我来说是一个可行的解决方案(再次)!
【讨论】:
以上是关于在.net核心应用程序中自托管HTTP(s)端点而不使用asp.net?的主要内容,如果未能解决你的问题,请参考以下文章
连接到 Windows 服务中自托管的 SignalR 的问题
Azure 不显示托管 .net 核心 API 的自定义错误消息
.net 核心 nginx 托管套接字不允许 http post