- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我一直在使用 Domain Events pattern一段时间以来 - 它使我们能够在我们的领域层中封装尽可能多的行为,并为我们应用程序的其他部分提供一种很好的方式来订阅领域事件。
目前我们正在使用一个静态类,我们的域对象可以调用它来引发事件:
static class DomainEvents
{
public static IEventDispatcher Dispatcher { get; set; }
public static void Raise<TEvent>(TEvent e)
{
if (e != null)
{
Dispatcher.Dispatch(e);
}
}
}
如您所见,这只不过是 IEventDispatcher
的垫片。它实际上执行调度 或发布 事件的工作。
我们的调度程序实现仅使用我们的 IoC 容器 (StructureMap) 来定位指定事件类型的事件处理程序。
public void Dispatch<TEvent>(TEvent e)
{
foreach (var handler in container.GetAllInstances<IHandler<TEvent>>())
{
handler.Handle(e);
}
}
这在大多数 情况下都可以正常工作。但是,这种方法存在一些问题:
仅当实体成功持久化时才应分派(dispatch)事件
参加以下类(class):
public class Order
{
public string Id { get; private set; }
public decimal Amount { get; private set; }
public Order(decimal amount)
{
Amount = amount;
DomainEvents.Raise(new OrderRaisedEvent { OrderId = Id });
}
}
在Order
构造函数我们提出一个 OrderRaisedEvent
.在我们的应用程序层中,我们可能会创建订单实例,将其添加到我们的数据库“ session ”中,然后提交/保存更改:
var order = new Order(amount: 10);
session.Store(order);
session.SaveChanges();
这里的问题是在我们成功保存订单实体(提交交易)之前引发了领域事件。如果保存失败,我们仍然会发送事件。
更好的方法是将事件排队直到实体被持久化。但是,我不确定如何在维护强类型事件处理程序的同时最好地实现它。
不应创建事件直到实体被持久化
我面临的另一个问题是我们的实体标识符在存储实体之前不会被设置/分配(RavenDB - session.Store
)。这意味着在上面的示例中,传递给事件的订单标识符实际上是 null
.
因为我不确定如何预先实际生成 RavenDB 标识符,一个解决方案可能是延迟事件的创建,直到实体被实际保存,但我又不知道如何最好地实现这个——也许是排队一个集合的 Func<TEntity, TEvent>
?
最佳答案
一种解决方案(如@synhershko 所建议的那样)是将域事件的调度移到域之外。通过这种方式,我们可以确保我们的实体在引发任何事件之前持久化。
但是,我们现在正在将行为从域(它所属的地方)移到我们的应用程序中,只是为了解决我们的持久性技术——我对此不太高兴。
我的只有在实体成功保留时才应分派(dispatch)事件的解决方案是创建一个延迟事件分派(dispatch)器来对事件进行排队。然后,我们将调度程序注入(inject)到我们的工作单元中,确保我们首先持久化/保存我们的实体,然后发出领域事件:
public class DeferredEventDispatcher : IEventDispatcher
{
private readonly IEventDispatcher inner;
private readonly ConcurrentQueue<Action> events = new ConcurrentQueue<Action>();
public DeferredEventDispatcher(IEventDispatcher inner)
{
this.inner = inner;
}
public void Dispatch<TEvent>(TEvent e)
{
events.Enqueue(() => inner.Dispatch(e));
}
public void Resolve()
{
Action dispatch;
while (events.TryDequeue(out dispatch))
{
dispatch();
}
}
}
public class UnitOfWork
{
public void Commit()
{
session.SaveChanges();
dispatcher.Resolve(); // raise events
}
}
基本上这实现了与@synhershko 所建议的相同的东西,但在我的域内保持事件的“引发”。
至于在实体被持久化之前不应创建事件,主要问题是实体标识符是由 RavenDB 在外部设置的。使我的域持久无知且易于测试的解决方案是简单地将 id 作为构造函数参数传递。如果使用 SQL 数据库(通常传递 Guid),这就是我会做的。
幸运的是,RavenDB 确实为您提供了一种使用 hilo 策略生成标识符的方法(因此我们可以保留 RESTful 标识符)。这是来自 RavenDB Contrib项目:
public static string GenerateIdFor<T>(this IAdvancedDocumentSessionOperations session)
{
// An entity instance is required to generate a key, but we only have a type.
// We might not have a public constructor, so we must use reflection.
var entity = Activator.CreateInstance(typeof(T), true);
// Generate an ID using the commands and conventions from the current session
var conventions = session.DocumentStore.Conventions;
var databaseName = session.GetDatabaseName();
var databaseCommands = session.GetDatabaseCommands();
return conventions.GenerateDocumentKey(databaseName, databaseCommands, entity);
}
然后我可以使用它来生成一个 ID 并将其传递到我的实体构造函数中:
var orderId = session.GenerateIdFor<Order>();
var order = new Order(orderId, 1.99M);
关于c# - 延迟域事件的创建和调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20792907/
这是我的本地域名 http://10.10.1.101/uxsurvey/profile/dashboard 在 Controller 中,我为用户列表设置了一个操作 redirect(control
要处理 Canonical URL,最佳做法是执行 301 重定向还是更好地为 www 和非 www 域使用相同的 IP 地址? 例如: 想要的规范 URL/域是 http://example.com
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
1 内网基础 内网/局域网(Local Area Network,LAN),是指在某一区域内有多台计算机互联而成的计算机组,组网范围通常在数千米以内。在局域网中,可以实现文件管理、应用软件共享、打印机
我想创建一个 weblogic 集群,其中有两个托管服务器,每个服务器在物理上独立的远程计算机上运行 根据weblogic文档 All Managed Servers in a cluster mus
我正在运行 grails 3.1.4,但在创建允许我将多个域对象绑定(bind)到其他几个域对象的模式时遇到了问题。作为我正在尝试做的一个例子: 我有三个类(class)。书籍、作者和阅读列表。 作者
我试图使用@count函数来根据它获取数据,但是在没有崩溃报告的情况下它以某种方式崩溃了。 这是代码 class PSMedia: Object { @objc dynamic var id
有谁知道是否有办法只输入字母字符而不输入数字?我想过这样的事情 CREATE DOMAIN countryDomain AS VARCHAR(100) CHECK( VALUE ??? );
我的代码: const checkoutUrl = 'https://example.com/checkout/*' window.onload = startup() function st
一些不是我编写的应用程序,也不是用 PHP 编写的,它为域 www.example.com 创建了一个 cookie。 我正在尝试替换该 cookie。所以在 PHP 中我做到了: setcookie
什么是 oauth 域?是否有任何免费的 oauth 服务?我可以将它用于 StackApps registration 吗? ?我在谷歌上搜索了很多,但找不到答案。 最佳答案 这是redirect_
自从 In October 2009, the Internet Corporation for Assigned Names and Numbers (ICANN) approved the cre
我使用 apache 作为我的应用程序 Web 服务器的代理,并希望即时更改与 sessionid cookie 关联的域名。 该cookie有一个与之关联的.company.com域,我想使用apa
我只想托管一个子域到cloudflare。我不想将主域名的域名服务器更改为他们的域名服务器。真的有可能吗? 最佳答案 是的,这是可能的,但是需要通过CloudFlare合作伙伴进行设置,或者您需要采用
When using socket in the UNIX domain, it is advisable to use path name for the directory directory m
想象两个共享一个域类的 Grails 应用程序。也许是 Book 域类。 一个应用程序被标识为数据的所有者,一个应用程序必须访问域数据。类似于亚马逊和亚马逊网络服务。 我想拥有的应用程序将使用普通的域
我有一个包含字段“URL”的表单。第一部分需要用户在文本框中填写。第二部分是预定义的,显示在文本框的右侧。 例如,用户在文本框中输入“test”。第二部分预定义为“.example.com”。因此,总
如果我要关闭并取消分配 azure 中的域 Controller ,从而生成新的 vm Generationid,我需要采取哪些步骤来恢复它? 最佳答案 what steps do I need to
我想尝试使用 Azure 作为托管提供商(我有一个域)。我读过那篇文章https://learn.microsoft.com/en-us/azure/app-service-web/web-sites
所以.... 我想知道是否有人可以在这方面协助我? 基本上,我已经创建了一个自托管的Docker容器,用作构建代理(Azure DevOps) 现在,我已经开始测试代理,并且由于我们的放置文件夹位于W
我是一名优秀的程序员,十分优秀!