从 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。

Prerequisites

创建新的 ASP.NET Core Web API 项目

  1. 在“文件”菜单中,选择 “新建>项目”
  2. 在搜索框中输入 Web API
  3. 选择 ASP.NET 核心 Web API 模板,然后选择“下一步”
  4. 配置新项目 对话框中,将项目命名为 ProductsCore,然后选择 下一步
  5. 在“其他信息”对话框中:
    1. 确认 框架.NET 6.0(长期支持)
    2. 确认已选中“使用控制器(取消选中以使用最小 API)”复选框
    3. 取消选中“启用 OpenAPI 支持”
    4. 选择 创建

删除 WeatherForecast 模板文件

  1. 从新的 WeatherForecast.cs 项目中删除 Controllers/WeatherForecastController.cs 示例文件。
  2. 打开属性\launchSettings.json。
  3. 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();

复制 产品 模型

  1. 解决方案资源管理器中,右键单击项目。 选择“添加>新文件夹。 把文件夹命名为 Models
  2. 右键单击 模型 文件夹。 选择添加>。 将类命名为“产品”,然后选择“添加”。
  3. 将模板模型代码替换为以下内容:
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; }
    }
}

上述突出显示的代码将更改以下内容:

  • 添加了 ? 批注,以将 NameCategory 属性声明为可为 null 的引用类型。

通过利用 C# 8 中引入的Nullable 功能,ASP.NET Core 可以在处理引用类型时提供额外的代码流分析和编译时安全性。 例如,防止 null 引用异常。

在这种情况下,意图是 NameCategory 可以是可为空的类型。

在 .NET 6 项目的 ASP.NET Core 中,默认启用可空引用类型。 有关详细信息,请参阅可为空引用类型

复制 ProductsController

  1. 右键单击 控制器 文件夹。
  2. 选择 添加 > 控制器...
  3. 在“添加新基架项”对话框中,选择“Mvc 控制器 - 空”,然后选择“添加”。
  4. 将控制器命名为 ProductsController,然后选择 添加
  5. 将模板控制器代码替换为以下内容:
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 组件的 using 语句:

    • ApiController
    • System.Web.Http 命名空间
    • IHttpActionResult 接口
  • using ProductsApp.Models; 语句更改为 using ProductsCore.Models;

  • 将根命名空间设置为 ProductsCore

  • 更改 ApiControllerControllerBase

  • 添加 using Microsoft.AspNetCore.Mvc; 以解析 ControllerBase 引用。

  • GetProduct 动作的返回类型从 IHttpActionResult 更改为 ActionResult<Product>。 有关详细信息,请参阅 控制器操作的返回类型

  • GetProduct 动作的 return 语句简化为以下语句:

    return product;
    
  • 添加以下属性,这些属性将在下一节中解释:

    • [Route("api/[controller]")]
    • [ApiController]
    • [HttpGet]
    • [HttpGet("{id}")]

Routing

ASP.NET Core 提供最少的托管模型,其中终结点路由中间件包装整个中间件管道,因此可以直接将路由添加到 WebApplication,而无需显式调用 UseEndpointsUseRouting 来注册路由。

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]。 在运行时,每个令牌分别替换为应用了该属性的控制器或操作的名称。 令牌:

    • 减少或消除对路由使用硬编码字符串的需要。
    • 在应用自动重命名重构时,确保路由与相应的控制器和动作保持同步。
  • ProductController 操作启用了具有以下属性的 HTTP Get 请求:

    • [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 所需的步骤。

查看或下载示例代码如何下载

Prerequisites

查看 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 项目以迁移:

  1. 在“文件”菜单中,选择 “新建>项目”
  2. 选择“空白解决方案”模板,然后选择“下一步”。
  3. 将解决方案命名为 WebAPIMigration。 选择 创建
  4. 将现有的 ProductsApp 项目添加到解决方案。

添加新的 API 项目以迁移到:

  1. 将新的 ASP.NET Core Web 应用程序 项目添加到解决方案。
  2. 在“配置新项目”对话框中,将项目命名为 ProductsCore,然后选择“创建 ”。
  3. 在“创建新的 ASP.NET 核心 Web 应用程序 对话框中,确认已选择 .NET CoreASP.NET Core 3.1。 选择“API”项目模板,然后选择“创建” 。
  4. 从新的 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

  1. Controllers/ProductsController.cs模型 文件夹从原始项目复制到新项目。
  2. 将复制文件的根命名空间更改为 ProductsCore
  3. using ProductsApp.Models; 语句更新为 using ProductsCore.Models;

ASP.NET Core 中不存在以下组件:

  • ApiController
  • System.Web.Http 命名空间
  • IHttpActionResult 接口

进行以下更改:

  1. ApiController 更改为 ControllerBase。 添加 using Microsoft.AspNetCore.Mvc; 以解析 ControllerBase 引用。

  2. 删除 using System.Web.Http;

  3. GetProduct 作的返回类型从 IHttpActionResult 修改为 ActionResult<Product>

  4. GetProduct 动作的 return 语句简化为以下内容:

    return product;
    

配置路由

ASP.NET Core API 项目模板包括生成的代码中的终结点路由配置。

以下 UseRoutingUseEndpoints 调用会执行以下操作:

  • 中间件管道中注册路由匹配和终结点执行。
  • 替换 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();
    });
}

按如下所示配置路由:

  1. 使用以下属性标记 ProductsController 类:

    [Route("api/[controller]")]
    [ApiController]
    

    前面的 [Route] 属性配置控制器的属性路由模式。 [ApiController] 属性把属性路由设为此控制器中所有操作的必要条件。

    属性路由支持令牌,例如 [controller][action]。 在运行时,每个令牌分别替换为应用了该属性的控制器或操作的名称。 令牌:

    • 减少项目中的魔法字符串数量。
    • 在应用自动重命名重构时,确保路由与相应的控制器和动作保持同步。
  2. 启用对 ProductsController 操作的 HTTP GET 请求。

    • [HttpGet] 属性应用于 GetAllProducts 操作。
    • [HttpGet("{id}")] 属性应用于 GetProduct 操作。

运行迁移的项目,并浏览到 /api/products。 将显示三个产品的完整列表。 导航至 /api/products/1 。 第一个产品出现了。

其他资源