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

时间:2017-02-21 10:50:59

标签: c# asp.net-core asp.net-core-mvc asp.net-core-webapi

我已经看到很多使用默认AddMvc()服务的ASP.NET Core Web API项目,却没有意识到由于对服务的控制,使用AddMvcCore()是一个更好的选择。

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

1 个答案:

答案 0 :(得分:69)

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

要理解的第一件事是AddMvc()只是AddMvcCore()的预加载版本。您可以在GitHub repository找到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中的一些功能。您真的必须权衡您的选择,看看您的设计路径是否正确,因为在设计模式,便利性,可维护性,代码占用空间以及最重要的性能和延迟之间存在平衡。 简单地说:“最小化”解决方案意味着最大限度地减少代码与请求之间的服务和中间件。

纯粹。“纯粹”的解决方案(就此答案的上下文而言)是避免所有与AddMvc()“预先捆绑”的默认服务和中间件首先没有实现它。相反,我们使用AddMvcCore(),这将在下一节进一步解释:

使用AddMvcCore()

实现我们自己的服务/中间件

首先要开始使用ConfigureServices设置AddMvcCore()。如果您查看GitHub repository,可以看到AddMvc()使用一组标准服务/中间件调用AddMvcCore()

以下是一些突出显示为“不需要”的服务/中间件:

var builder = services.AddMvcCore();

builder.AddViews();
builder.AddRazorViewEngine();
builder.AddRazorPages();

这些默认服务中的许多都适用于一般的Web项目,但通常不适用于“纯”Web API。

以下是ConfigureServices使用AddMvcCore()进行Web API的示例实现:

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)序列化。 / LI>
  • 请求标头处理。您可以确保识别Accept标头。
  • 授权处理。您可以实施自己的自定义授权,也可以利用内置功能。<​​/ li>
  • ApiExplorer。对于某些项目,您可能会包含它,否则某些WebAPI可能不想使用此功能。
  • 跨域请求(CORS)。如果您需要在WebAPI上获得更宽松的安全性,则可以启用它。

希望通过这个“纯粹”解决方案的示例,您可以看到使用AddMvcCore()的好处并且习惯使用它。

如果您在ASP.NET Core的Web主机上工作时非常认真地控制性能和延迟,那么深入了解“最小”解决方案就是您在请求管道的边缘处理,而不是让它被MVC中间件陷入困境。

补充阅读

直观地了解中间件管道的外观......根据我的定义,较少的层意味着“最小”,而“纯”只是MVC的简洁版本。

enter image description here

您可以在Microsoft文档中详细了解它:ASP.NET Core Middleware Fundamentals