asp.Net   发布时间:2022-04-07  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了eShopOnWeb 知多少大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/fa8dc7a8f326b22f3c1bf13ad01901bd.png" >

是基于ASP.NET Core构建,官方创建这样一个示例项目的目的,我想无非以下几点:

  1. 推广ASP.NET Core
  2. 指导利用ASP.NET Core如何进行架构设计
  3. 普及架构设计思想

eShopOnWeb 与另外一个eShopOnContainers互相补充。eShopOnContainers是基于微服务和容器技术的应用程序架构,支持多重部署。而eShopOnWeb相较于它就简单的多,其是基于传统Web应用开发,仅支持单一部署。

本文就简单梳理下自己的所学所得。

eShopOnWeb的示例项目中包含两个Web项目,一个是基于MVC创建的MPA多页面应用,一个是基于Razor创建的SPA单页面应用。在此之间我该如何选择呢?

  1. 是否需要丰富的交互行为?
  2. 是否足够的前端技术积累?
  3. 是否主要通过API进行交互?

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/d0a57b5b633fde1689d0440c3039813a.png" >

eShopOnWeb中应用了DDD和整洁架构的部分思想,值得了解一下。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/2c9578b64d2a0f6190630dda58401630.png">

传统的分层架构是大家所熟知的三层架构。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/ff7cf5126d4d43a6dd013cee55eae01e.png" >

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/5834a418e0c0b4511466669d5adb8cc6.png" >

这样的架构的缺点是:

  1. 依赖关系由上至下,不易解耦
  2. 不易测试,需要测试数据库

那如何解决三层架构的问题呢,借助【依赖倒置原则】。 DDD的分层架构思想和整洁架构中都是借助【依赖倒置原则】实现层与层之间强依赖关系的解耦。我们来看下整洁架构:

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/55e3446bc173a9f7d6198a9631ab8c1c.png" >

从该洋葱视图中我们可以看到

  1. 依赖关系由外而内。
  2. 处于核心的是实体和接口,不依赖任何其他项。其次是领域服务,仅依赖实体和接口,也相对独立。它们统称为应用程序内核
  3. 应用程序内核之外是基础架构层和展现层,彼此也不一定依赖。

由于应用程序内核不依赖于基础设施层,所以可以很容易编写单元测试。https://cn.js-code.com/res/2019/02-08/23/91ab3bbf62156ca8988d0cea8f0ce477.png" alt="单元测试位置"> 由于UI层也不直接依赖于基础设施层,所以我们可以轻松置换基础设施层的实现(比如使用内存数据库),以进行集成测试。https://cn.js-code.com/res/2019/02-08/23/516bad03d4c6695532d28d37419262fc.png" alt="集成测试位置">

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/6d5f3fa611912a416a9a54426d10804f.png" >

下面我们就来看看eShopOnWeb是如何应用整洁架构的。

首先我们看下模板架构的项目结构。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/3ae454312f469a756086e898efe34ef5.png" >

从上图来看其项目结构十分简单,简单的三层,加上三个测试项目。 三层对应:

  1. ApplicationCore:领域层
  2. Infrastructure:基础设施层
  3. Web/WebRazorPages:展现层

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/2c78df8e30593d8eb419d1695486d960.png" >

其实该项目架构是DDD经典四层架构,只不过其将应用层集成到展现层中去了。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/a0d70fe8158d74bf53ba2dd961c5ae61.png" >

主要提供通用的基础服务和持久化。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/c16e1835f54215edc01d501d03614d37.png" >

从上图的代码结构我们可以看出

  1. 在Data文件夹下定义了用于持久化的商品目录数据库上下文CatalogContext和泛型仓储EfRepository
  2. Identity文件夹下定义了身份数据库上下文的。
  3. Logging文件夹定义了一个日志适配器。
  4. services定义了一个通用的邮件发送基础服务。

领域层是一个项目的核心,用来定义业务规则并实现。其主要用来实体、值对象、聚合、仓储、领域服务和领域事件等。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/2239fdf6effbd85437a5254e8287fa1e.png" >

从上图来看:

  1. Entities文件夹下定义了三个聚合根和相关的实体及值对象。
  2. Exceptions文件夹定义了公共的异常。
  3. Interfaces文件夹定义了系列接口。
  4. services文件夹定义了两个领域服务。
  5. Specifications文件夹下是实现的规约模式。

这里我们来看下聚合根的相关定义和实现。

///抽象的聚合根空接口
public interface IAggregateRoot
    { }
//所有的实体基类
public class BaseEntity
    {
        public int id { get; set; }
    }

//购物车聚会根
public class Basket : BaseEntity,IAggregateRoot
{
public String BuyerId { get; set; }
private readonly List _items = new List();
public IReadOnlyCollection Items => _items.AsReadOnly();

public void AddItem(int catalogItemId,decimal unitPrice,int quantity = 1)
{
    if (!Items.Any(i => i.CatalogItemId == catalogItemId))
    {
        _items.Add(new BasketItem()
        {
            CatalogItemId = catalogItemId,Quantity = quantity,UnitPrice = unitPrice
        });
        return;
    }
    var exisTingItem = Items.FirstOrDefault(i => i.CatalogItemId == catalogItemId);
    exisTingItem.Quantity += quantity;
}

}

从这个实现中我们可以学习到:

这样做的体现了什么思想:

  1. 面向接口编程
  2. 约定大于配置
  3. 依赖注入

为什么这样做?

  1. 因为实体的特征是具有唯一的身份标识,所以通过在父类来定义Id属性来实现。这也就是层超类型的实现方式。

