从 .NET Core WebAPI 学习 NServiceBus
将现有的 .NET Core WebAPI 应用程序转换为 NServiceBus
引言
NServiceBus
可用于多种不同配置;在配置可能性方面,它就像瑞士军刀。学习新事物的好方法是基于你已知的东西。我认为学习如何使用 NServiceBus
的一个好方法是在一个我已熟悉的 .NET Core Web 应用程序中使用它。我的计划是采用一个现有的 Web API 应用程序,用 NServiceBus
替换 Web API 接口,并保留其余部分。用户应该看不到任何区别,GUI 和功能应该相同。
由于 .NET Core 是一个相对较新的版本,有一些新东西需要学习。学习 .NET Core 的一个非常好的文档是 这份。
WebAPI 项目
我使用了一个我很久以前为了好玩而开发的用于公司车辆管理的应用程序。它由两个项目组成,以客户端/服务器配置工作。它们都是 Visual Studio 的标准解决方案,基于 C# MVC WebAPI Core 2.0。名为 CarAPI
的服务器有两个 SQLite 数据库,Car.db 和 AspNet.db。名为 CarClient
的客户端是一个通过 RESTFul http 与服务器通信的 Web GUI。
测试
最终解决方案中没有单元测试。但是,为了支持测试,在客户端和服务器的初始化过程中使用了依赖注入 (DI)。服务器使用 Autofac,客户端使用 .NET Core 内置的 DI 功能。
整洁代码
在编写这些应用程序时,我努力遵循整洁代码的大部分原则。这里有一个很好的总结,解释了整洁代码的含义。
我总是努力避免使用我不完全理解的其他程序的代码。我还努力尽可能简化一切,并删除不必要的代码。我已尝试删除应用程序中所有不必要的代码,并希望您作为读者能告知我您发现的任何可能的改进。
SQLite 数据库
没有使用 SQLite 服务器,因此服务器无法通过 IP 连接到 SQLite 数据库。SQLite 数据库可以被视为文本文件。CarAPI
程序会在程序启动期间创建并初始化 Car.db(如果它不存在)。Car.db 的初始化会创建并填充两个表:Cars
和 Companies
。使用“DB browser for SQLite”工具,您可以打开数据库。打开 Car.db 将会显示如下所示的数据库。
第二个数据库 AspNet.db 具有与传统 Visual Studio Web 项目中的 ASPNETDB.mdf 相同的功能,即存储用户身份数据。
SQLite 具有“内存模式”,在单元测试期间特别有用。这时,您可以这样打开连接:
在单元测试中使用 SQLite,在生产环境中使用 SQL Server 是很常见的。在大多数情况下,SQLite 和 SQL Server 的 SQL 语法是相同的。
在正常的 SQLite 操作中,您会在初始化期间的 Startup.cs 文件中使用 Autofac 依赖注入来定义 db 上下文。
运行 CarAPI 和 CarClient
要运行该系统,请下载 CarAPI
和 CarClient
解决方案,在 Visual Studio 2017 中打开它们,然后先按 F5 启动 CarAPI
。然后,按 F5 启动 CarClient
。运行 CarClient
时,您可以创建一个用户帐户。此代码使用了来自 Microsoft.AspNetCore.Authentication
、Authorization
和 Identity
类的类和方法,这些类和方法来自 Visual Studio 项目模板。
当以已登录用户的身份运行客户端时,第一个视图如下所示:
“显示消息队列”按钮将打开一个弹出窗口,显示所有车辆状态和“模拟”消息队列。
NServiceBus 回调示例
Particular Software 建议仅在特殊情况下使用回调,例如,在无法更改的遗留组件中,在同步 API 后面引入消息传递。它们允许应用程序逐步过渡到消息传递。但是,它们不能替代异步消息传递,也不会提供类似的好处(在可伸缩性、松耦合等方面)。有关更多信息,请参阅 文档。
以下回调示例用作 NServiceBusAPI
开发的基础:
我建议您下载并运行它,以确保您了解它的工作原理。请注意,您必须在 Program.cs 中添加以下行(这是示例中的一个错误!):
CultureInfo.CurrentUICulture = new CultureInfo("en-US");
像这样
为了发送和接收对象消息,使用了类 ObjectMessage
、ObjectResponseMessage
和 ObjectMessageHandler
。
我建议您运行回调示例并熟悉代码。
NServiceBusAPI
在 NServiceBusAPI
中发送消息有三个类别的类:处理程序、请求消息和响应消息。它们通常看起来像这样:
[Serializable]
public class CreateCarRequest : IMessage
{
public CreateCarRequest(Car car)
{
DataId = Guid.NewGuid();
Car = car;
}>
public Guid DataId { get; set; }
public Car Car { get; set; }
}
[Serializable]
public class CreateCarResponse : IMessage
{
public CreateCarResponse()
{
DataId = Guid.NewGuid();
}
public Guid DataId { get; set; }
public Car Car { get; set; }
}
public class CreateCarRequestHandler:IHandleMessages<CreateCarRequest>
{
readonly DbContextOptionsBuilder<CarApiContext> _dbContextOptionsBuilder;
public CreateCarRequestHandler(DbContextOptionsBuilder<CarApiContext> dbContextOptionsBuilder)
{
_dbContextOptionsBuilder= dbContextOptionsBuilder;
}
static ILog log = LogManager.GetLogger<CreateCarRequestHandler>();
public Task Handle(CreateCarRequest message, IMessageHandlerContext context)
{
log.Info("Received CreateCarRequest.");
var response = new CreateCarResponse()
{
Car = message.Car
};
using (var unitOfWork = new CarUnitOfWork(new CarApiContext(_dbContextOptionsBuilder.Options)))
{
unitOfWork.Cars.Add(message.Car);
unitOfWork.Complete;
}
var reply = context.Reply(response);
return reply;
}
实际数据从数据库中获取,在...
CreateCarRequestHandler:IHandleMessages<CreateCarRequest>
...并传递给...
CarController: Controller
... 像这样:
模式很简单。请下载并运行 NServiceBusAPI
解决方案以充分理解它。它包含三个项目:Client
、Server
和 Shared
。Client
和 Server
都使用的类位于 Shared
项目中。Server
项目的作用与 CarAPI
项目相同,即 Server
项目访问数据库 Car.db 和 AspNet.db。它是一个控制台程序,启动方式如下所示的 Program.cs。我尽可能多地使用了 CarAPI
的内容。数据库在名为 InitSqLiteDb
的扩展方法中初始化。
class Program
{
public static void Main(string[] args)
{
CultureInfo.CurrentUICulture = new CultureInfo("en-US");
BuildWebHost(args).Run();
}
static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.InitSqLiteDb("DataSource=App_Data/Car.db")
.Build();
}
}
public static class WebHostBuilderExtension
{
//
// Summary:
// Defines the context for Car.db
// Parameters:
// db: name and location of the database
static readonly DbContextOptionsBuilder<CarApiContext>_optionsBuilder =
new DbContextOptionsBuilder<CarApiContext>();
public static IWebHostBuilder InitSqLiteDb(this IWebHostBuilder hostBuilder, string db)
{
_optionsBuilder.UseSqlite(db);
using (var context = new CarApiContext(_optionsBuilder.Options))
{
context.Database.EnsureCreated();
context.EnsureSeedData();
}
}
}
有关详细信息,请参阅 NServiceBusAPI
中的代码并运行它。
关注点
撰写本文让我学到了很多东西,例如:
- 如何使用 Autofac 进行依赖注入
- 如何在单元测试中使用 SQLite 作为 SQL Server 的补充
- 如何使用扩展方法初始化 .NET Core 程序
- 如何使用
NServiceBus