从 ASP.NET Web API 迁移到 ASP.NET Core
ASP.NET Core 将 ASP.NET 4.x 的 MVC 和 Web API 应用模型组合到被称为 ASP.NET Core MVC 的单一编程模型中。
本文介绍如何使用在 ASP.NET Web API 2 入门中创建的产品控制器迁移到 ASP.NET Core。
先决条件
- 带有 ASP.NET 和 Web 开发工作负载的 Visual Studio 2022。
- .NET 6.0 SDK
创建新的 ASP.NET Core Web API 项目
- 从“文件”菜单中选择“新建”>“项目” 。
- 在搜索框中输入“Web API”。
- 选择“ASP.NET Core Web API”模板,然后选择“下一步”。
- 在“配置新项目”对话框中,将项目命名为 ProductsCore,然后选择“下一步”。
- 在“其他信息”对话框中:
- 确认“框架”为“.NET 6.0 (长期支持)”。
- 确认已选中“使用控制器(取消选中以使用最小 API)”。
- 取消选中“启用 OpenAPI 支持”。
- 选择“创建”。
删除 WeatherForecast 模板文件
- 从新的 ProductsCore 项目中删除
WeatherForecast.cs
和Controllers/WeatherForecastController.cs
示例文件。 - 打开 Properties\launchSettings.json。
- 将
launchUrl
属性从weatherforcast
更改为productscore
。
ASP.NET Core Web API 的配置
ASP.NET Core 不使用 App_Start 文件夹或 Global.asax 文件。 web.config 文件是在发布时添加的。 有关详细信息,请参阅 web.config 文件。
Program.cs
文件:
- 替换 Global.asax。
- 处理所有应用启动任务。
有关详细信息,请参阅 ASP.NET Core 中的应用启动。
下面显示了 ASP.NET Core Program.cs
文件中的应用程序启动代码:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
复制产品模型
- 在“解决方案资源管理器”中,右键单击项目。 选择“添加”>“新建文件夹”。 将文件夹命名为“Models”。
- 右键单击“Models”文件夹。 选择“添加”>“类” 。 将类命名为“产品”,然后选择“添加”。
- 将模板模型代码替换为以下内容:
namespace ProductsCore.Models
{
public class Product
{
public int Id { get; set; }
public string? Name { get; set; }
public string? Category { get; set; }
public decimal Price { get; set; }
}
}
前面突出显示的代码更改以下内容:
- 添加
?
注释以将Name
和Category
属性声明为可为空引用类型。
通过利用 C#8 中引入的可为空功能,ASP.NET Core 可以在处理引用类型时提供额外的代码流分析和编译时安全性。 例如,防止 null
引用异常。
在本例中,意向是 Name
,Category
可以是可为空类型。
ASP.NET Core 6.0 项目默认启用可为空引用类型。 有关详细信息,请参阅可为空引用类型。
复制 ProductsController
- 右键单击 Controllers 文件夹。
- 选择“添加 > 控制器...”。
- 在“添加新基架项”对话框中,选择“Mvc 控制器 - 空”,然后选择“添加”。
- 将控制器命名为 ProductsController,然后选择“添加”。
- 将模板控制器代码替换为以下内容:
using Microsoft.AspNetCore.Mvc;
using ProductsCore.Models;
namespace ProductsCore.Controllers;
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
Product[] products = new Product[]
{
new Product
{
Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1
},
new Product
{
Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M
},
new Product
{
Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M
}
};
[HttpGet]
public IEnumerable<Product> GetAllProducts()
{
return products;
}
[HttpGet("{id}")]
public ActionResult<Product> GetProduct(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
return NotFound();
}
return product;
}
}
前面突出显示的代码会更改以下内容,以迁移到 ASP.NET Core:
使用语句删除 ASP.NET Core 中不存在的以下 ASP.NET 4.x 组件:
ApiController
类System.Web.Http
命名空间IHttpActionResult
接口
将
using ProductsApp.Models;
语句更改为using ProductsCore.Models;
。将根命名空间设置为
ProductsCore
。将
ApiController
更改为 ControllerBase。添加
using Microsoft.AspNetCore.Mvc;
来解析ControllerBase
引用。将
GetProduct
操作的返回类型从IHttpActionResult
更改为ActionResult<Product>
。 有关详细信息,请参阅控制器操作返回类型。将
GetProduct
操作的return
语句简化为以下语句:return product;
添加以下属性,这些属性将在后续部分进行介绍:
[Route("api/[controller]")]
[ApiController]
[HttpGet]
[HttpGet("{id}")]
路由
ASP.NET Core 提供了一个最小托管模型,其中终结点路由中间件包装整个中间件管道,因此可以直接将路由添加到 WebApplication,而无需显式调用 UseEndpoints 或 UseRouting 来注册路由。
UseRouting
仍可用于指定进行路由匹配的位置,但如果应在中间件管道开头匹配路由,则无需显式调用 UseRouting
。
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
注意:直接添加到 WebApplication 的路由在管道的末端执行。
迁移的 ProductsController
中的路由
迁移的 ProductsController
包含以下突出显示的属性:
using Microsoft.AspNetCore.Mvc;
using ProductsCore.Models;
namespace ProductsCore.Controllers;
[Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
Product[] products = new Product[]
{
new Product
{
Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1
},
new Product
{
Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M
},
new Product
{
Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M
}
};
[HttpGet]
public IEnumerable<Product> GetAllProducts()
{
return products;
}
[HttpGet("{id}")]
public ActionResult<Product> GetProduct(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
return NotFound();
}
return product;
}
}
[Route]
属性配置控制器的属性路由模式。[ApiController]
属性使得此控制器中所有操作都必须使用属性路由。属性路由支持令牌,例如
[controller]
和[action]
。 在运行时,每个标记分别替换为应用了属性的控制器或操作的名称。 令牌执行以下操作:- 减少或消除对路由使用硬编码字符串的需求。
- 应用自动重命名重构时,请确保路由与相应的控制器和操作保持同步。
HTTP Get 请求为具有以下属性的
ProductController
操作启用:[HttpGet]
属性应用于GetAllProducts
操作。[HttpGet("{id}")]
属性应用于GetProduct
操作。
运行迁移的项目,并浏览到 /api/products
。 例如:https://localhost:<port>
/api/products。 这会显示包含三个产品的完整列表。 浏览到 /api/products/1
。 此时显示第一个产品。
其他资源
本文演示从 ASP.NET 4.x Web API 迁移到 ASP.NET Core MVC 所需的步骤。
先决条件
- 具有“ASP.NET 和 Web 开发”工作负载的 Visual Studio 2019 16.4 或更高版本
- .NET Core 3.1 SDK
查看 ASP.NET 4.x Web API 项目
本文使用在 ASP.NET Web API 2 入门中创建的 ProductsApp 项目。 在该项目中,按如下方式配置基本 ASP.NET 4.x Web API 项目。
在 Global.asax.cs
中,对 WebApiConfig.Register
进行调用:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Routing;
namespace ProductsApp
{
public class WebApiApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
GlobalConfiguration.Configure(WebApiConfig.Register);
}
}
}
WebApiConfig
类位于 App_Start 文件夹中,具有一个静态 Register
方法:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
namespace ProductsApp
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
}
上述类会执行以下操作:
- 配置属性路由(虽然实际上并没有使用它)。
- 配置路由表。
示例代码要求 URL 匹配格式
/api/{controller}/{id}
,其中{id}
是可选的。
以下部分演示了如何将 Web API 项目迁移到 ASP.NET Core MVC。
创建目标项目
在 Visual Studio 中创建新的空白解决方案,并添加 ASP.NET 4.x Web API 项目进行迁移:
- 从“文件”菜单中选择“新建”>“项目” 。
- 选择“空白解决方案”模板,然后选择“下一步”。
- 将解决方案命名为 WebAPIMigration。 选择“创建”。
- 将现有的 ProductsApp 项目添加到解决方案。
添加要迁移到的新 API 项目:
- 将新的“ASP.NET Core Web 应用程序”项目添加到解决方案中。
- 在“配置新项目”对话框中,将项目命名为 ProductsCore,然后选择“创建”。
- 在“创建新的 ASP.NET Core Web 应用程序”对话框中,确认选择“.NET Core”和“ASP.NET Core 3.1” 。 选择“API”项目模板,然后选择“创建” 。
- 从新的 ProductsCore 项目中删除
WeatherForecast.cs
和Controllers/WeatherForecastController.cs
示例文件。
解决方案包含两个项目。 以下部分介绍了如何将 ProductsApp 项目的内容迁移到 ProductsCore 项目。
迁移配置
ASP.NET Core 不使用 App_Start 文件夹或 Global.asax 文件。 此外,还会在发布时添加 web.config 文件。
Startup
类:
- 替换 Global.asax。
- 处理所有应用启动任务。
有关详细信息,请参阅 ASP.NET Core 中的应用启动。
迁移模型和控制器
下面的代码演示了要为 ASP.NET Core 更新的 ProductsController
:
using ProductsApp.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Web.Http;
namespace ProductsApp.Controllers
{
public class ProductsController : ApiController
{
Product[] products = new Product[]
{
new Product
{
Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1
},
new Product
{
Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M
},
new Product
{
Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M
}
};
public IEnumerable<Product> GetAllProducts()
{
return products;
}
public IHttpActionResult GetProduct(int id)
{
var product = products.FirstOrDefault((p) => p.Id == id);
if (product == null)
{
return NotFound();
}
return Ok(product);
}
}
}
更新 ASP.NET Core 的 ProductsController
:
- 将
Controllers/ProductsController.cs
和 Models 文件夹从原始项目复制到新项目。 - 将复制的文件的根命名空间更改为
ProductsCore
。 - 将
using ProductsApp.Models;
语句更新为using ProductsCore.Models;
。
ASP.NET Core 中不存在下列组件:
ApiController
类System.Web.Http
命名空间IHttpActionResult
接口
进行以下更改:
将
ApiController
更改为 ControllerBase。 添加using Microsoft.AspNetCore.Mvc;
来解析ControllerBase
引用。删除
using System.Web.Http;
。将
GetProduct
操作的返回类型从IHttpActionResult
更改为ActionResult<Product>
。将
GetProduct
操作的return
语句简化为如下内容:return product;
配置路由
ASP.NET Core API 项目模板在生成的代码中包含终结点路由配置。
以下 UseRouting 和 UseEndpoints 调用会执行以下操作:
- 在中间件管道中注册路由匹配和终结点执行。
- 替换 ProductsApp 项目的
App_Start/WebApiConfig.cs
文件。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
按如下所示配置路由:
使用以下属性标记
ProductsController
类:[Route("api/[controller]")] [ApiController]
上述
[Route]
属性会配置控制器的属性路由模式。[ApiController]
属性使得此控制器中所有操作都必须使用属性路由。属性路由支持标记,例如
[controller]
和[action]
。 在运行时,每个标记分别替换为应用了属性的控制器或操作的名称。 令牌执行以下操作:- 减少项目中的魔幻字符串的数量。
- 应用自动重命名重构时,请确保路由与相应的控制器和操作保持同步。
启用对
ProductsController
操作的 HTTP Get 请求:- 将
[HttpGet]
属性应用于GetAllProducts
操作。 - 将
[HttpGet("{id}")]
属性应用于GetProduct
操作。
- 将
运行迁移的项目,并浏览到 /api/products
。 这会显示包含三个产品的完整列表。 浏览到 /api/products/1
。 此时显示第一个产品。