带有点网核心的自托管进程内 Web API
Posted
技术标签:
【中文标题】带有点网核心的自托管进程内 Web API【英文标题】:Self-hosted In Process Web API with Dot net core 【发布时间】:2020-01-25 00:18:55 【问题描述】:我正在尝试调查迁移到 dot net core 的合理性,现在 3.0 已经发布。我们的关键组件之一允许我们的(私有)nugets 创建自己的 WebAPI,为消费者提供事件和方法。支持远程服务控制、远程服务配置等功能,允许api提供远程配置设置/检索等功能。
此功能是我们微服务架构当前工作方式的关键。
我正在尝试使用 dotnet core 复制它,但是,我正在努力寻找直接等效的教程/场景。我们基本上遵循了这里详述的过程:
https://docs.microsoft.com/en-us/aspnet/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api
但是,在检查了 nuget 包的兼容性(一切看起来都还不错..)之后,我现在在调用 WebApp.Start<Startup>(baseaddress);
时得到空引用异常
null 引用异常显然是由 nuget 包与 .net 核心的不兼容调用的,请参见此处:
NullReferenceException experienced with Owin on Startup .Net Core 2.0 - Settings?
链接中提供的解决方案是一种方式,但它使用了第三方应用程序 - NancyFx。有没有办法以当前形式实现与 dotnet core 相同的功能?之前有大量关于自托管的文档,但不幸的是,由于 aspnet 核心在自己的进程中运行,因此很难找到解决方案!
任何人都可以在这里指出正确的方向吗?
代码如下所示
//the external library would contain all this code. I.e. this could present the configuration endpoints as mentioned above.
public class Startup
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/controller/id",
defaults: new id = RouteParameter.Optional
);
appBuilder.UseWebApi(config);
public class WebAPI:IDisposable
private IDisposable _webApp;
public WebAPI()
string baseAddress = "http://localhost:8800/";
_webApp = WebApp.Start<Startup>(baseAddress); // << This line throws null reference exception
#region IDisposable Support
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
if (!disposedValue)
if (disposing)
_webApp.Dispose();
_webApp = null;
disposedValue = true;
public void Dispose()
Dispose(true);
#endregion
public class ValuesController:ApiController
// GET api/values
public IEnumerable<string> Get()
return new string[] "value1", "value2" ;
// GET api/values/5
public string Get(int id)
return "value";
主应用,上面库的宿主/消费者。
class Program
static void Main()
var webapi = new WebApiTest.WebAPI();
Console.WriteLine("Running...");
Console.ReadLine();
webapi.Dispose();
【问题讨论】:
你看过dotnet new webapi
提供的模板了吗?这默认情况下自托管,但也可以部署到 IIS。
谢谢一个好主意,我会看看他们是怎么做的!谢谢..
@ChrisWatts 我知道这是一个老问题 - 但你有没有想过这个问题?我们正在将 .NET Framework 项目移植到 .NET 5,我也遇到了这个空引用问题。 NancyFX 项目已停止,如果可以的话,我宁愿避免它。
@tmwoods,见下文.. 应该是您需要的唯一一点.. 它可以帮助您入门,也可以解决您的问题..
【参考方案1】:
我最终还是弄清楚了。基本上,我查看了使用新的 dotnet core webapi 项目创建的项目存根,然后重写了启动类,使其不那么固定。这意味着我可以在主应用程序中使用我自己的依赖注入容器,并且一切都可以按预期连接。我必须补充一点,这没有经过实战测试,或者根本没有经过真正的测试,该项目退居二线,但原理有效,只需要改进/定制以适应。
唯一感兴趣的代码是新的“Api”类,在我的例子中,它可以按需启动/停止 API:(可能可以删除配置,但正在尝试尽可能多地自定义 API)
public class Api:IDisposable
private readonly IHost _host;
private readonly IConfigurationManager _configManager;
public Api(DryIoc.IContainer container, IConfigurationManager configManager)
_host = CreateBuilder(Array.Empty<string>(), container).Build();
_configManager = configManager;
_configManager.Build($"nameof(Api)_iosource");
public async void Start()
await _host.StartAsync();
public async void Stop()
await _host.StopAsync();
private IHostBuilder CreateBuilder(string[] args, DryIoc.IContainer container = null)
return new HostBuilder()
//CreateDefaultBuilder, taken from source, to allow custom useserviceproviderfactory
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureHostConfiguration(config =>
config.AddEnvironmentVariables(prefix: "DOTNET_");
if (args != null)
config.AddCommandLine(args);
)
.ConfigureAppConfiguration((hostingContext, config) =>
var env = hostingContext.HostingEnvironment;
config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.env.EnvironmentName.json", optional: true, reloadOnChange: true);
if (env.IsDevelopment() && !string.IsNullOrEmpty(env.ApplicationName))
var appAssembly = Assembly.Load(new AssemblyName(env.ApplicationName));
if (appAssembly != null)
config.AddUserSecrets(appAssembly, optional: true);
config.AddEnvironmentVariables();
if (args != null)
config.AddCommandLine(args);
)
.UseServiceProviderFactory(new DryIocServiceProviderFactory(container))
.ConfigureLogging((hostingContext, logging) =>
var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
// IMPORTANT: This needs to be added *before* configuration is loaded, this lets
// the defaults be overridden by the configuration.
if (isWindows)
// Default the EventLogLoggerProvider to warning or above
logging.AddFilter<EventLogLoggerProvider>(level => level >= LogLevel.Warning);
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
logging.AddConsole();
logging.AddDebug();
logging.AddEventSourceLogger();
if (isWindows)
// Add the EventLogLoggerProvider on windows machines
logging.AddEventLog();
)
.ConfigureWebHostDefaults(webBuilder =>
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("http://localhost:12000/");
);
//This is the original code thats generated by dotnet for new webapi projects
//private IHostBuilder CreateHostBuilder(string[] args) =>
// //new WebHostBuilder().Build();
// Host.CreateDefaultBuilder(args)
// .ConfigureWebHostDefaults(webBuilder =>
//
// webBuilder.UseStartup<Startup>();
// webBuilder.UseUrls("http://localhost:12000/");
// );
public void Dispose()
_host?.Dispose();
【讨论】:
以上是关于带有点网核心的自托管进程内 Web API的主要内容,如果未能解决你的问题,请参考以下文章
Azure 不显示托管 .net 核心 API 的自定义错误消息
带有 EF Core 更新实体的 ASP.Net 核心 Web Api 如何