这样做有什么缺点? 因为所有实体的主键类型不一定都是int类型,所以这个基类型最好改成泛型。

仓储是用来透明持久化领域对象的。

public interface IRepository where T : BaseEntity
{
    T GetById(int id);
    T GetSingleBySpec(ISpecification spec);
    IEnumerable ListAll();
    IEnumerable List(ISpecification spec);
    T Add(T entity);
    void update(T entity);
    void @R_450_9421@e(T entity);
}
public interface IAsyncRepository where T : BaseEntity
{
    Task GetByIdAsync(int id);
    Task> ListAllAsync();
    Task> ListAsync(ISpecification spec);
    Task AddAsync(T entity);
    Task updateAsync(T entity);
    Task @R_450_9421@eAsync(T entity);
}

从以上代码我们可以学到两点:

  1. 面向接口编程
  2. 职责分离,同步异步接口分离。

领域服务用来实现业务逻辑的。

public interface Iorderservice
{
    Task CreateOrderAsync(int basketId,Address shippingAddress);
}
public class orderservice : Iorderservice
{
    private readonly IAsyncRepository _orderRepository;
    private readonly IAsyncRepository _basketRepository;
    private readonly IAsyncRepository _itemRepository;
    public orderservice(IAsyncRepository basketRepository,IAsyncRepository itemRepository,IAsyncRepository orderRepository)
    {
        _orderRepository = orderRepository;
        _basketRepository = basketRepository;
        _itemRepository = itemRepository;
    }
    public async Task CreateOrderAsync(int basketId,Address shippingAddress)
    {
        var basket = await _basketRepository.GetByIdAsync(basketId);
        Guard.Against.NullBasket(basketId,basket);
        var items = new List();
        foreach (var item in basket.Items)
        {
            var catalogItem = await _itemRepository.GetByIdAsync(item.CatalogItemId);
            var itemordered = new CatalogItemordered(catalogItem.Id,catalogItem.Name,catalogItem.PictureUri);
            var orderItem = new OrderItem(itemordered,item.UnitPrice,item.Quantity);
            items.Add(orderItem);
        }
        var order = new Order(basket.buyerId,shippingAddress,items);
        await _orderRepository.AddAsync(order);
    }

从以上代码我们可以学习到:

  1. 依赖注入
  2. 领域服务负责实现真正的业务逻辑

如上面所阐述,在示例项目中应用层和展现层合二为一。应用层负责展现层与领域层之间的协调,协调业务对象来执行特定的应用程序。

eShopOnWeb中也提到了AOP,介绍了在ASP.NET Core中如何应用过滤器来进行AOP,比如:身份验证、模型验证、输出缓存和错误处理等。

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/728b50d77080ac9bcd2f76a6a4726b4e.png" >

title="eShopOnWeb 知多少" alt="eShopOnWeb 知多少" src="https://cn.js-code.com/res/2019/02-08/23/96ad3f0ceBAC50763d0bd0d4f5ace4fa.png" >

在eShopOnWeb中,也对DDD的概念,是否使用,何时使用,何时不用,都略有介绍。这里就摘录一二,当然也可以参我之前的写的

  1. DDD首先是一个方法论,其注重于领域的合理建模,分为战略建模和战术建模。
  2. 如果你不知道你需要它,那么你可能不需要它。
  3. 如果你不知道到DDD用于解决什么问题,那么你可能没有遇到这些问题。
  4. DDD倡导者也经常指出其仅适用于大型项目 (>6个月)。
  1. DDD是用来对真实世界系统或流程的建模。
  2. 使用DDD时,你需要和领域专家紧密合作,领域专家能够解释真实的系统该如何运行。在和领域专家的交流中确定通用语言,其主要用来描述系统中的一些概念。而之所以是通用,是因为不管是开发人员还是领域专家都应能够读懂。而通用语言描述的概念将构成面向对象设计的基础。其体现在代码中的理想状态是代码即设计
  1. 值对象:不可变。
  2. 实体:具有唯一标识符可变。
  3. 聚会根:在DDD中,用来表示整体与部分的关系,聚合是将相关联的领域对象进行显式分组,来表达整体的概念(也可以是单一的领域对象)。比如将表示订单与订单项的领域对象进行组合,来表达领域中订单这个整体概念。
  4. 仓储:一种持久化的模式,用于隔离具体持久化措施,实现透明持久化。
  5. 工厂:用于对象的创建。
  6. 服务:应用服务和领域服务。领域服务负责业务逻辑,应用服务用于表达业务用例和用户故事。
  1. 限界上下文:来为领域提供上下文语境,保证在领域之内的一些术语、业务相关对象等(通用语言)有一个确切的含义,没有二义性。
  2. 上下文映射图:限界上下文之间的关联关系。

在eShopOnWeb中,还示例了三个测试项目,来指导我们合理的进行测试。

eShopOnWeb 知多少

总体而言,示例项目简单容易理解,也主要是为了便于推广和演示。但里面涉及的知识点并没有想象的那么简单,从架构原则到设计和应用,每一个环节都包含不简单的知识体系。

所以等什么呢?结合和官方文档https://docs.microsoft.com/zh-cn/dotnet/standard/modern-web-apps-azure-architecture/">使用 ASP.NET Core 和 Azure 构建新式 Web 应用程序开始学习吧,相信你也会收获颇丰。

大佬总结

以上是大佬教程为你收集整理的eShopOnWeb 知多少全部内容,希望文章能够帮你解决eShopOnWeb 知多少所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。

标签: