前言 :本篇文章,我将会介绍如何在不包括MVC / Razor功能和包的情况下,添加最少的依赖项到ASP.NET Core Web API项目中。
一、MVC VS WebApi
(1)在ASP.NET的早期版本中,MVC和Web API技术栈是完全分开的。 尽管它们之间共享了许多相似的概念,但实际类型却截然不同。 这通常有点尴尬,当您意外引用错误的命名空间时,通常会导致错误。
(2)在ASP.NET Core中,这不再是个问题:MVC和Web API已统一,其中MVC中的控制器和Web API中的控制器之间基本上没有真正的区别。 您所有的控制器都可以充当MVC控制器,也可以充当Web API控制器,以返回格式化(例如JSON或XML)数据。
(3)话虽如此,如果您只需要使用Web API功能,那么您可能就不需要MVC功能。 但是,当前默认模板中却默认包含了MVC的功能。
二、默认模板
当您从Visual Studio中的模板或通过命令行创建新的MVC项目时,可以选择创建空的ASP.NET Core项目,Web API项目还是MVC Web应用程序项目。如果您创建一个“空”项目,那么生成的应用程序实际上是超轻量级的。 它不依赖于任何MVC构造,并且在运行时仅产生一个非常简单的“ Hello World”响应:
另一方面,如果你选择了“ MVC Web app”模板的话,该模板会为您提供了更“完善”的应用。 如果您选择了身份验证选项,除了所有MVC配置和Razor视图模板外,它还可以包括ASP.NET Core Identity,EF Core和SQL Server集成:
如果你选择了WebApi模板的话,会创建WebApi 应用并且包含一些必须的MVC依赖项,最简单的版本就包含了一个ValuesController。
但是,虽然看起来很简单,但它也添加了用于创建完整MVC应用程序所有必需依赖包,即服务器端Razor依赖包。 这是因为它包含与整个MVC Web应用程序相同的Microsoft.AspNetCore.Mvc程序包,并在Startup.ConfigureServices中调用AddMvc()。如下图所示:
AddMvc()将会向服务容器中添加一堆各种服务, 其中一些是允许您使用Web API所必需的,但其中一些(尤其是与Razor相关的服务)对于Web API而言是不必要的。
在大多数情况下,使用Microsoft.AspNetCore.Mvc包是最容易的事情,但是有时您希望尽可能地减少依赖关系,并尽可能地减轻API的负担。 在这些场景下,您可能会发现仅专门添加应用程序所需的MVC软件包和服务会很有用。
三、添加依赖包的正确姿势
我们将从“空” Web应用程序模板开始,然后向其中添加Web API所需的包。您需要那些软件包将取决于您应用程序所需的功能。 默认情况下,Empty ASP.NET Core模板包括ApplicationInsights和Microsoft.AspNetCore元数据包,因此我将其留在项目中。
在这些之上,我将添加MVC.Core包,JSON格式化程序包和CORS包:
- MVC Core软件包添加了所有必需的MVC类型,例如ControllerBase和RouteAttribute,以及许多依赖项,例如Microsoft.AspNetCore.Mvc.Abstractions和Microsoft.AspNetCore.Authorization。
- JSON格式化程序包确保我们可以实际呈现Web API操作结果
- CORS软件包增加了跨源资源共享(CORS)支持-这是Web API常见的要求,该Web API将托管在调用它们的客户端不同的域中。
最终的.csproj文件应如下所示:
为了方便我练习我贴出文字版的项目文件:
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>netcoreapp2.1</TargetFramework> </PropertyGroup> <ItemGroup> <Folder Include="wwwroot" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.ApplicationInsights.AspNetCore" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Cors" Version="2.1.0" /> <PackageReference Include="Microsoft.AspNetCore.Mvc.Formatters.Json" Version="2.1.0" /> </ItemGroup> </Project>
还原完软件包后,现在我们就 可以更新Startup文件来添加我们的WebApi服务了.
四、在 Startup.cs文件中添加我们必须的服务
在大多数情况下,将Web API服务添加到项目中就像在ConfigureServices方法中调用AddMvc()一样简单。 但是,该方法增加了我们不需要的一些依赖项。 默认情况下,它将添加ApiExplorer,Razor视图引擎,Razor views,TagHelpers和DataAnnotations-目前我们都没有使用(如果后面用到了我们稍后再添加ApiExplorer和DataAnnotations都是可以的),但现在我们不需要。相反,我们只需要添加一下服务:
public void ConfigureServices(IServiceCollection services) { var builder = services.AddMvcCore(); builder.AddAuthorization(); builder.AddFormatterMappings(); builder.AddJsonFormatters(); builder.AddCors(); }
这就是我们需要的服务,好了,现在我们在添加所需要的中间件。
五、添加中间件
将MvcMiddleware添加到管道很简单。 我们只需要用UseMvc()替换了运行“ Hello World”中间件就行了。但是, 请注意,我们使用的是该方法的非参数化版本,该版本没有向该应用程序添加任何常规路由。 由于这是一个Web API,因此我将仅使用属性路由,因此无需设置常规路由。
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //if (env.IsDevelopment()) //{ // app.UseDeveloperExceptionPage(); //} //app.Run(async (context) => //{ // await context.Response.WriteAsync("Hello World!"); //}); loggerFactory.AddConsole(); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseMvc(); }
这些就是我们所需要的MVC配置,最后,我们再来创建一个控制器,来看看是否能正确运行。
六、添加一个 MVC控制器
以这种方式创建Web API时需要注意的一个重要点就是:您必须使用ControllerBase类作为所有Controller的父类,而不是Controller。 后者在Microsoft.AspNetCore.Mvc程序包中已经定义但是我们没有添加。 幸运的是,它主要包含与渲染Razor有关的方法,因此这对我们来说不是问题。 ControllerBase类包含您可能会使用的所有各种StatusCodeResult帮助方法,例如下面的代码:
[Route("api/[controller]")] public class ValuesController:ControllerBase { // GET api/values [HttpGet] public IActionResult Get() { return Ok(new string[] { "value1", "value2" }); } }
运行结果如下:
瞧! 这就是精简的Web API控制器,具有最小的依赖项。
七、扩展:AddWebApi扩展方法
最后梳理一下-我们的ConfigureServices方法看起来有点乱。 在这种方法中,我们可以通过创建一个扩展方法来减少Startup.cs类中的混乱情况,代码如下:
using System; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Internal; // ReSharper disable once CheckNamespace namespace Microsoft.Extensions.DependencyInjection { public static class WebApiServiceCollectionExtensions { /// <summary> /// Adds MVC services to the specified <see cref="IServiceCollection" /> for Web API. /// This is a slimmed down version of <see cref="MvcServiceCollectionExtensions.AddMvc"/> /// </summary> /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param> /// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns> public static IMvcBuilder AddWebApi(this IServiceCollection services) { if (services == null) throw new ArgumentNullException(nameof(services)); var builder = services.AddMvcCore(); builder.AddAuthorization(); builder.AddFormatterMappings(); // +10 order builder.AddJsonFormatters(); builder.AddCors(); return new MvcBuilder(builder.Services, builder.PartManager); } /// <summary> /// Adds MVC services to the specified <see cref="IServiceCollection" /> for Web API. /// This is a slimmed down version of <see cref="MvcServiceCollectionExtensions.AddMvc"/> /// </summary> /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param> /// <param name="setupAction">An <see cref="Action{MvcOptions}"/> to configure the provided <see cref="MvcOptions"/>.</param> /// <returns>An <see cref="IMvcBuilder"/> that can be used to further configure the MVC services.</returns> public static IMvcBuilder AddWebApi(this IServiceCollection services, Action<MvcOptions> setupAction) { if (services == null) throw new ArgumentNullException(nameof(services)); if (setupAction == null) throw new ArgumentNullException(nameof(setupAction)); var builder = services.AddWebApi(); builder.Services.Configure(setupAction); return builder; } } }
最后,我们可以使用此扩展方法来整理我们的ConfigureServices方法:
public void ConfigureServices(IServiceCollection services) { services.AddWebApi(); }
这下看起来就清爽多了。
八、总结:
这篇文章展示了当您知道不需要Razor依赖时,如何从应用程序中移除它们。 这几乎使我们能在应用程序中使用的最小化的Web API。 我知道方法可能会有很多,但是,添加额外的功能(例如ApiExplorer)却很容易!好了,今天就聊到这里。幸运的是,Net Core 3.0 中已经为我们做了这些工作,如果不了解的可以参考我以前的文章,也可以查看源码。
作者:郭峥
出处:http://www.cnblogs.com/runningsmallguo/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。