諾禾、.net core下運用事情總線

.net core下運用事情總線

  隨着微效勞的火熱,DDD(範疇驅動設計方式)思想風起雲湧,衝擊着整個軟件生態系統。其中,事情總線那是必需知道的了,於是我便抱着一個學習DDD的心態搭建了一個博客網站,目前該網站正在樹立階段,後續會不時完善,這裏我只是講一下我裏面所用到的事情總線。
  事情總線,我的理解就是發佈訂閱方式,這裏有一篇文章寫的比較好,我就是按着這個文章來完成的事情總線:事情總線知幾。我之前按照他的文章別離自己寫的,但是今天又看了下自己寫的,發現好多都生疏了,所以覺得有必要來回想下,這裏只是我個人的理解,如有不對請指出。

 事情總線就肯定要有事情源,這裏我定義一個Command事情源:   

1
2
3
4
5
6
7
///
/// 範疇命令基類(此處文章裏我稱之爲事情源)
///
public class Command
{

}
 然後我根據事情源來定義一個事情源處置的接口和它的完成類:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
///
/// 創建用戶範疇命令(創建事情源)
///
public class CreateUserCommand: Command
{
public CreateUserCommand(User user)
{
User = user;
}
public User User { get; private set; }

}
///
/// 用戶命令處置程序(處置事情源)
///
public class UserCommandHandler : ICommandHandler,
{
private readonly IUserRepository _userRepository;
private readonly IEventBus _eventBus;
public UserCommandHandler(IUserRepository userRepository, IEventBus eventBus)
{
_userRepository = userRepository;
_eventBus = eventBus;
}

public void Handler(CreateUserCommand command)
{
    int count = _userRepository.SelectCountByAccount(command.User.Account);
    if (count > 0)
    {
        _eventBus.RaiseEvent(new NotifyValidation("該賬號已存在"));
        return;
    }
    _userRepository.Insert(command.User);
}

}
此處我覺得曾經完成了關於事情源的功用,那麼我們就來思索根據這個事情源來處置發佈訂閱的關係。

 就那註冊用戶功用來說,前面曾經將註冊用戶的事情源曾經寫好了,那麼發佈訂閱怎樣處置呢?首先,我們應該清楚一個邏輯,那就是頁面生成用戶信息,後端獲取信息生成UserModel,然後我們根據UserModel轉爲我們需求的CreateUserCommand,然後我們ICommandHandler根據CreateUserCommand來調用Handler,這是一個簡單的調用邏輯。那麼IcommandHnadler怎樣知道調用哪一個Handler呢?那就是我將事情源和事情源處置類存入集合裏面,這樣我以後就會根據Command來獲取到我的ICommandHandler了,又由於.net core遵照依賴注入準繩,所以我需求往容器了注入ICommander和他的完成類,就是UserCommandhandler,這個時分可以說是曾經將事情源都註冊到了內存裏了,以下是我的相關代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
///
/// 暫時存儲類型數組
///
private static Type[] serviceTypes = Assembly.Load(“Blog.Domain”).GetTypes();

private static ConcurrentDictionary<Type, IList> handlerMapping = new ConcurrentDictionary<Type, IList>();

public static IList GetOrAddHandlerMapping(this Type eventType)
{
return handlerMapping.GetOrAdd(eventType,(Type type)=>new List());
}

///
/// 註冊事情總線(事情源)
///
/// ICommandler
/// CreateUserCommand
///
public static void AddEventBus<TImplementation, TService>(this IServiceCollection serviceDescriptors)
{
Type handler = typeof(TImplementation);
Type serviceType = serviceTypes.FirstOrDefault(s => handler.IsAssignableFrom(s));//獲得接口的完成類
if (serviceType == null)
throw new ArgumentNullException(string.Format(“類型{0}未找到完成類”, handler.FullName));
serviceDescriptors.AddTransient(handler, serviceType);//.net core自帶的IOC容器
GetOrAddHandlerMapping(typeof(TService)).Add(handler);//將事情源和事情源處置程序註冊到內存裏,可以說生成了一個訂閱列表
}
   接下來我們再看發佈與訂閱,我要先定義一個發佈訂閱的中間件,

1
2
3
4
5
6
7
8
9
10
11
12
///
/// 中間件
///
public interface IEventBus
{
///
/// 發佈
///
///
///
void Publish(TCommand command) where TCommand : Command;
}
  然後還有它的完成類,處置邏輯就是根據UserCommandHandler去ConcurrentDictionary裏找到它的對應的ICommandHandler,然後在從IOC容器找到ICommandHandler的完成類,然後執行裏面的方法,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public sealed class EventBus : IEventBus
{
private IServiceProvider _serviceProvider;
public EventBus(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
///
/// 發佈事情
///
///
///
public void Publish(TCommand command) where TCommand : Command
{
IList types=typeof(TCommand).GetOrAddHandlerMapping();
if (types == null || types.Count == 0)
throw new ServiceException(“事情總線未註冊:” + typeof(TCommand).Name);
foreach (var type in types)//從訂閱列表裏尋覓
{
object obj = _serviceProvider.GetService(type);
if(type.IsAssignableFrom(obj.GetType()))
{
ICommandHandler handler = obj as ICommandHandler;
if (handler != null)
handler.Handler(command);//
}
}
}
}
  這個時分可以說曾經完成了發佈訂閱,程序生成CreateUserCommand,這裏我的理解爲就是發佈,調用Publish方法,這裏我覺得就是訂閱,然後最後執行Handler完成業務邏輯:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class UserService : IUserService
{
private readonly IUserRepository _userRepository;
private readonly IEventBus _eventBus;
///
/// 根據UserModel轉實體
///
///
///
private User TransferModel(UserModel userModel)
{
return user;
}
public UserService(IUserRepository userRepository, IEventBus eventBus)
{
_userRepository = userRepository;
_eventBus = eventBus;
}
public void Insert(UserModel userModel)
{
userModel.Password = EncrypUtil.MD5Encry(userModel.Password);
var command = new CreateUserCommand(TransferModel(userModel));//創建事情源
_eventBus.Publish(command);//發佈命令
}
}
還有就是最後的IServiceCollection注入了:

1
2
3
4
5
6
7
8
9
10
11
///
/// 效勞集合
///
///
public static void AddServices(this IServiceCollection services)
{
services.AddTransient<IUserRepository, UserRepository>();
services.AddTransient<IUserService, UserService>();
services.AddEventBus<ICommandHandler, CreateUserCommand>();
services.AddTransient<IEventBus,EventBus>()
services.DisposeServiceTypes();
}
  以上就是我對事情總線的細緻應用,希望有大佬能指出我這菜鳥的缺乏指出!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章