如何使用AddMvcCore()实现一个“纯粹”的ASP.NET Core Web API

39

我看到许多使用默认的AddMvc()服务的ASP.NET Core Web API项目,但并没有意识到使用AddMvcCore()是一种更优选的选择,因为它可以更好地控制服务。

那么,如何使用AddMvcCore()实现ASP.NET Core Web API,并且为什么它更好呢?

1个回答

89

什么是AddMvc()AddMvcCore()之间的区别?

首先要理解的关键是,AddMvc()只是AddMvcCore()的预加载版本。您可以在GitHub存储库中查看AddMvc()扩展的确切实现。

我像其他人一样喜欢使用默认的VS模板,但有时候您需要知道何时选择错误。我已经看到了几个在线指南,这些指南更倾向于尝试“撤消”这些默认服务,而不是选择一个从一开始就不实现它们的解决方案。

随着ASP.NET Core成为开源,我们真的没有理由不能剥离一层并在低级别上工作,而不用担心失去“魔力”。


"Minimal"和"pure"的定义

注意:这些定义仅适用于本回答的上下文中,主要是为了清晰和帮助进一步理解。

本回答更倾向于"pure"而不是"minimal"。我想描述一下原因,以便更清楚地说明我的观点。

Minimal(最小化)。一个"minimal"解决方案是实现中甚至根本不调用AddMvcCore()方法。原因是MVC并不是组装自己的Web API所必需的组件,而且它还会通过额外的依赖项增加代码的负担。在这种情况下,由于您没有使用AddMvcCore()方法,您也不会将其注入到应用程序中,在此处。

public void Configure(IApplicationBuilder app)
{
    app.UseMvc(); // you don't need this
}

这意味着您需要映射自己的路由并以自己的方式响应上下文。这真的不难,但我不想深入探讨,因为这与主题相去甚远,但是这里有一个最小实现的简单示例
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中的一些功能。你需要权衡利弊,看看这种设计路径是否是正确的选择,因为在设计模式、便利性、可维护性、代码占用空间以及最重要的性能和延迟之间存在平衡。简而言之: “最小化”方案意味着将代码和请求之间的服务和中间件最小化。
“纯粹”的解决方案(就本回答的上下文而言)是避免使用“AddMvc()”默认捆绑的所有服务和中间件,而是首先不实现它。相反,我们使用“AddMvcCore()”,这在下一节中有进一步的解释:

使用AddMvcCore()实现自己的服务/中间件

开始第一步是设置ConfigureServices来使用AddMvcCore()。如果您查看GitHub存储库,您会发现AddMvc()使用一组标准的服务/中间件调用了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<HttpNoContentOutputFormatter>();

            // 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标头。
  • 授权处理。您可以实现自己的自定义授权或利用内置功能。
  • ApiExplorer。对于某些项目,您可能会包括它,否则一些WebAPI可能不希望使用此功能。
  • 跨源请求(CORS)。如果您需要在WebAPI上放松安全性,可以启用它。
希望通过这个“纯”解决方案的示例,您可以看到使用AddMvcCore()的好处,并且能够放心地使用它。
如果您对控制性能和延迟很认真,而且正在使用ASP.NET Core的Web主机进行工作,那么深入研究“最小化”解决方案可能是您处理请求管道边缘的地方,而不是让它被MVC中间件拖垮。

额外阅读

一个视觉化的中间件管道是什么样子的... 根据我的定义,更少的层次意味着“最小化”,而“纯粹”只是MVC的干净版本。

enter image description here

您可以在Microsoft文档中了解更多信息: ASP.NET Core中间件基础知识


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接