前言
源码地址:
https://github.com/SkylerSkr/Skr3D
好了,我们有了只关心自己的领域层,辛苦持久化的基础设施层。那么又有人问了,领域对象不能直接扔给UI层,要处理一下才能扔给UI层。这里你没有EF了,看你怎么操作。
那么,AutoMapper就走来了!
PS:应用层是很薄的一层,不写任何业务代码,只负责推送请求和返回响应值。
视图模型(Dtos)
我们先来写视图模型,就是扔给UI层的实体
public class OrderViewModel
{
[Key]
public Guid Id { get; set; }
[Required(ErrorMessage = "The Order Name is Required")]
[MinLength(2)]
[MaxLength(100)]
[DisplayName("Name")]
public string Name { get; set; }
public List<OrderItemViewModel> Items { get; set; }
public string Province { get; set; }
public string City { get; set; }
public string County { get; set; }
public string Street { get; set; }
}
public class OrderItemViewModel
{
[Required(ErrorMessage = "The Item Name is Required")]
[MinLength(2)]
[MaxLength(100)]
[DisplayName("Name")]
public string Name { get; set; }
}
/// <summary>
/// 地址
/// </summary>
public class AddressViewModel
{
/// <summary>
/// 省份
/// </summary>
[Required(ErrorMessage = "The Province is Required")]
[DisplayName("Province")]
public string Province { get; set; }
/// <summary>
/// 城市
/// </summary>
public string City { get; set; }
/// <summary>
/// 区县
/// </summary>
public string County { get; set; }
/// <summary>
/// 街道
/// </summary>
public string Street { get; set; }
}
AutoMapper
然后我们用AutoMapper来做VIewModel和Domain(领域实体)的映射
/// <summary>
/// 静态全局 AutoMapper 配置文件
/// </summary>
public class AutoMapperConfig
{
public static MapperConfiguration RegisterMappings()
{
//创建AutoMapperConfiguration, 提供静态方法Configure,一次加载所有层中Profile定义
//MapperConfiguration实例可以静态存储在一个静态字段中,也可以存储在一个依赖注入容器中。 一旦创建,不能更改/修改。
return new MapperConfiguration(cfg =>
{
//这个是领域模型 -> 视图模型的映射,是 读命令
cfg.AddProfile(new DomainToViewModelMappingProfile());
//这里是视图模型 -> 领域模式的映射,是 写 命令
cfg.AddProfile(new ViewModelToDomainMappingProfile());
});
}
}
public class DomainToViewModelMappingProfile : Profile
{
/// <summary>
/// 配置构造函数,用来创建关系映射
/// </summary>
public DomainToViewModelMappingProfile()
{
CreateMap<Order, OrderViewModel>()
.ForPath(d => d.Province, o => o.MapFrom(s => s.Address.Province))
.ForPath(d => d.City, o => o.MapFrom(s => s.Address.City))
.ForPath(d => d.County, o => o.MapFrom(s => s.Address.County))
.ForPath(d => d.Street, o => o.MapFrom(s => s.Address.Street)); ;
CreateMap<OrderItem, OrderItemViewModel>();
}
}
public class ViewModelToDomainMappingProfile : Profile
{
public ViewModelToDomainMappingProfile()
{
//手动进行配置
CreateMap<OrderViewModel, Order>()
.ForPath(d => d.Address.Province, o => o.MapFrom(s => s.Province))
.ForPath(d => d.Address.City, o => o.MapFrom(s => s.City))
.ForPath(d => d.Address.County, o => o.MapFrom(s => s.County))
.ForPath(d => d.Address.Street, o => o.MapFrom(s => s.Street))
.ForPath(d=>d.OrderItem,o=>o.MapFrom(s=>s.Items));
CreateMap<OrderItemViewModel, OrderItem>();
}
}
这里有两个配置文件,Domain到ViewModel还有ViewModel到Domain
领域层实现
有了领域对象和Dtos的映射,接着就是实现应用层了。
/// <summary>
/// 定义 IOrderAppService 服务接口
/// 并继承IDisposable,显式释放资源
/// 注意这里我们使用的对象,是视图对象模型
/// </summary>
public interface IOrderAppService : IDisposable
{
void Register(OrderViewModel OrderViewModel);
IEnumerable<OrderViewModel> GetAll();
}
/// <summary>
/// OrderAppService 服务接口实现类, 继承 服务接口
/// 通过 DTO 实现视图模型和领域模型的关系处理
/// 作为调度者,协调领域层和基础层,
/// 这里只是做一个面向用户用例的服务接口,不包含业务规则或者知识
/// </summary>
public class OrderAppService : IOrderAppService
{
// 注意这里是要IoC依赖注入的,还没有实现
private readonly IOrderRepository _OrderRepository;
// 用来进行DTO
private readonly IMapper _mapper;
public OrderAppService(
IOrderRepository OrderRepository,
IMapper mapper
)
{
_OrderRepository = OrderRepository;
_mapper = mapper;
}
public IEnumerable<OrderViewModel> GetAll()
{
var orders = _OrderRepository.GetAll();
var orderList = orders.ToList();
return _mapper.Map<IEnumerable<OrderViewModel>>(orders);
}
public OrderViewModel GetById(Guid id)
{
return _mapper.Map<OrderViewModel>(_OrderRepository.GetById(id));
}
public void Register(OrderViewModel OrderViewModel)
{
var order = _mapper.Map<Order>(OrderViewModel);
_OrderRepository.Add(order);
_OrderRepository.SaveChanges();
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
第一次跑通项目
那么我们有了应用层,领域层,基础设施层。就有了最简单的DDD的框架,只需要在StartUp中注入简单的IOC就可以使用。
public class NativeInjectorBootStrapper
{
public static void RegisterServices(IServiceCollection services)
{
// ASP.NET HttpContext dependency
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// 注入 应用层Application
services.AddScoped<IOrderAppService, OrderAppService>();
// 领域层 - Memory
services.AddSingleton<IMemoryCache>(factory =>
{
var cache = new MemoryCache(new MemoryCacheOptions());
return cache;
});
// 注入 基础设施层 - 数据层
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<OrderContext>();
}
}
我把这个最简单的体现DDD思想的例子单独建立一个分支,OnlyDDD。
接下来我会加入CQRS+Event来实现微服务。