【问题标题】:ASP.NET MVC multilayered application: where to place Automapper initialization? [closed]ASP.NET MVC 多层应用程序:Automapper 初始化放置在哪里? [关闭]
【发布时间】:2015-09-28 08:51:32
【问题描述】:

我正在创建一个多层应用程序,将 asp.net mvc 应用程序作为最高层。

架构如下(---> 表示引用):

表示层--->服务层--->业务层---->数据访问层---->数据库

此外,还有一个名为“Infrastracture”的层被所有层引用。

每一层都有自己的实体。例如:在表示层我们可能有 UserViewModel,在服务层 UserDTO,在业务层 UserBDO,最后,在数据访问层,User。

automapper 用于自动化不同类型之间的转换。

我读到一些开发人员建议将映射创建放在 Global.asax 中,但很明显,如果您有一个多层应用程序,则无法在其中创建所有映射。您不能在表示层中将 User 与 UserBDO 映射。

所以,我正在寻求一种最简洁的方式来管理多层应用程序中的映射集中化。您甚至可以建议对架构进行更改。

【问题讨论】:

  • 你有没有实用程序或框架之类的层,在那里你可以公开一个可以输入 fromTYPE 和 ToTYPE 并转换的函数
  • 你需要一个实用项目或类似的东西。您将枚举(命名法)保存在哪里?
  • Oooooooone 快速说明,如果您只有一个已部署的应用程序,请不要创建所有这些项目。只需在单个 MVC 项目中使用文件夹即可。
  • @Errore Fatale 如果这只是一个预测,那么创建 n 层架构仍然没有任何理由:)
  • 项目应该被视为物理可重用性的单位。如果没有其他东西共享所有这些项目,那么将它们合并到一个项目中。随着需求的变化进行重构,而不是之前。

标签: c# asp.net-mvc automapper multi-layer


【解决方案1】:

我建议您已经有了答案 - 如果您无法在一个地方访问所有类型 - 只需将映射配置拆分为几个部分。这个解决方案在大型项目中更易于维护(想象一下在一个配置中有 100 或 1000 个映射)。例如,我们使用特定的映射器将第三方 WCF 合同转换为自定义 DTO。此映射器与 WCF 客户端一起位于单独的项目中。因此无法从外部访问合约和映射。

【讨论】:

  • 那么,您是否在类的构造函数中调用映射,将一种类型转换为另一种类型?还是您有不同的方法?
  • 是的,我们不直接调用Mapper 方法。相反,类包装器与它自己的Map 方法一起使用(Mapper.Map 的简单包装器)。这个类还有一个包含Mapper.CreateMap调用的静态构造函数(所以我们确定配置是在Mapper.Map调用之前创建的,并且只创建了1次)。
  • 你需要所有这些层吗?尝试从简单的实体和您的 MVC 视图模型/模型开始。尝试将您的项目折叠到文件夹中以使用命名空间。这样做是否会失去任何有意义的东西。在新建项目中使用自动映射器通常表明事情已经太复杂了。
  • @Ilya Chumakow 在 WCF 服务的上下文中,您会在服务的构造函数中调用 CongifureAllMappings() 方法吗?问题是,如果服务是无状态的,则每次调用服务时都会调用 ConfigureAllMappings() 方法。这是必要的吗?映射的“生命周期”是什么?它们是静态资源,对吗?所以他们一直活着,直到托管服务的进程还活着,对吧?
  • @ErroreFatale,是的,映射是静态的(默认情况下),并且每个 AppDomain stackoverflow.com/questions/4984358/static-variables-in-wcf 创建一次静态资源。此外,还可以管理 WCF 服务的生命周期codeproject.com/Articles/86007/…
【解决方案2】:

我尝试回答我自己的问题:如果有任何对您不利的地方,请随时纠正我。

我会用下面的话:

  • 层:在这种情况下,层是垂直意义上的应用程序模块(从数据库到用户界面)

  • 模块:横向意义上的应用程序区域,例如“CRM”、“产品”、“会计”……每个模块的代码位于不同的层。

如果您的应用程序分为 n 层和 n 个模块,则以下可能是特定模块和层的特定类的示例。

