如何使用AddMvcCore()实现“纯”ASP.NET Core Web API
我见过很多使用默认AddMvc()
服务的ASP.NET Core Web API项目,但没有意识到由于对服务的控制,使用AddMvcCore()
是一个更好的选择。
您是如何使用AddMvcCore()
实现ASP.NET Core Web API的?它为什么更好?
AddMvc()
和AddMvcCore()
什么AddMvcCore()
?
首先要理解的是, AddMvc()
只是AddMvc()
的预加载版本。 您可以在GitHub存储库中看到AddMvc()
扩展的确切实现。
我喜欢使用默认VS模板和下一个人一样多,但有时你需要知道什么时候它是错误的选择。 我在网上看到了几个指南,更倾向于试图“撤销”这些默认服务,而不是仅仅采用一开始就没有实现它们的解决方案。
随着ASP.NET Core的出现,我们无法在不担心失去“魔力”的情况下剥离一层并在较低级别工作。
“minimal”和“pure”的定义
注意:这些定义仅适用于本答案的上下文。 主要是为了清楚起见并有助于进一步理解。
这个答案更倾向于“纯粹”而不是“最小”。 我想描述一下为什么,所以我说的更清楚。
最小。 “最小”解决方案将是一个甚至根本不调用 AddMvcCore()
方法的实现 。 这样做的原因是,MVC并不是组装自己的Web API的“必需”组件,它肯定会给你的代码带来额外的依赖性。 在这种情况下,由于您没有使用AddMvcCore()
方法,因此您也不会将其注入到您的应用程序中,这里
public void Configure(IApplicationBuilder app) { app.UseMvc(); // you don't need this }
这意味着映射您自己的路线并以您自己的方式响应context
。 这根本不具有挑战性,但我不想深入研究它,因为它非常偏离主题,但这是一个极小的实现 :
public void Configure(IApplicationBuilder app) { app.Map("/api", HandleMapApi); // notice how we don't have app.UseMvc()? } private static void HandleMapApi(IApplicationBuilder app) { app.Run(async context => { // implement your own response await context.Response.WriteAsync("Hello WebAPI!"); }); }
对于许多项目,“最小”方法意味着我们放弃了MVC中的一些function。 您真的必须权衡您的选项,看看您的设计路径是否正确,因为在设计模式,便利性,可维护性,代码占用空间以及最重要的性能和延迟之间存在平衡。 简单地说:“最小”解决方案意味着最小化代码和请求之间的服务和中间件。
纯。 一个“纯粹的”解决方案(就这个答案的上下文而言)是避免所有默认服务和中间件,这些服务和中间件与AddMvc()
预先捆绑在一起,而不是首先实现它。 相反,我们使用AddMvcCore()
,这将在下一节中进一步解释:
使用AddMvcCore()
实现我们自己的服务/中间件
首先要做的是将ConfigureServices
为使用AddMvcCore()
。 如果查看GitHub存储库 ,可以看到AddMvcCore()
使用一组标准服务/中间件调用AddMvcCore()
:
以下是一些突出显示为“不需要”的服务/中间件:
var builder = services.AddMvcCore(); builder.AddViews(); builder.AddRazorViewEngine(); builder.AddRazorPages();
许多这些默认服务非常适合一般的Web项目,但通常不适合“纯”Web API。
以下是使用AddMvcCore()
为Web API的ConfigureServices
示例实现:
public void ConfigureServices(IServiceCollection services) { // Build a customized MVC implementation, without using the default AddMvc(), // instead use AddMvcCore(). The repository link is below: // https://github.com/aspnet/Mvc/blob/release/2.2/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs services .AddMvcCore(options => { options.RequireHttpsPermanent = true; // this does not affect api requests options.RespectBrowserAcceptHeader = true; // false by default //options.OutputFormatters.RemoveType(); // these two are here to show you where to include custom formatters options.OutputFormatters.Add(new CustomOutputFormatter()); options.InputFormatters.Add(new CustomInputFormatter()); }) //.AddApiExplorer() //.AddAuthorization() .AddFormatterMappings() //.AddCacheTagHelper() //.AddDataAnnotations() //.AddCors() .AddJsonFormatters(); }
上面的实现主要是AddMvc()
扩展方法的副本,但是我添加了一些新的区域,以便其他人可以看到这样做的额外好处。
- 自定义输入/输出格式化程序。 您可以在这里使用自己的高度优化的序列化程序(例如Protobuf,Thrift,Avro等),而不是使用JSON(或更糟糕的XML)序列化。
- 请求标头处理。 您可以确保识别或不识别
Accept
标头。 - 授权处理。 您可以实施自己的自定义授权,也可以利用内置function。
- ApiExplorer。 对于某些项目,您可能会包含它,否则某些WebAPI可能不希望使用此function。
- 跨域请求(CORS)。 如果您在WebAPI上需要更宽松的安全性,则可以启用它。
希望通过这个“纯”解决方案的示例,您可以看到使用AddMvcCore()
的好处并且习惯使用它。
如果您在ASP.NET Core的Web主机上工作时非常认真地控制性能和延迟,那么深入了解“最小”解决方案就是您在请求管道的边缘处理,而不是放弃它被MVC中间件陷入困境。
补充阅读
直观地了解中间件管道的外观……根据我的定义,较少的层意味着“最小”,而“纯”只是MVC的简洁版本。
您可以在Microsoft Documents: ASP.NET Core Middleware Fundamentals上阅读有关它的更多信息