MDP.Hosting
MDP.Hosting是一个.NET开发模组,协助开发人员快速建立具有依赖注入的应用系统。提供标签注册、具名实例、具名注入等功能服务,用以简化开发流程并满足多变的商业需求。
说明文件:https://clark159.github.io/MDP.Net/
程式源码:https://github.com/Clark159/MDP.Net/
模组功能
标签注册
MDP.Hosting扩充.NET Core既有的参数管理,加入ServiceAttribute标签,只要使用标签宣告就可以注册类别(Class)。
// 注册类别
[Service<MessageRepository>(singleton:false)]
public class SqlMessageRepository : MessageRepository
{
//...
}
- 注册的类别(Class):SqlMessageRepository
- 注册为甚么服务(Service):MessageRepository
- 生成为唯一实例(Instance):singleton=false(false是预设值,可省略)
ServiceAttribute标签:用来宣告注册的类别(Class)、这个类别注册为甚么服务(Service)、以及类别生成的实例(Instance)是否全域唯一。
- 命名空间:
MDP.Registration
- 类别定义:
[AttributeUsage(AttributeTargets.Class)]
public sealed class ServiceAttribute<TService> : ServiceAttribute where TService : class
- TService:类别注册为甚么服务(Service)。
- 建构函式:
public ServiceAttribute(bool singleton = false)
- singleton:类别生成的实例(Instance)是否全域唯一。(false是预设值,可省略)
具名实例
MDP.Hosting里完成注册的类别(Class),在执行阶段会参考Config设定生成实例(Instance)。开发人员可以透过设定Config设定,生成多个实例;而每个实例除了被标记为服务(Service)的Type类型之外,还会被标记为实例(Instance)本身的Name名称。
// 注册类别
namespace MyLab.Module
{
[Service<MessageRepository>()]
public class SqlMessageRepository : MessageRepository
{
public SqlMessageRepository(string connectionString)
{
// ...
}
}
}
// Config设定
{
"MyLab.Module": {
"SqlMessageRepository": { "ConnectionString" : "Database Connection String"}
}
}
- 命名空间:MyLab.Module
- 生成实例:SqlMessageRepository
- 生成参数:ConnectionString="Database Connection String"
- 实例Type类型:MessageRepository
- 实例Name名称:SqlMessageRepository
具名注入
被标注Type类型及Name名称的实例(Instance),在系统里就可以被注入使用。预设.NET Core内建的依赖注入,会使用Type类型做为条件取得实例,来提供Typed注入;而MDP.Hosting的依赖注入,则是可以额外使用Name名称做为条件取得实例,来提供Named注入。(注:.NET8将会支援Named注入)
Typed注入范例:ASP.NET Core生成HomeController的时候,预设取得Type类型被标注为MessageRepository的实例来注入。
// 注册类别
namespace MyLab.Module
{
[Service<MessageRepository>()]
public class SqlMessageRepository : MessageRepository
{
//...
}
}
// Config设定
{
"MyLab.Module": {
"SqlMessageRepository": {}
}
}
// 服务注入
public class HomeController : Controller
{
public HomeController(MessageRepository messageRepository)
{
// ...
}
}
- 命名空间:MyLab.Module
- 生成实例:SqlMessageRepository
- 实例Type类型:MessageRepository
- 实例Name名称:SqlMessageRepository
Named注入范例:MDP.Hosting生成MessageContext的时候,参考Config设定("messageRepository": "SqlMessageRepository"
),取得Name名称被标注为SqlMessageRepository的实例来注入。
// 注册类别
namespace MyLab.Module
{
[Service<MessageContext>(singleton: true)]
public class MessageContext
{
public MessageContext(MessageRepository messageRepository)
{
// ...
}
}
[Service<MessageRepository>()]
public class SqlMessageRepository : MessageRepository
{
//...
}
}
// Config设定
{
"MyLab.Module": {
"MessageContext": {
"messageRepository": "SqlMessageRepository"
},
"SqlMessageRepository": {}
}
}
- 命名空间:MyLab.Module
- 生成实例:SqlMessageRepository
- 实例Type类型:MessageRepository
- 实例Name名称:SqlMessageRepository
模组使用
加入模组
MDP.Hosting预设内建在MDP.Net专案范本内,依照下列操作步骤,即可建立包含MDP.Hosting模组的专案。
- 在命令提示字元输入下列指令,使用MDP.Net专案范本建立专案。
// 建立API服务、Web站台
dotnet new install MDP.WebApp
dotnet new MDP.WebApp -n WebApplication1
// 建立Console程式
dotnet new install MDP.ConsoleApp
dotnet new MDP.ConsoleApp -n ConsoleApp1
使用ServiceAttribute
建立包含MDP.Hosting模组的专案之后,就可以使用ServiceAttribute标签,透过标签宣告来注册类别(Class)。
// 注册类别
namespace MyLab.Module
{
[Service<MessageRepository>()]
public class SqlMessageRepository : MessageRepository
{
public SqlMessageRepository(string connectionString)
{
// ...
}
}
}
设定参数
MDP.Hosting里完成注册的类别(Class),开发人员可以透过设定Config设定生成实例(Instance)。
// Config设定
{
"MyLab.Module": {
"SqlMessageRepository": { "ConnectionString" : "Database Connection String"}
}
}
- 命名空间:MyLab.Module
- 生成实例:SqlMessageRepository
- 生成参数:ConnectionString="Database Connection String"
- 实例Type类型:MessageRepository
- 实例Name名称:SqlMessageRepository
模组范例
专案开发过程,在开发/测试/正式三个执行环境,常常需要各自使用不同资料来源、或是使用不同连线字串。例如:开发环境使用Mock资料来源(假资料)、测试环境使用SQL资料来源(连线至测试资料库)、正式环境使用SQL资料来源(连线至正式资料库)。本篇范例协助开发人员使用MDP.Hosting,逐步完成必要的设计和实作。
- 范例下载:WebApplication1.zip
操作步骤
1.开启命令提示字元,输入下列指令。用以安装MDP.WebApp范本、并且建立一个名为WebApplication1的Web站台。
dotnet new install MDP.WebApp
dotnet new MDP.WebApp -n WebApplication1
2.使用Visual Studio开启WebApplication1专案。于专案内加入Modules\MessageContext.cs、Modules\MessageRepository.cs,并使用标签宣告来注册MessageContext。
using MDP.Registration;
namespace WebApplication1
{
[Service<MessageContext>(singleton: true)]
public class MessageContext
{
// Fields
private readonly MessageRepository _messageRepository = null;
// Constructors
public MessageContext(MessageRepository messageRepository)
{
// Default
_messageRepository = messageRepository;
}
// Methods
public string GetValue()
{
// Return
return _messageRepository.GetValue();
}
}
}
namespace WebApplication1
{
public interface MessageRepository
{
// Methods
string GetValue();
}
}
3.于专案内加入Modules\SqlMessageRepository.cs、Modules\MockMessageRepository.cs,并使用标签宣告来注册类别为MessageRepository。
using MDP.Registration;
namespace WebApplication1
{
[Service<MessageRepository>()]
public class SqlMessageRepository : MessageRepository
{
// Fields
private readonly string _connectionString;
// Constructors
public SqlMessageRepository(string connectionString)
{
// Default
_connectionString = connectionString;
}
// Methods
public string GetValue()
{
// Return
return "Hello World By " + _connectionString;
}
}
}
using MDP.Registration;
namespace WebApplication1
{
[Service<MessageRepository>()]
public class MockMessageRepository : MessageRepository
{
// Methods
public string GetValue()
{
// Return
return "Hello World By Mock Source";
}
}
}
4.改写专案内的Controllers\HomeController.cs、Views\Home\Index.cshtml,注入并使用MessageContext。
using System;
using Microsoft.AspNetCore.Mvc;
namespace WebApplication1
{
public class HomeController : Controller
{
// Fields
private readonly MessageContext _messageContext = null;
// Constructors
public HomeController(MessageContext messageContext)
{
// Default
_messageContext = messageContext;
}
// Methods
public ActionResult Index()
{
// ViewBag
this.ViewBag.Message = _messageContext.GetValue();
// Return
return View();
}
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>WebApplication1</title>
</head>
<body>
<!--Title-->
<h2>WebApplication1</h2>
<hr />
<!--Message-->
<h3>@ViewBag.Message</h3>
</body>
</html>
5.于专案内加入下列三个Config设定档,用来定义开发/测试/正式三个执行环境,各自使用不同资料来源、使用不同连线字串。
- 开发环境:\config\Development\appsettings.json,设定为MessageContext具名注入MockMessageRepository。(Mock资料来源)
{
"WebApplication1": {
"MessageContext": {
"MessageRepository": "MockMessageRepository"
},
"MockMessageRepository": {}
}
}
- 测试环境:\config\Staging\appsettings.json,设定为MessageContext具名注入SqlMessageRepository,并且设定连线至Staging Database。(SQL资料来源)
{
"WebApplication1": {
"MessageContext": {
"MessageRepository": "SqlMessageRepository"
},
"SqlMessageRepository": { "connectionString": "Staging Database" }
}
}
- 正式环境:\config\Production\appsettings.json,设定为MessageContext具名注入SqlMessageRepository,并且设定连线至Production Database。(SQL资料来源)
{
"WebApplication1": {
"MessageContext": {
"MessageRepository": "SqlMessageRepository"
},
"SqlMessageRepository": { "connectionString": "Production Database" }
}
}
6.执行专案,于开启的Browser视窗内,可以看到系统依照开发环境:\config\Development\appsettings.json
的设定执行,于画面显示MockMessageRepository回传的Hello World By Mock Source。
7.改写专案内的启动档 \Properties\launchSettings.json,将ASPNETCORE_ENVIRONMENT的内容改为Staging。
{
"profiles": {
"WebApplication1": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:7146;http://localhost:5257",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Staging"
}
}
}
}
8.重建并执行专案,于开启的Browser视窗内,可以看到系统依照测试环境:\config\Staging\appsettings.json
的设定执行,于画面显示SqlMessageRepository回传的Hello World By Staging Database。
9.最后将ASPNETCORE_ENVIRONMENT的内容改为Production,重建并执行专案,于开启的Browser视窗内,可以看到系统依照正式环境:\config\Production\appsettings.json
的设定执行,于画面显示SqlMessageRepository回传的Hello World By Production Database。