public static class ProductMapper
{
    static ProductMapper()
    {
        MapProductBDOToDTO();
        MapProductDTOToBDO();

        MapProductCategoryBDOToDTO();
        MapProductCategoryDTOToBDO();

        MapIvaBDOToDTO();
        MapIvaDTOToBDO();

        MapProductSupplierBDOToDTO();
        MapProductSupplierDTOToBDO();

        MapProductPictureBDOToDTO();
        MapProductPictureDTOToBDO();

        MapProductNoteBDOToDTO();
        MapProductNoteDTOToBDO();

        MapStockProductBDOToDTO();
        MapStockProductDTOToBDO();

        MapTagBDOToDTO();
        MapTagDTOToBDO();
    }


    public static TTargetType Convert<TToConvert, TTargetType>(TToConvert toConvert)
    {
        return Mapper.Map<TTargetType>(toConvert);
    }


    private static void MapProductDTOToBDO()
    {
        Mapper.CreateMap<ProductDTO, ProductBDO>();
    }

    private static void MapProductBDOToDTO()
    {
        Mapper.CreateMap<ProductDTO, ProductBDO>().ReverseMap();
    }

    private static void MapProductCategoryDTOToBDO()
    {
        Mapper.CreateMap<ProductCategoryDTO, ProductCategoryBDO>();
    }

    private static void MapProductCategoryBDOToDTO()
    {
        Mapper.CreateMap<ProductCategoryBDO, ProductCategoryDTO>();
    }

    private static void MapIvaDTOToBDO()
    {
        Mapper.CreateMap<IvaDTO, IvaBDO>();
    }

    private static void MapIvaBDOToDTO()
    {
        Mapper.CreateMap<IvaBDO, IvaDTO>();
    }

    private static void MapProductSupplierDTOToBDO()
    {
        Mapper.CreateMap<ProductSupplierDTO, ProductSupplierBDO>();
    }

    private static void MapProductSupplierBDOToDTO()
    {
        Mapper.CreateMap<ProductSupplierDTO, ProductSupplierBDO>().ReverseMap();
    }

    private static void MapProductPictureDTOToBDO()
    {
        Mapper.CreateMap<ProductPictureDTO, ProductPictureBDO>();
    }

    private static void MapProductPictureBDOToDTO()
    {
        Mapper.CreateMap<ProductPictureDTO, ProductPictureBDO>().ReverseMap();
    }

    private static void MapProductNoteDTOToBDO()
    {
        Mapper.CreateMap<ProductNoteDTO, ProductNoteBDO>();
    }

    private static void MapProductNoteBDOToDTO()
    {
        Mapper.CreateMap<ProductNoteDTO, ProductNoteBDO>().ReverseMap();
    }

    private static void MapStockProductDTOToBDO()
    {
        Mapper.CreateMap<StockProductDTO, StockProductBDO>();
    }

    private static void MapStockProductBDOToDTO()
    {
        Mapper.CreateMap<StockProductDTO, StockProductBDO>().ReverseMap();
    }

    private static void MapTagDTOToBDO()
    {
        Mapper.CreateMap<TagDTO, TagBDO>();
    }

    private static void MapTagBDOToDTO()
    {
        Mapper.CreateMap<TagDTO, TagBDO>().ReverseMap();
    }

如您所见,它是一个带有静态构造函数的静态类,这意味着构造函数在应用程序生命周期内被调用的次数不会超过一次。 第一次调用 Convert 方法时,会调用构造函数并创建所有映射。 第二次、第三次、第四次……你在同一个会话中调用 Convert 方法的 n 次,构造函数将不会被调用。

优点:

  • 不能多次创建特定映射
  • 映射仅在您需要时创建(在这种情况下,当您使用产品时)。您不会在应用程序启动时创建 1000 个映射,然后只使用其中的 5 个或 6 个。

缺点:

  • 开发人员可以使用他/她想要的所有类型调用通用 Convert 方法,不检查类型。顺便说一句,使用泛型方法需要的代码更少,如果尚未创建映射,AutoMapper 将抛出异常。

【讨论】:

    猜你喜欢
    • 2012-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多