1

我试图在我的解决方案中掌握引发/处理领域事件的基础知识。我正在使用 Visual Studio 2017、.Net Core 1.1、C#、StructureMap 4.5.1。

我的代码中的故障在单元测试中暴露出来,该单元测试在检查我的域事件是否被正确引发时失败。

我的Startup.cs课程包括以下代码:

    public IServiceProvider ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton(_config);

        services.AddAutoMapper();

        services.AddMvc()
            .AddControllersAsServices();

        return ConfigureIoC(services);
    }

    public IServiceProvider ConfigureIoC(IServiceCollection services)
    {
        var container = new Container();

        container.Configure(config =>
        {
            config.Scan(scan =>
            {
                scan.AssemblyContainingType(typeof(Startup));
                scan.Assembly("Shared");
                scan.Assembly("TaskScheduling");
                scan.Assembly("TaskScheduling_Tests");
                scan.WithDefaultConventions();
                scan.ConnectImplementationsToTypesClosing(typeof(IHandle<>));

            });

            //Populate the container using the service collection
            config.Populate(services);
        });

        return container.GetInstance<IServiceProvider>();

    }

在可能的情况下,我一直在关注 Udi Dahan 的方法Domain Events - Salvation

My DomainEvents 类实现以下接口:

using System;

namespace Shared.Interfaces
{
    public interface IDomainEvent
    {
        DateTime DateTimeEventOccurred { get; }
    }
}

DomainEvents 类如下:

using System;
using System.Collections.Generic;
using Shared.Interfaces;
using StructureMap;

namespace Shared
{
    /// <summary>
    /// http://udidahan.com/2009/06/14/domain-events-salvation/
    /// http://msdn.microsoft.com/en-gb/magazine/ee236415.aspx#id0400046
    /// 
    /// This class registers Domain Events and makes sure they get called.
    /// </summary>

    public static class DomainEvents
    {
        [ThreadStatic]
        private static List<Delegate> actions;
        public static IContainer Container { get; set; }

        // Registers a callback for the given domain event.
        public static void Register<T>(Action<T> callback) where T : IDomainEvent
        {
            if (actions == null)
            {
                actions = new List<Delegate>();
            }
            actions.Add(callback);
        }

        // Clears callbacks passed to Register on the current thread.
        public static void ClearCallbacks()
        {
            actions = null;
        }

        // Raises the given domain event.
        public static void Raise<T>(T args) where T : IDomainEvent
        {
            foreach (var handler in Container.GetAllInstances<IHandle<T>>())
            {
                handler.Handle(args);
            }

            if (actions != null)
            {
                foreach (var action in actions)
                {
                    if (action is Action<T>)
                    {
                        ((Action<T>)action)(args);
                    }
                }
            }
        }
   }
}

我有一Task门课,更新时会引发TaskUpdatedEvent. TaskUpdatedEvent课程如下:

using Shared.Interfaces;
using System;
namespace TaskScheduling.Model.Events
{
    public class TaskUpdatedEvent : IDomainEvent
    {
        /// <summary>
        /// When creating a TaskUpdatedEvent you have to pass in the Task object.
        /// </summary>
        /// <param name="task"></param>
        public TaskUpdatedEvent(ScheduleAggregate.Task task)
            : this()
        {
            TaskUpdated = task;
        }
        public TaskUpdatedEvent()
        {
            this.Id = Guid.NewGuid();
            DateTimeEventOccurred = DateTime.Now; // IDomainEvent interface requirement.
        }

        public Guid Id { get; private set; }
        public DateTime DateTimeEventOccurred { get; private set; }
        public ScheduleAggregate.Task TaskUpdated { get; private set; }
    }
}

Task并且在我的课堂上通过以下几行引发了该事件:

var taskUpdatedEvent = new TaskUpdatedEvent(this);
DomainEvents.Raise(taskUpdatedEvent);

到目前为止,我只有一个单元测试来检查是否引发了此事件。单元测试如下:

using System;
using NUnit.Framework;
using Shared;
using TaskScheduling.Model.ScheduleAggregate;
using TaskScheduling.Model.Events;

namespace TaskScheduling_Tests
{
    [TestFixture]
    public class TaskUpdatedEventShould
    {
        private Task testTask;
        private readonly Guid testScheduleId = Guid.NewGuid();
        private const int TestLocationId = 567;
        private const int TestDeviceId = 123;
        private const int TestTaskTypeId = 1;
        private readonly DateTime testStartTime = new DateTime(2014, 7, 1, 9, 0, 0);
        private readonly DateTime testEndTime = new DateTime(2014, 7, 1, 9, 30, 0);
        private readonly DateTimeRange newTaskTimeRange = new DateTimeRange(new DateTime(2014, 6, 9, 10, 0, 0), TimeSpan.FromHours(1));
        private const string TestTitle = "Unit Test Title";

        [SetUp]
        public void SetUp()
        {
            DomainEvents.ClearCallbacks();

            testTask = Task.Create(
                testScheduleId,
                TestLocationId,
                TestDeviceId,
                TestTaskTypeId,
                testStartTime,
                testEndTime,
                TestTitle
            );
        }

        [Test]
        public void EntityConstructor_IsNot_Null()
        {
            Assert.IsNotNull(testTask);
        }


        [Test]
        public void RaiseTaskUpdatedEvent()
        {
            // Arrange
            Guid updatedAppointmentId = Guid.Empty;
            DomainEvents.Register<TaskUpdatedEvent>(aue =>
                {
                    // This defines happens when the event is raised/
                    // The 'updatedAppointmentId' is changed from being all zeros to the testTask's id value.
                    updatedAppointmentId = testTask.Id;
                });

            // Act
            testTask.UpdateTime(newTaskTimeRange);

            // Assert
            Assert.AreEqual(testTask.Id, updatedAppointmentId);
        }

    }
}

调用该Raise方法时,故障似乎发生在 DomainEvent 类中。调试显示事件已引发并设置了参数,但是容器是Null这样的,因此foreach循环无法检查处理程序。

我无法弄清楚为什么 Container 是Null,但我确定我一定遗漏了一些明显的东西。欢迎任何建议。

4

0 回答 0