引言
在当今数字化时代,Webapi 开发已然成为现代应用开发的关键环节。它作为连接前端与后端服务的桥梁,使得不同系统之间能够高效地进行数据交互与通信。无论是构建移动端应用、Web 应用,还是开发企业级的分布式系统,Webapi 都发挥着不可或缺的作用。
传统的 Webapi 开发过程往往较为繁琐,需要开发者处理众多的基础配置、依赖注入、路由设置等问题,这不仅耗费大量的时间和精力,还容易引入人为错误,影响开发效率和项目进度。而 Furion 框架的出现,为这一困境带来了全新的解决方案。
Furion 是一个基于.NET Core 的轻量级、高性能的开发框架,它致力于简化 Webapi 开发流程,让开发者能够更专注于业务逻辑的实现,极大地提高开发效率。它具有丰富的功能特性,如强大的依赖注入容器、灵活的 AOP(面向切面编程)机制、便捷的数据库访问组件、自动化的代码生成工具等,这些特性使得开发者可以用更少的代码实现更多的功能,减少重复劳动,提升项目的整体质量。
在接下来的内容中,我们将深入探讨如何使用 Furion 快速实现 Webapi,从环境搭建到项目实战,一步步带你领略 Furion 框架的魅力与强大之处,让你在 Webapi 开发的道路上如虎添翼。
认识 Furion
什么是 Furion
Furion 是一个基于.NET Core 的通用开发框架,它为开发者提供了丰富的功能和便捷的开发体验。该框架的设计目标是简化开发流程,提高开发效率,让开发者能够更专注于业务逻辑的实现。
Furion 具有许多强大的特性。它拥有丰富的扩展,这些扩展涵盖了日志记录、缓存管理、身份验证、授权等多个方面,开发者可以根据项目需求轻松引入所需的扩展,避免了重复造轮子。例如,在日志记录方面,Furion 集成了常用的日志框架,只需简单配置,就能实现高效的日志记录功能,方便开发者对系统运行状态进行监控和调试。
依赖注入是 Furion 的另一大核心特性。它提供了强大的依赖注入容器,支持多种生命周期的服务注册,如瞬态(Transient)、作用域(Scoped)和单例(Singleton)。通过依赖注入,开发者可以将对象的创建和管理交给框架,实现解耦和可测试性。以一个简单的用户服务为例,我们可以将用户数据访问层的依赖通过依赖注入的方式注入到用户服务中,这样在测试用户服务时,就可以方便地替换掉真实的数据访问层,使用模拟数据进行测试,大大提高了代码的可测试性。
动态 API 是 Furion 的一大亮点。它可以根据定义的接口自动生成 API,无需编写繁琐的控制器代码。这一特性极大地减少了样板代码的编写量,提高了开发效率。比如,我们定义一个简单的接口,用于获取用户信息,Furion 会自动为这个接口生成对应的 API 端点,并且支持常见的 HTTP 方法,如 GET、POST、PUT、DELETE 等,使得接口开发变得更加简单快捷。
为什么选择 Furion 开发 Webapi
与其他常见的 Webapi 开发框架相比,Furion 在多个方面展现出明显的优势。
在开发效率方面,Furion 的丰富扩展和动态 API 等特性使得开发过程更加高效。以传统的ASP.NET Core 开发 Webapi 为例,开发者需要手动编写大量的控制器代码、配置路由等,而使用 Furion,通过动态 API 功能,只需定义接口,就能快速生成 API,大大节省了开发时间。在一个中等规模的项目中,使用 Furion 开发 Webapi,开发周期可能会缩短 20% - 30%。
代码简洁性上,Furion 的依赖注入和 AOP(面向切面编程)机制让代码更加简洁和易读。AOP 机制可以将一些横切关注点,如日志记录、性能监控、事务处理等,从业务逻辑中分离出来,以切面的方式进行统一处理。例如,在进行数据库操作时,使用 Furion 的 AOP 机制,可以轻松地在方法执行前后添加事务处理逻辑,而无需在每个业务方法中重复编写事务相关代码,使业务代码更加专注于核心逻辑,提高了代码的可读性和维护性。
从可维护性角度看,Furion 采用了分层架构和模块化设计,各个模块之间职责清晰,依赖关系明确。这使得项目在后期维护和扩展时更加容易。当项目需要添加新功能时,只需在相应的模块中进行扩展,而不会对其他模块造成过多影响。例如,当需要添加新的业务逻辑时,只需在业务逻辑层进行开发,而不会影响到数据访问层和表示层的代码,降低了维护成本和风险。
环境搭建
准备工作
在开始使用 Furion 开发 Webapi 之前,我们需要先搭建好开发环境,准备好所需的软件和工具。
首先,要安装.NET Core SDK。它是开发.NET Core 应用程序的基础,提供了编译、运行和调试.NET Core 项目所需的工具和库。你可以前往.NET 官方下载页面,根据你的操作系统(如 Windows、macOS 或 Linux)选择对应的版本进行下载。下载完成后,运行安装程序,按照提示完成安装。安装完成后,打开命令行工具,输入dotnet --info,如果能正确显示出.NET Core SDK 的版本信息等内容,说明安装成功。
其次,选择一款合适的代码编辑器。这里推荐使用 Visual Studio,它是一款功能强大的集成开发环境(IDE),为.NET 开发提供了丰富的功能和便捷的操作体验,如代码智能提示、调试工具、项目管理等。你可以从Visual Studio 官方下载页面下载并安装。下载时,根据你的需求选择合适的版本,如社区版(免费,适合个人开发者和小型团队)、专业版或企业版。安装过程中,可以根据提示选择需要安装的组件,建议保持默认选择,以确保安装完整的功能。
创建 Furion 项目
环境搭建完成后,就可以开始创建 Furion 项目了。这里介绍两种常见的创建方式:使用命令行工具和使用 Visual Studio。
使用命令行工具创建 Furion 项目:
- 打开命令行工具(如 Windows 的 CMD 或 PowerShell,macOS 和 Linux 的终端)。
- 安装 Furion 项目模板。在命令行中输入以下命令来安装 Furion 的 WebApi 项目模板:
dotnet new install Furion.Template.Api
这个命令会从 NuGet 源下载并安装最新版本的 Furion WebApi 项目模板。如果需要安装指定版本的模板,可以在模板名称后加上版本号,例如dotnet new install Furion.Template.Api::3.2.2 。
- 创建项目。安装完成后,使用以下命令创建一个新的 Furion 项目,假设项目名为 “MyFurionWebApi”:
dotnet new furionapi -n MyFurionWebApi
这里的furionapi是 Furion WebApi 项目模板的关键词,-n参数用于指定项目名称。执行该命令后,会在当前目录下创建一个名为 “MyFurionWebApi” 的项目文件夹,里面包含了 Furion 项目的基本结构和文件。
使用 Visual Studio 创建 Furion 项目:
- 打开 Visual Studio。
- 点击 “创建新项目”。在弹出的 “创建新项目” 窗口中,在搜索框中输入 “Furion”,然后选择 “Furion WebAPI 模板”,点击 “下一步”。
- 在 “配置新项目” 页面,设置项目名称和保存位置,然后点击 “创建”。Visual Studio 会根据 Furion 模板创建一个新的项目,并自动安装所需的依赖包。
无论是使用命令行工具还是 Visual Studio 创建项目,创建完成后,项目结构通常包含以下几个主要部分:
- Web.Entry:这是项目的入口,包含了程序的启动代码和配置,负责初始化应用程序、配置中间件、注册服务等。
- Application:用于存放应用程序的业务逻辑,定义各种服务接口和实现,处理业务流程和规则。
- Core:存放核心的业务逻辑和实体类,包含一些通用的方法、常量、枚举等,是整个项目的核心部分。
- Database.Migrations:如果使用数据库迁移功能,该项目用于管理数据库的迁移脚本,记录数据库结构的变更历史,确保数据库结构与应用程序的实体模型保持一致。
- EntityFramework.Core:如果使用 Entity Framework Core 作为数据访问技术,该项目用于配置和管理数据库上下文,定义与数据库的交互逻辑,实现数据的增删改查操作。
在创建项目后,还需要确保项目中安装了 Furion 相关的依赖包。可以通过 NuGet 包管理器来查看和管理依赖包。在 Visual Studio 中,右键点击项目,选择 “管理 NuGet 程序包”,在 NuGet 包管理器中搜索 “Furion”,确保安装了最新版本的 Furion 包以及其他相关的依赖包。如果是使用命令行创建的项目,也可以通过在项目目录下执行dotnet restore命令来恢复项目所需的依赖包,确保项目能够正常运行。
配置与基础设定
配置文件详解
在 Furion 项目中,appsettings.json是一个至关重要的配置文件,它用于集中管理应用程序的各种配置信息,使得我们能够方便地对应用进行定制和调整。
appsettings.json的基本结构采用 JSON 格式,以键值对的形式组织数据。例如,一个典型的appsettings.json文件可能包含如下内容:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"DefaultConnection": "Server=yourServer;Database=yourDatabase;User ID=yourUser;Password=yourPassword;Trusted_Connection=False;MultipleActiveResultSets=true"
}
}
在这个示例中,Logging节点用于配置日志相关的设置。其中,LogLevel子节点定义了不同类型日志的输出级别,如Default表示默认的日志级别为Information,这意味着在应用运行时,会记录信息级别及以上(如Warning、Error等)的日志;Microsoft表示针对Microsoft相关组件的日志级别为Warning,即只记录警告级别及以上的日志;Microsoft.Hosting.Lifetime则专门针对Microsoft.Hosting.Lifetime组件设置日志级别为Information。
AllowedHosts用于指定允许访问应用程序的主机地址。这里设置为*,表示允许任何主机访问。在实际生产环境中,建议根据实际情况进行更严格的限制,以提高应用的安全性。
ConnectionStrings节点则用于配置数据库连接字符串。DefaultConnection是一个自定义的连接字符串名称,其对应的值是一个完整的数据库连接信息,包括服务器地址(Server)、数据库名称(Database)、用户名(User ID)、密码(Password)等。通过这个连接字符串,应用程序可以与数据库建立连接,进行数据的读写操作。
除了这些常见的配置项,appsettings.json还可以根据项目的具体需求添加其他自定义的配置节点。例如,我们可以添加一个AppSettings节点,用于存放应用程序特有的配置信息:
{
"AppSettings": {
"AppName": "MyFurionApp",
"Version": "1.0.0",
"EnableFeatureX": true
},
// 其他配置项...
}
在代码中读取appsettings.json中的配置信息也非常简单。可以通过依赖注入的方式获取IConfiguration接口,然后使用它来读取配置值。例如,在一个控制器中读取AppSettings节点下的AppName配置项:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
namespace MyFurionWebApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class HomeController : ControllerBase
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration configuration)
{
_configuration = configuration;
}
[HttpGet]
public IActionResult GetAppName()
{
string appName = _configuration["AppSettings:AppName"];
return Ok($"App Name: {appName}");
}
}
}
此外,Furion 还支持根据不同的环境加载不同的配置文件。例如,在开发环境下,可以创建一个appsettings.Development.json文件,用于存放开发环境特有的配置,这些配置会覆盖appsettings.json中的相同配置项,从而实现环境差异化配置。
依赖注入与服务注册
依赖注入(Dependency Injection,简称 DI)是 Furion 框架中的一个核心概念,它是一种软件设计模式,旨在将对象的创建和依赖关系的管理从对象内部转移到外部容器中,从而实现对象之间的解耦,提高代码的可维护性和可测试性。
在 Furion 中,依赖注入的实现基于.NET Core 的内置依赖注入容器,并进行了进一步的扩展和增强。通过依赖注入,我们可以将一个对象所依赖的其他对象(即依赖项)通过构造函数、属性或方法参数的方式注入到该对象中,而不是在对象内部直接创建依赖项。
例如,假设我们有一个服务接口IUserService,用于处理用户相关的业务逻辑,以及它的实现类UserService:
public interface IUserService
{
string GetUserName(int userId);
}
public class UserService : IUserService
{
public string GetUserName(int userId)
{
// 实际的业务逻辑,例如从数据库中查询用户信息
return $"User_{userId}";
}
}
在传统的开发方式中,如果我们需要在另一个类中使用UserService,通常会在该类内部直接创建UserService的实例:
public class HomeController : ControllerBase
{
[HttpGet]
public IActionResult GetUserName()
{
var userService = new UserService();
string name = userService.GetUserName(1);
return Ok($"User Name: {name}");
}
}
这种方式会导致HomeController与UserService之间存在紧密的耦合关系,当UserService的实现发生变化,或者需要替换为其他实现时,HomeController的代码也需要相应地修改。而且,在进行单元测试时,很难对HomeController进行独立测试,因为它依赖于具体的UserService实现。
而使用依赖注入,我们可以将UserService的创建和管理交给 Furion 的依赖注入容器。首先,需要在Startup类(或使用AppStartup的方式)中注册UserService:
using Furion.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<IUserService, UserService>();
}
}
这里使用services.AddScoped<IUserService, UserService>()方法将IUserService接口和它的实现类UserService进行注册,并指定其生命周期为Scoped。Scoped生命周期表示在同一个 HTTP 请求中,每次获取到的IUserService实例都是相同的;不同的 HTTP 请求会获取到不同的实例。Furion 还支持其他生命周期,如Transient(瞬态,每次获取都会创建一个新的实例)和Singleton(单例,整个应用程序中只有一个实例)。
注册完成后,在需要使用IUserService的地方,通过构造函数注入的方式获取实例:
public class HomeController : ControllerBase
{
private readonly IUserService _userService;
public HomeController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
public IActionResult GetUserName()
{
string name = _userService.GetUserName(1);
return Ok($"User Name: {name}");
}
}
这样,HomeController只依赖于IUserService接口,而不依赖于具体的实现类UserService。当需要更换UserService的实现时,只需要在注册服务的地方进行修改,而HomeController的代码无需变动,大大提高了代码的灵活性和可维护性。同时,在进行单元测试时,可以很方便地使用模拟对象(如 Moq 库)来替换IUserService的实际实现,从而对HomeController进行独立测试,提高测试的准确性和效率。
构建 Webapi
创建控制器
在 Furion 中,创建控制器是构建 Webapi 的重要一步,它主要包含传统的 MVC 控制器和独具特色的动态 API 控制器这两种类型,它们各自有着不同的使用场景和优势。
传统 MVC 控制器:
传统的 MVC 控制器在 Furion 中依然遵循着ASP.NET Core 的基本规范。创建时,我们需要创建一个继承自ControllerBase的类。例如,要创建一个用于管理用户信息的UserController,代码如下:
using Microsoft.AspNetCore.Mvc;
namespace MyFurionWebApi.Controllers
{
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
// 控制器方法将在这里定义
}
}
在这个示例中,[ApiController]特性用于标识该类是一个 API 控制器,它会启用一些与 API 相关的特性,如自动模型验证和问题详情的返回。[Route("[controller]")]特性则用于定义路由模板,这里的[controller]会被替换为控制器类名去掉 “Controller” 后缀后的部分,即 “User”,所以该控制器的基础路由为 “/User” 。
传统 MVC 控制器适用于一些需要复杂业务逻辑处理和视图渲染(虽然在 Webapi 中较少用到视图渲染,但在某些混合场景下可能会用到)的场景。它的优势在于代码结构清晰,符合传统的 MVC 开发模式,开发者容易上手,并且对于一些需要进行复杂的请求处理和响应格式化的情况,能够提供更灵活的控制。
动态 API 控制器:
动态 API 控制器是 Furion 的一大特色功能,它能极大地简化控制器的创建过程。创建动态 API 控制器有两种方式,一种是实现IDynamicApiController接口,另一种是使用[DynamicApiController]特性。
以实现IDynamicApiController接口为例,创建一个ProductService类作为动态 API 控制器:
using Furion.DynamicApiController;
namespace MyFurionWebApi.Application
{
public class ProductService : IDynamicApiController
{
public string GetProductName(int productId)
{
// 模拟获取产品名称的业务逻辑
return $"Product_{productId}";
}
}
}
使用[DynamicApiController]特性的方式类似:
using Furion.DynamicApiController;
namespace MyFurionWebApi.Application
{
[DynamicApiController]
public class OrderService
{
public string GetOrderStatus(int orderId)
{
// 模拟获取订单状态的业务逻辑
return $"Order_{orderId}_Status";
}
}
}
动态 API 控制器会自动根据方法名和配置生成路由地址和 HTTP 谓词。例如,上述ProductService中的GetProductName方法会生成一个 HTTP GET 请求的路由,大致路径类似于 “/ProductService/GetProductName” 。它适用于快速迭代的项目和对 API 灵活性要求较高的场景,尤其是在微服务架构中,能够快速地暴露服务接口。其优势在于减少了大量的样板代码,提高了开发效率,并且支持运行时动态添加、更新、卸载控制器,无需重启服务即可生效,增强了系统的灵活性和可扩展性。
定义接口方法
在控制器中定义接口方法是实现 Webapi 功能的核心部分,通过定义不同 HTTP 方法的接口,我们可以实现对各种请求的处理和响应。
GET 方法接口:
GET 方法通常用于从服务器获取数据。在 Furion 的控制器中定义一个 GET 方法接口,以获取用户列表为例:
[HttpGet]
public IActionResult GetUsers()
{
// 模拟获取用户列表的业务逻辑
var users = new List<string> { "User1", "User2", "User3" };
return Ok(users);
}
这里使用[HttpGet]特性来标识该方法处理 HTTP GET 请求。Ok方法用于返回 HTTP 200 状态码和响应数据,在这个例子中,响应数据是一个包含用户名称的列表。如果请求的 URL 为 “/User/GetUsers”,当客户端发起 GET 请求时,就会执行这个方法,返回用户列表数据。
POST 方法接口:
POST 方法常用于向服务器提交数据,如创建新的资源。定义一个用于创建用户的 POST 方法接口:
[HttpPost]
public IActionResult CreateUser([FromBody] User user)
{
// 模拟创建用户的业务逻辑
// 这里可以将用户数据保存到数据库等操作
return CreatedAtAction(nameof(GetUser), new { id = user.Id }, user);
}
[HttpPost]特性表示该方法处理 POST 请求。[FromBody]特性用于从请求体中获取数据,并将其绑定到User对象上。CreatedAtAction方法用于返回 HTTP 201 状态码,表示资源已成功创建,同时返回创建的资源信息和一个指向该资源的 URL,这里通过nameof(GetUser)指定了获取该用户的方法名,new { id = user.Id }是生成 URL 所需的路由参数。
PUT 方法接口:
PUT 方法一般用于更新服务器上的资源。定义一个更新用户信息的 PUT 方法接口:
[HttpPut("{id}")]
public IActionResult UpdateUser(int id, [FromBody] User updatedUser)
{
// 模拟更新用户信息的业务逻辑
// 这里根据id查找并更新用户信息
return NoContent();
}
[HttpPut("{id}")]中的{id}是路由参数,表示该方法的 URL 中会包含一个名为 “id” 的参数,用于指定要更新的用户的 ID。FromBody特性同样用于获取请求体中的更新数据。NoContent方法用于返回 HTTP 204 状态码,表示请求已成功处理,但没有内容返回。
DELETE 方法接口:
DELETE 方法用于删除服务器上的资源。定义一个删除用户的 DELETE 方法接口:
[HttpDelete("{id}")]
public IActionResult DeleteUser(int id)
{
// 模拟删除用户的业务逻辑
// 这里根据id从数据库等存储中删除用户信息
return NoContent();
}
通过[HttpDelete("{id}")]标识该方法处理 DELETE 请求,{id}为路由参数指定要删除的用户 ID。执行删除操作后,同样返回 HTTP 204 状态码。
参数绑定与验证
在 Webapi 开发中,参数绑定与验证是确保接口接收到的数据符合预期的重要环节,Furion 提供了强大且灵活的机制来实现这一功能。
参数绑定机制:
Furion 支持多种参数绑定方式,包括从路由、查询字符串、请求体等位置获取参数并绑定到方法参数上。
从路由中绑定参数,如前面更新用户信息的 PUT 方法接口中的int id参数,通过[HttpPut("{id}")]这样的路由定义,id参数会自动从 URL 的路由中获取。例如,当请求 URL 为 “/User/1” 时,“1” 就会被绑定到id参数上。
从查询字符串中绑定参数,假设我们有一个获取用户列表的接口,支持根据年龄过滤用户:
[HttpGet]
public IActionResult GetUsersByAge(int? age)
{
// 根据age参数进行用户列表过滤的业务逻辑
var users = new List<string>();
if (age.HasValue)
{
// 模拟根据年龄过滤用户
users = new List<string> { $"User_{age.Value}" };
}
else
{
users = new List<string> { "User1", "User2", "User3" };
}
return Ok(users);
}
当请求 URL 为 “/User/GetUsersByAge?age=20” 时,age参数会自动从查询字符串中获取值 “20” 并绑定到方法参数上。
从请求体中绑定参数,如创建用户的 POST 方法接口中使用[FromBody] User user,会将请求体中的 JSON 数据解析并绑定到User对象上。假设请求体中的 JSON 数据为{"Id": 1, "Name": "John", "Email": "john@example.com"},则会自动创建一个User对象,并将这些属性值赋值给该对象。
参数验证:
Furion 集成了强大的参数验证功能,通过数据注解(Data Annotations)和 FluentValidation 库,可以方便地对输入参数进行验证。
使用数据注解进行简单的参数验证,例如在User类中定义属性验证:
public class User
{
public int Id { get; set; }
[Required(ErrorMessage = "Name is required")]
[StringLength(50, ErrorMessage = "Name cannot exceed 50 characters")]
public string Name { get; set; }
[EmailAddress(ErrorMessage = "Invalid email address")]
public string Email { get; set; }
}
在创建用户的 POST 方法接口中,当请求体中的数据绑定到User对象时,会自动根据这些数据注解进行验证。如果Name为空或者Email格式不正确,就会返回相应的错误信息。
对于更复杂的验证逻辑,可以使用 FluentValidation 库。首先安装FluentValidation.AspNetCore包,然后创建一个UserValidator类:
using FluentValidation;
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(u => u.Name).NotEmpty().WithMessage("Name is required");
RuleFor(u => u.Email).EmailAddress().WithMessage("Invalid email address");
RuleFor(u => u.Id).GreaterThan(0).WithMessage("Id must be greater than 0");
}
}
在Startup类(或使用AppStartup的方式)中注册验证器:
using FluentValidation.AspNetCore;
using Microsoft.Extensions.DependencyInjection;
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddFluentValidation(fv =>
{
fv.RegisterValidatorsFromAssemblyContaining<UserValidator>();
});
}
}
这样,在处理涉及User对象的请求时,FluentValidation 会自动执行验证逻辑,确保输入数据的有效性。如果验证失败,会返回包含详细错误信息的响应,方便客户端进行错误处理。
数据交互与持久化
数据库连接与操作
在 Furion 项目中,实现与不同数据库的连接并进行基本的数据操作是至关重要的环节,它为应用程序提供了数据存储和管理的能力。以下以常见的 SQL Server、MySQL 和 SQLite 数据库为例,展示在 Furion 中如何进行数据库连接配置以及基本的数据操作。
SQL Server 数据库:
- 配置数据库连接:在appsettings.json文件中添加 SQL Server 的连接字符串。例如:
{
"ConnectionStrings": {
"SqlServerConnection": "Server=yourServer;Database=yourDatabase;User ID=yourUser;Password=yourPassword;Trusted_Connection=False;MultipleActiveResultSets=true"
}
}
在上述配置中,Server指定了数据库服务器的地址,Database是要连接的数据库名称,User ID和Password分别是登录数据库的用户名和密码。Trusted_Connection=False表示不使用 Windows 身份验证,而是使用指定的用户名和密码进行验证;MultipleActiveResultSets=true则允许在一个连接中同时执行多个结果集的操作。
- 基本数据操作:以使用IRepository接口进行数据操作为例,假设我们有一个User实体类。首先,在Startup类(或使用AppStartup的方式)中注册数据库访问服务:
using Furion.DatabaseAccessor;
using Microsoft.Extensions.DependencyInjection;
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDatabaseAccessor(options =>
{
options.AddDbPool<YourDbContext>(DbProvider.SqlServer);
});
}
}
这里的YourDbContext是继承自DbContext的数据库上下文类,用于与数据库进行交互。
在业务逻辑中,进行数据查询操作:
using Furion.DatabaseAccessor;
using System.Linq;
public class UserService
{
private readonly IRepository<User> _userRepository;
public UserService(IRepository<User> userRepository)
{
_userRepository = userRepository;
}
public User GetUserById(int id)
{
return _userRepository.Entities.FirstOrDefault(u => u.Id == id);
}
}
在这个例子中,通过依赖注入获取IRepository实例,然后使用Entities属性获取User实体的查询集合,通过FirstOrDefault方法根据Id查询单个用户。
进行数据插入操作:
public async Task<int> AddUser(User user)
{
var result = await _userRepository.InsertNowAsync(user);
return result.Entity.Id;
}
InsertNowAsync方法用于将新的User对象插入到数据库中,并返回插入后的实体对象,通过result.Entity.Id可以获取插入后数据的主键值。
数据更新操作:
public async Task UpdateUser(User user)
{
await _userRepository.UpdateAsync(user);
}
UpdateAsync方法会根据传入的User对象更新数据库中对应的记录。
数据删除操作:
public async Task DeleteUser(int id)
{
var user = await _userRepository.FirstOrDefaultAsync(u => u.Id == id);
if (user!= null)
{
await _userRepository.DeleteAsync(user);
}
}
首先通过FirstOrDefaultAsync方法查询要删除的用户,然后使用DeleteAsync方法将其从数据库中删除。
MySQL 数据库:
- 配置数据库连接:在appsettings.json中添加 MySQL 连接字符串:
{
"ConnectionStrings": {
"MySqlConnection": "server=yourServer;database=yourDatabase;user=yourUser;password=yourPassword;SslMode=none"
}
}
server指定数据库服务器地址,database为数据库名称,user和password分别是用户名和密码,SslMode=none表示不使用 SSL 加密连接。
- 基本数据操作:在Startup类中注册 MySQL 数据库访问服务:
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDatabaseAccessor(options =>
{
options.AddDbPool<YourMySqlDbContext>(DbProvider.MySql);
});
}
}
数据操作方法与 SQL Server 类似,只是使用的数据库上下文类变为YourMySqlDbContext。例如查询操作:
public class UserService
{
private readonly IRepository<User, YourMySqlDbContext> _userRepository;
public UserService(IRepository<User, YourMySqlDbContext> userRepository)
{
_userRepository = userRepository;
}
public User GetUserById(int id)
{
return _userRepository.Entities.FirstOrDefault(u => u.Id == id);
}
}
这里通过IRepository<User, YourMySqlDbContext>指定了使用YourMySqlDbContext作为数据库上下文来进行User实体的数据操作。
SQLite 数据库:
- 配置数据库连接:在appsettings.json中配置 SQLite 连接字符串:
{
"ConnectionStrings": {
"SqliteConnection": "Data Source=yourDatabase.db"
}
}
Data Source指定了 SQLite 数据库文件的路径。
- 基本数据操作:在Startup类中注册 SQLite 数据库访问服务:
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDatabaseAccessor(options =>
{
options.AddDbPool<YourSqliteDbContext>(DbProvider.Sqlite);
});
}
}
在业务逻辑中进行数据操作,如查询:
public class UserService
{
private readonly IRepository<User, YourSqliteDbContext> _userRepository;
public UserService(IRepository<User, YourSqliteDbContext> userRepository)
{
_userRepository = userRepository;
}
public User GetUserById(int id)
{
return _userRepository.Entities.FirstOrDefault(u => u.Id == id);
}
}
通过以上配置和操作示例,可以看到在 Furion 中针对不同类型的数据库进行连接和基本数据操作的方式具有一定的相似性,通过合理的配置和使用IRepository等接口,能够方便地实现数据的持久化和交互功能。
使用 EF Core(或其他 ORM)
在 Furion 项目中,EF Core 是一个常用的对象关系映射(ORM)框架,它能够帮助我们更方便地与数据库进行交互,将数据库中的表映射为对象,以面向对象的方式进行数据操作。
集成 EF Core:
- 安装相关包:首先,需要在项目中安装Microsoft.EntityFrameworkCore以及对应数据库的 EF Core 驱动包。例如,如果使用 SQL Server 数据库,需要安装Microsoft.EntityFrameworkCore.SqlServer;若使用 MySQL 数据库,则安装Pomelo.EntityFrameworkCore.MySql。可以通过 NuGet 包管理器进行安装,在 Visual Studio 中,右键点击项目,选择 “管理 NuGet 程序包”,然后在搜索框中输入相应的包名进行安装。
- 创建数据模型:定义数据模型类,这些类将映射到数据库中的表。以一个简单的Product数据模型为例:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
在这个模型中,Id、Name和Price分别对应数据库表中Product表的字段。
- 创建数据库上下文:创建一个继承自DbContext的数据库上下文类,用于管理与数据库的连接和交互。例如:
using Microsoft.EntityFrameworkCore;
public class MyDbContext : DbContext
{
public DbSet<Product> Products { get; set; }
public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// 可以在这里进行更多的模型配置,如设置主键、外键、索引等
modelBuilder.Entity<Product>().HasKey(p => p.Id);
}
}
在MyDbContext类中,定义了一个DbSet属性,它对应数据库中的Product表。OnModelCreating方法用于对数据模型进行进一步的配置,这里设置了Product的Id字段为主键。
- 注册服务:在Startup类(或使用AppStartup的方式)中注册 EF Core 服务和数据库上下文:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
public class MyStartup : AppStartup
{
public void ConfigureServices(IServiceCollection services)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
services.AddDbContext<MyDbContext>(options =>
options.UseSqlServer(connectionString));
}
}
这里通过services.AddDbContext方法注册了MyDbContext,并使用UseSqlServer指定使用 SQL Server 数据库,connectionString从配置文件中获取。
迁移数据库:
- 使用命令行迁移:在项目中启用数据库迁移功能,可以使用.NET CLI 命令。首先,确保项目中安装了Microsoft.EntityFrameworkCore.Design包,它提供了用于创建和管理迁移的工具。
打开命令行工具,进入项目目录,执行以下命令创建迁移:
dotnet ef migrations add InitialCreate
这里的InitialCreate是迁移的名称,可以根据实际情况进行修改。该命令会在项目中创建一个迁移文件,记录对数据模型的更改。
执行以下命令将迁移应用到数据库:
dotnet ef database update
这个命令会根据迁移文件中的更改,在数据库中创建或更新相应的表结构。
- 使用 Package Manager Console 迁移:在 Visual Studio 中,也可以使用 Package Manager Console 进行数据库迁移。打开 Package Manager Console,选择项目,执行以下命令创建迁移:
Add-Migration InitialCreate
同样,InitialCreate是迁移名称。
执行以下命令应用迁移:
Update-Database
通过以上步骤,就可以在 Furion 项目中成功集成 EF Core,并使用它进行数据库的创建、表结构管理以及数据的增删改查操作。在实际项目中,根据业务需求不断完善数据模型和数据库上下文的配置,能够实现高效的数据持久化和交互功能。
测试与验证
单元测试
在 Webapi 开发过程中,单元测试是确保代码质量和功能正确性的重要环节。通过对各个独立的单元(如控制器、服务方法等)进行测试,可以在开发的早期阶段发现潜在的问题,提高代码的稳定性和可靠性。在 Furion 项目中,我们可以使用流行的测试框架,如 xUnit 或 NUnit,来编写单元测试。
以 xUnit 为例,首先需要在项目中安装 xUnit 和相关的 NuGet 包。在 Visual Studio 中,右键点击项目,选择 “管理 NuGet 程序包”,在搜索框中输入 “xUnit”,安装xunit和xunit.runner.visualstudio包。xunit包提供了核心的测试功能,而xunit.runner.visualstudio包则用于在 Visual Studio 中运行 xUnit 测试。
假设我们有一个UserController,其中包含一个GetUserById方法,用于根据用户 ID 获取用户信息。我们可以编写如下的单元测试:
using System;
using System.Threading.Tasks;
using Xunit;
using Moq;
using MyFurionWebApi.Controllers;
using MyFurionWebApi.Application;
using Microsoft.AspNetCore.Mvc;
public class UserControllerTests
{
[Fact]
public async Task GetUserById_ReturnsOkResult()
{
// Arrange
var mockUserService = new Mock<IUserService>();
int userId = 1;
var user = new User { Id = userId, Name = "TestUser" };
mockUserService.Setup(service => service.GetUserByIdAsync(userId)).ReturnsAsync(user);
var controller = new UserController(mockUserService.Object);
// Act
var result = await controller.GetUserById(userId) as OkObjectResult;
// Assert
Assert.NotNull(result);
Assert.Equal(200, result.StatusCode);
var returnedUser = result.Value as User;
Assert.NotNull(returnedUser);
Assert.Equal(userId, returnedUser.Id);
Assert.Equal("TestUser", returnedUser.Name);
}
}
在这个测试用例中,我们使用了 Moq 库来创建一个IUserService的模拟对象。Moq 是一个用于创建模拟对象的库,它可以帮助我们在测试中模拟依赖对象的行为,从而实现对被测对象的隔离测试。通过mockUserService.Setup(service => service.GetUserByIdAsync(userId)).ReturnsAsync(user),我们设置了模拟的GetUserByIdAsync方法的返回值为一个预设的User对象。
然后,我们创建了UserController的实例,并传入模拟的IUserService对象。接着,调用GetUserById方法,并将返回结果转换为OkObjectResult。最后,使用Assert类中的各种方法对结果进行断言,验证返回的状态码是否为 200,返回的用户对象是否不为空,以及用户对象的属性是否与预期一致。
如果使用 NUnit 进行单元测试,测试代码的结构和逻辑与 xUnit 类似,但语法略有不同。首先,需要安装 NUnit 和NUnit3TestAdapter包。NUnit包提供测试框架的核心功能,NUnit3TestAdapter包则用于在 Visual Studio 中运行 NUnit 测试。以下是使用 NUnit 的测试示例:
using System;
using System.Threading.Tasks;
using NUnit.Framework;
using Moq;
using MyFurionWebApi.Controllers;
using MyFurionWebApi.Application;
using Microsoft.AspNetCore.Mvc;
[TestFixture]
public class UserControllerNUnitTests
{
[Test]
public async Task GetUserById_ReturnsOkResult()
{
// Arrange
var mockUserService = new Mock<IUserService>();
int userId = 1;
var user = new User { Id = userId, Name = "TestUser" };
mockUserService.Setup(service => service.GetUserByIdAsync(userId)).ReturnsAsync(user);
var controller = new UserController(mockUserService.Object);
// Act
var result = await controller.GetUserById(userId) as OkObjectResult;
// Assert
Assert.NotNull(result);
Assert.AreEqual(200, result.StatusCode);
var returnedUser = result.Value as User;
Assert.NotNull(returnedUser);
Assert.AreEqual(userId, returnedUser.Id);
Assert.AreEqual("TestUser", returnedUser.Name);
}
}
在 NUnit 中,使用[TestFixture]特性标记测试类,使用[Test]特性标记测试方法。断言方法Assert.AreEqual用于比较两个值是否相等,Assert.NotNull用于验证对象是否不为空,这些断言方法与 xUnit 中的断言方法类似,但在使用时需要注意 NUnit 的语法规则。
接口测试
除了单元测试,接口测试也是保证 Webapi 质量的关键步骤。接口测试主要关注 Webapi 的外部接口,验证接口的功能、性能、安全性等方面是否符合预期。Postman 是一款广泛使用的接口测试工具,它提供了直观的图形化界面,方便我们发送各种 HTTP 请求,并查看接口的响应结果。
使用 Postman 进行接口测试的基本步骤如下:
- 下载和安装 Postman:可以从 Postman 官方网站(www.postman.com/downloads/ )下载适合你操作系统的版本,然后按照安装向导进行安装。
- 创建请求:打开 Postman,点击左侧的 “New” 按钮,选择 “Request”,输入请求名称(例如 “GetUserById”),然后点击 “Save to [Collection]” 将请求保存到一个集合中。集合可以帮助我们组织和管理多个相关的请求,方便后续的测试和维护。
- 设置请求 URL:在新建的请求界面顶部的 URL 栏中,输入要测试的 Webapi 接口地址。例如,如果我们要测试前面UserController中的GetUserById方法,假设应用程序运行在本地,端口为 5000,那么 URL 可以设置为 “https://localhost:5000/User/1”,其中 “1” 是用户 ID。
- 选择 HTTP 方法:根据接口的定义,选择合适的 HTTP 方法。对于获取用户信息的GetUserById方法,使用 GET 方法,在请求界面顶部的下拉菜单中选择 “GET”。
- 发送请求:点击 “Send” 按钮,Postman 会向指定的 URL 发送请求,并在下方的响应区域显示服务器返回的响应内容。响应内容包括状态码、响应头和响应体。例如,如果接口正常工作,我们应该收到状态码为 200 的响应,响应体中包含对应的用户信息。
- 验证响应:检查响应的状态码是否符合预期。对于成功的请求,通常状态码为 200。查看响应体中的数据是否正确,例如用户信息是否与预期一致。在 Postman 的响应区域,点击 “Body” 标签,可以查看响应体的内容。如果响应体是 JSON 格式的数据,Postman 会自动格式化显示,方便我们查看和验证。
除了基本的请求发送和响应验证,Postman 还提供了许多高级功能,如环境变量、集合运行、自动化测试等。
环境变量:在不同的环境(如开发、测试、生产)中,Webapi 的 URL 和其他配置可能会有所不同。Postman 的环境变量功能可以帮助我们轻松地在不同环境之间切换。例如,我们可以创建一个名为 “Development” 的环境,设置其中的baseUrl变量为开发环境的 Webapi 地址 “https://localhost:5000”;再创建一个 “Production” 环境,设置baseUrl变量为生产环境的地址。在请求 URL 中,我们可以使用{{baseUrl}}来引用环境变量,这样在不同环境下测试时,只需要切换环境,而无需修改请求 URL 中的地址。
集合运行:当我们有多个相关的接口需要测试时,可以将这些接口请求组织成一个集合。在 Postman 中,点击左侧的 “Collections”,可以管理和运行集合。点击集合名称旁边的 “Run” 按钮,选择要运行的环境,然后点击 “Run [Collection Name]”,Postman 会按照集合中请求的顺序依次发送请求,并显示每个请求的响应结果和测试结果。
自动化测试:Postman 内置了强大的自动化测试功能,支持使用 JavaScript 编写测试脚本。在每个请求的 “Tests” 标签页中,我们可以编写脚本来验证 API 响应是否符合预期。例如,验证 HTTP 状态码是否为 200:
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
验证响应体中是否包含特定的字段:
pm.test("Response body contains 'name' field", function () {
var jsonData = pm.response.json();
pm.expect(jsonData).to.have.property('name');
});
通过这些自动化测试脚本,我们可以快速验证接口的功能正确性,提高测试效率和准确性。在进行接口测试时,还可以模拟各种异常情况和边界条件,如传入非法参数、测试接口的限流和熔断机制等,以全面验证 Webapi 的稳定性和可靠性。
部署上线
发布项目
在完成 Furion Webapi 项目的开发和测试后,就需要将其发布,以便在生产环境中部署运行。在 Visual Studio 中,发布项目的步骤如下:
- 右键点击项目,选择 “发布”。这将打开发布向导,引导你完成发布配置。
- 在发布向导的 “目标” 页面,选择 “文件夹” 作为发布目标。这意味着项目将被发布到本地的一个文件夹中,生成可部署的文件。点击 “下一步”。
- 在 “配置” 页面,可以选择发布配置,如 “Release” 模式。“Release” 模式会对代码进行优化,去除调试信息,提高应用程序的性能,适合生产环境。还可以根据需要进行其他高级设置,如选择目标框架、是否包含调试符号等。点击 “下一步”。
- 在 “目标位置” 页面,指定发布文件的输出路径。可以通过点击 “浏览” 按钮选择一个已有的文件夹,也可以输入新的路径。例如,我们可以在项目根目录下创建一个名为 “Publish” 的文件夹,用于存放发布文件。点击 “保存”。
- 点击 “发布” 按钮,Visual Studio 将开始生成发布文件。这一过程可能需要一些时间,具体取决于项目的大小和复杂程度。在发布过程中,Visual Studio 会编译项目代码,将其打包成可执行文件,并将项目所依赖的库、配置文件等一并复制到指定的发布文件夹中。发布完成后,在指定的发布文件夹中,会看到生成的一系列文件,包括.dll文件(项目的程序集)、.pdb文件(调试符号文件,在 “Release” 模式下可能没有)、appsettings.json配置文件以及其他相关的资源文件。
部署到服务器
部署 Furion Webapi 项目到服务器时,常见的服务器环境有 IIS 和 Nginx,下面分别介绍在这两种环境下的部署步骤和注意事项。
部署到 IIS:
- 安装 IIS:如果服务器上尚未安装 IIS,需要先进行安装。在 Windows Server 系统中,可以通过 “服务器管理器” 进行安装。打开 “服务器管理器”,选择 “添加角色和功能”,在 “安装类型” 中选择 “基于角色或基于功能的安装”,然后在 “服务器角色” 中勾选 “Web 服务器(IIS)”,按照提示完成安装。
- 安装.NET Core 运行时:确保服务器上安装了与项目目标框架版本匹配的.NET Core 运行时。可以从.NET 官方下载页面下载并安装相应版本的运行时。例如,如果项目是基于.NET 6 开发的,就需要安装.NET 6 运行时。
- 配置 IIS:
-
- 打开 IIS 管理器。可以通过在 “开始” 菜单中搜索 “IIS 管理器” 来找到并打开它。
-
- 在 IIS 管理器中,右键点击 “网站”,选择 “添加网站”。
-
- 在 “添加网站” 对话框中,填写网站名称,例如 “MyFurionWebApi”。
-
- 选择应用程序池,通常可以使用默认的应用程序池,也可以根据需要创建新的应用程序池。如果创建新的应用程序池,需要注意设置其.NET CLR 版本和托管管道模式,确保与项目的要求一致。
-
- 设置物理路径,将其指向之前发布项目时指定的发布文件夹。
-
- 配置绑定,设置网站的 IP 地址、端口和主机名。例如,可以使用默认的 80 端口(HTTP)或 443 端口(HTTPS),如果服务器上有多个网站,需要确保端口不冲突。
- 测试访问:完成上述配置后,在浏览器中输入网站的 URL(如http://服务器IP地址:端口号),如果部署成功,应该能够访问到 Furion Webapi 项目的相关接口。例如,如果项目中定义了一个获取用户信息的接口,访问该接口的 URL,应该能够得到正确的响应数据。
注意事项:
- 确保 IIS 和.NET Core 运行时的版本兼容性,避免因版本不匹配导致的问题。
- 检查防火墙设置,确保服务器的相应端口(如 80、443)已开放,允许外部访问。
- 如果项目需要访问数据库,要确保数据库连接字符串配置正确,并且服务器能够访问到数据库服务器。
部署到 Nginx:
- 安装 Nginx:在 Linux 服务器上,可以使用包管理器安装 Nginx。例如,在 Ubuntu 系统中,可以使用以下命令安装:
sudo apt-get update
sudo apt-get install nginx
在 CentOS 系统中,可以使用以下命令安装:
sudo yum install epel-release
sudo yum install nginx
2. 安装.NET Core 运行时:同样,需要在服务器上安装与项目目标框架版本匹配的.NET Core 运行时。对于 Linux 系统,可以从.NET 官方下载页面获取相应的安装包,并按照官方文档的说明进行安装。
- 配置 Nginx:
-
- 打开 Nginx 的配置文件,通常位于/etc/nginx/nginx.conf或/etc/nginx/conf.d/default.conf。
-
- 在配置文件中,添加一个新的server块,用于代理 Furion Webapi 项目。例如:
server {
listen 80;
server_name your_domain.com; # 替换为你的域名或服务器IP地址
location / {
proxy_pass http://127.0.0.1:5000; # 假设Furion Webapi项目运行在本地的5000端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
在上述配置中,listen指定了 Nginx 监听的端口,server_name指定了域名或 IP 地址,location /中的proxy_pass指定了 Furion Webapi 项目的实际运行地址。
- 启动和测试:保存配置文件后,使用以下命令启动 Nginx 服务:
sudo systemctl start nginx
然后在浏览器中输入配置的域名或 IP 地址,测试是否能够正常访问 Furion Webapi 项目。
注意事项:
- 确保 Nginx 配置正确,特别是proxy_pass的地址要与 Furion Webapi 项目的实际运行地址一致。
- 检查服务器的防火墙设置,确保 Nginx 监听的端口(如 80、443)已开放。
- 如果使用域名访问,要确保域名已正确解析到服务器的 IP 地址。
总结与展望
在本次探索中,我们深入领略了使用 Furion 快速实现 Webapi 的全过程。从环境搭建的准备工作,到项目创建的便捷操作,再到配置文件的详细解读、依赖注入的巧妙运用,以及 Webapi 构建中控制器的创建、接口方法的定义和参数的绑定与验证,还有数据交互与持久化的实现,以及测试与验证的关键步骤,最后到项目的部署上线,每一个环节都展示了 Furion 框架的强大功能和便捷性。
Furion 以其丰富的扩展、强大的依赖注入、独特的动态 API 等特性,显著提升了 Webapi 的开发效率,让代码更加简洁易读,项目的可维护性也得到了极大增强。它不仅减少了繁琐的基础代码编写,还提供了灵活的架构和丰富的工具,使开发者能够将更多的精力聚焦于业务逻辑的实现。
对于正在阅读本文的你,我强烈建议在实际项目中尝试应用 Furion。无论是小型项目的快速迭代,还是大型企业级项目的架构搭建,Furion 都能为你带来高效、稳定的开发体验。在实践中,你将更深刻地体会到它的优势,同时也能不断积累经验,提升自己的开发技能。
展望未来,随着技术的不断发展,Furion 有望在功能上持续创新和完善。例如,在与新兴技术的融合方面,可能会更好地支持云原生架构,实现更便捷的容器化部署和管理;在性能优化上,进一步提升运行效率,满足高并发场景下的需求。而 Webapi 开发也将朝着更加智能化、高效化的方向发展,如自动化的接口文档生成、智能的错误处理和更强大的安全防护机制等。相信 Furion 将在这一发展趋势中持续发挥重要作用,为 Webapi 开发带来更多的惊喜和可能。