【问题标题】:How to initialize AutoMapper in a multi-layer web application based on ASP.NET Core 5?如何在基于 ASP.NET Core 5 的多层 Web 应用程序中初始化 AutoMapper?
【发布时间】:2021-11-08 21:44:11
【问题描述】:

我只是第一次尝试在项目中使用 AutoMapper。我的解决方案包括以下项目:

  • WebApplication:这是实际的 ASP.NET Core 5 Web 应用程序,包含控制器、前端文件 (Angular) 等。

  • BusinessLogic:这包含应用程序的业务逻辑。基本上,在 Web 应用程序中的每个控制器方法中,都会调用 BusinessLogic 的一个或多个函数来获取和/或向前端发送数据到/从前端到/从应用程序使用的多个不同数据源之一

  • DataAccess:这是所有发送或写入数据的函数所在的位置。

  • Model:该项目包含用于表示来自各种数据源的数据的模型类。由 EFCore 搭建的类也位于此处。

在较旧的项目中,我总是直接将脚手架类用于所有内容。在大多数情况下,这工作得很好,但出于各种不同的原因,我不再想这样做(例如,因为类并不总是以我希望它们命名的方式命名,并且修改/扩展它们也非常困难,有时甚至是不可能的)。 因此,我想使用 AutoMapper 将脚手架的类映射到我可以完全控制而不依赖于 EFCore 的类。

我已经将 AutoMapper NuGet 包添加到 DataAccess 项目,因为这是我希望进行映射的地方。现在我的第一个问题是:我在哪里以及如何初始化它? 在教程中,我经常看到人们在 Startup.cs 文件中对其进行初始化,但由于我在 Web 应用程序项目中没有引用 AutoMapper,所以我不能这样做。

显然,我还需要能够在 DataAccess 项目中的不同类中使用 AutoMapper 函数,那么如何在这些类中获取对它的引用?在示例/教程中,这通常是通过依赖注入完成的,但这似乎不适用于我当前的项目架构。但是,如果在我的解决方案中有通过 DI 实现此目的的简单方法,请告诉我,因为我仍然不完全了解如何在多项目解决方案中使用 DI。

这是我想如何使用 AutoMapper 的示例:

Web 应用程序中的控制器方法:

[HttpGet]
public IEnumerable<Project> GetProjects()
{
    using (ProjectManager projectManager = new ProjectManager())
    {
        return projectManager.GetProjects();
    }
}

BusinessLogic 项目中的Manager 类(简化):

public List<Project> GetProjects()
{
    return projectDataAccessor.GetProjects();
}

DataAccess 项目中的访问器类:

public List<Project> GetProjects()
{
    List<Project> projects = new List<Project>();

    foreach (TblProject tblProject in context.TblProjects)
    {
        Project project = <map tblProject into type Project>; // ToDo
        projects.Add(project);
    }

    return projects;
}

如何初始化和使用 AutoMapper 以执行此类操作?

【问题讨论】:

  • 您不必初始化 AutoMapper。很久以前,它只有一个需要一次性初始化的静态 API。现在您可以在任何地方创建映射配置文件、实例化它们并从中创建映射器。

标签: c# asp.net-core entity-framework-core automapper .net-5


【解决方案1】:

如果您真的不想使用依赖注入,您可以使用静态引导程序类来设置映射并访问映射器实例:

// DataAccess project
public static class MapperBootstrapper
{
    private static IMapper _instance;
    internal static IMapper Instance => _instance;
    
    public static void Configure()
    {
        if (_instance != null)
            throw new InvalidOperationException("Already configured");
        
        var config = new MapperConfiguration(
            cfg =>
            {
                cfg.AddProfile<ProjectProfile>();
                // Add more profiles and other mapping
            });
        _instance = config.CreateMapper();
    }
}

使用配置文件,您可以对相关映射逻辑进行分组,例如与Project 模型相关的映射:

// DataAccess project
public class ProjectProfile : Profile
{
    public ProjectProfile()
    {
        CreateMap<ProjectEntity, Model.Project>()
            .ForMember(
                dest => dest.FullName,
                opt => opt.MapFrom(src => $"{src.Area}\\{src.Name}"));
    }
}

在您的Startup.cs 中,您可以使用引导程序类在应用程序的生命周期中尽早设置映射(如果您不希望 WebApplication 项目引用 DataAccess 项目,则需要一个中间类在 BusinessLogic 项目中):

public void ConfigureServices(IServiceCollection services)
{
    DataAccess.MapperBootstrapper.Configure();
    // ...
}

在您的ProjectDataAccessor 中,您可以像这样使用映射器:

public List<Model.Project> GetProjects()
{
    var dbCollection = // Get data from the source
    
    return MapperBootstrapper.Instance
        .Map<List<Model.Project>>(dbCollection);
}

示例基于一些虚拟模型:

// DataAccess project
public class ProjectEntity
{
    public Guid ID { get; set; }
    public string Area { get; set; }
    public string Name { get; set; }
}

// Model project
public class Project
{
    public Guid ID { get; set; }
    public string FullName { get; set; }
}

要查看实际示例,请查看this fiddle

【讨论】:

  • 这不像我“真的不想使用依赖注入”,但我根本不知道这将如何在我的解决方案中的多个项目中工作,所以我自然宁愿不用它。如果可以在不需要大量重构的情况下使用它,那么这对我来说也很好。无论如何,谢谢你的建议!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-21
  • 1970-01-01
  • 1970-01-01
  • 2023-02-26
  • 1970-01-01
相关资源
最近更新 更多