ASP.NET Core使用AutoMapper实现实体映射

一、前言

在实际的项目开发过程中,我们使用各种ORM框架可以使我们快捷的获取到数据,并且可以将获取到的数据绑定到对应的List<T>中,然后页面或者接口直接显示List<T>中的数据。但是我们最终想要显示在视图或者接口中的数据和数据库实体之间可能存在着差异,一般的做法就是去创建一些对应的“模型”类,然后对获取到的数据再次进行处理,从而满足需求。

因此,如果便捷的实现数据库持久化对象与模型对象之间的实体映射,避免在去代码中手工实现这一过程,就可以大大降低开发的工作量。AutoMapper就是可以帮助我们实现实体转换过程的工具。

二、使用AutoMapper实现实体映射

AutoMapper是一个OOM(Object-Object-Mapping)组件,从它的英文名字中可以看出,AutoMapper主要是为了实现实体间的相互转换,从而避免我们每次采用手工的方式进行转换。在没有OOM这类组件之前,如果我们需要实现实体之间的转换,只能使用手工修改代码,然后逐个赋值的方式实现映射,而有了OOM组件,可以很方便的帮助我们实现这一需求。看下面的一个例子。

首先创建一个ASP.NET Core WebApi项目:

添加一个Student实体类:

namespace AutoMapperDemo.Model
{
    public class Student
    {
        public int ID { get; set; }

        public string Name { get; set; }

        public int Age { get; set; }

        public string Gender { get; set; }
    }
}

添加StudentDTO类,跟Student属性一致。

然后添加一个类,模拟一些测试数据:

using AutoMapperDemo.Model;
using System.Collections.Generic;

namespace AutoMapperDemo
{
    public class Data
    {
        public static List<Student> ListStudent { get; set; }

        public static List<Student> GetList()
        {
            ListStudent = new List<Student>();
            for (int i = 0; i < 3; i++)
            {
                Student student = new Student()
                {
                  ID=i,
                  Name=$"测试_{i}",
                  Age=20,
                  Gender="男"
                };
                ListStudent.Add(student);
            }

            return ListStudent;
        }
    }
}

添加Student控制器,通过Get方法获取所有的值:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapperDemo.Model;
using Microsoft.AspNetCore.Mvc;

namespace AutoMapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        [HttpGet]
        public async Task<List<Student>> Get()
        {
            List<Student> list = new List<Student>();
            list = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });
            return list;
        }
    }
}

使用Postman进行测试:

这样返回的数据直接就是数据库对应的实体类类型。这时需求改变了,我们要返回StudentDTO类型的数据,这时就需要修改代码:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;
using Microsoft.AspNetCore.Mvc;

namespace AutoMapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        [HttpGet]
        public async Task<List<Student>> Get()
        {
            List<Student> list = new List<Student>();
            list = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });

            return list;
        }

        [HttpGet("GetDTO")]
        public async Task<List<StudentDTO>> GetDto()
        {
            List<StudentDTO> list = new List<StudentDTO>();
            List<Student>  listStudent = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });
            // 循环给属性赋值
            foreach (var item in listStudent)
            {
                StudentDTO dto = new StudentDTO();
                dto.ID = item.ID;
                dto.Name = item.Name;
                dto.Age = item.Age;
                dto.Gender = item.Gender;
                // 加入到集合中
                list.Add(dto);
            }

            return list;
        }
    }
}

还是使用Postman进行测试:

可以看到:这时返回的是DTO类型的数据。这种情况就是我们上面说的,需要手动修改代码,然后循环给对应的属性进行赋值。这里Student类只有4个属性,如果属性非常多,或者很多地方使用到了,如果还是采用这种方式进行赋值,那么就会很麻烦。假如以后其中的一个属性名称改变了,那么所有的地方也都需要修改,工作量就会很大。这时就需要使用AutoMapper解决。

首先引入AutoMapper包,直接在NuGet中引入:

这里选择安装AutoMapper.Extensions.Microsoft.DependencyInjection这个包。这个包主要是为了让我们可以通过依赖注入的方式去使用AutoMapper。

新建StudentProfile类,继承自AutoMapper的Profile类,在无参构造函数中,我们就可以通过 CreateMap 方法去创建两个实体间的映射关系。

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;

namespace AutoMapperDemo.AutoMapper
{
    /// <summary>
    /// 继承自Profile类
    /// </summary>
    public class StudentProfile: Profile
    {
        /// <summary>
        /// 构造函数中实现映射
        /// </summary>
        public StudentProfile()
        {
            // Mapping
            // 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)
            CreateMap<Student, StudentDTO>();
        }
    }
}

这里的 Profile有什么用呢?services.AddAutoMapper他会自动找到所有继承了Profile的类然后进行配置。

然后修改Student控制器,通过构造函数使用AutoMapper的注入,并使用AutoMapper实现自动映射:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;
using Microsoft.AspNetCore.Mvc;

namespace AutoMapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        private readonly IMapper _mapper;

        /// <summary>
        /// 通过构造函数实现依赖注入
        /// </summary>
        /// <param name="mapper"></param>
        public StudentController(IMapper mapper)
        {
            _mapper = mapper;
        }

        [HttpGet]
        public async Task<List<Student>> Get()
        {
            List<Student> list = new List<Student>();
            list = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });

            return list;
        }

        [HttpGet("GetDTO")]
        public async Task<List<StudentDTO>> GetDto()
        {
            List<StudentDTO> list = new List<StudentDTO>();
            List<Student>  listStudent = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });
            //// 循环给属性赋值
            //foreach (var item in listStudent)
            //{
            //    StudentDTO dto = new StudentDTO();
            //    dto.ID = item.ID;
            //    dto.Name = item.Name;
            //    dto.Age = item.Age;
            //    dto.Gender = item.Gender;
            //    // 加入到集合中
            //    list.Add(dto);
            //}

            // 使用AutoMapper进行映射
            list = _mapper.Map<List<StudentDTO>>(listStudent);
            return list;
        }
    }
}

修改Startup类的ConfigureServices方法,添加AutoMapper:

public void ConfigureServices(IServiceCollection services)
{
    #region 使用AutoMapper
    // 参数类型是Assembly类型的数组 表示AutoMapper将在这些程序集数组里面遍历寻找所有继承了Profile类的配置文件
    // 在当前作用域的所有程序集里面扫描AutoMapper的配置文件
    services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());
    #endregion

    services.AddControllers();
}

再次使用Postman进行测试:

可以看到,这样也实现了我们的需求,而且还不需要进行手动映射。

上面的示例中,Student和StudentDTO类里面的属性名称都是一样的,如果属性名称不一样呢?我们把StudentDTO类里面的ID改为StudentID,然后修改映射代码:

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;

namespace AutoMapperDemo.AutoMapper
{
    /// <summary>
    /// 继承自Profile类
    /// </summary>
    public class StudentProfile: Profile
    {
        /// <summary>
        /// 构造函数中实现映射
        /// </summary>
        public StudentProfile()
        {
            // Mapping
            // 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)
            // CreateMap<Student, StudentDTO>();

            // 使用自定义映射 Student类的ID映射到StudentDTO类的StudentID
            CreateMap<Student, StudentDTO>()
                .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); });
        }
    }
}

再次使用Postman进行测试:

这样就实现了自定义映射。这里是映射了一个字段,如果是多个字段不同呢? 修改StudentDTO类:

namespace AutoMapperDemo.DTO
{
    public class StudentDTO
    {
        public int StudentID { get; set; }

        public string StudentName { get; set; }

        public int StudentAge { get; set; }

        public string StudentGender { get; set; }
    }
}

然后修改映射配置类:

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;

namespace AutoMapperDemo.AutoMapper
{
    /// <summary>
    /// 继承自Profile类
    /// </summary>
    public class StudentProfile: Profile
    {
        /// <summary>
        /// 构造函数中实现映射
        /// </summary>
        public StudentProfile()
        {
            // Mapping
            // 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)
            // CreateMap<Student, StudentDTO>();

            // 使用自定义映射 Student类的ID映射到StudentDTO类的StudentID
            //CreateMap<Student, StudentDTO>()
            //    .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); });

            // 对多个属性进行自定义映射
            CreateMap<Student, StudentDTO>()
                .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); })
                .ForMember(destinationMember: des => des.StudentName, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Name); })
                .ForMember(destinationMember: des => des.StudentAge, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Age); })
                .ForMember(destinationMember: des => des.StudentGender, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Gender); });
        }
    }
}

在使用Postman进行测试:

这样就实现了多个属性的自定义映射。

上面的实例中是从Student映射到StudentDTO,那么可以从StudentDTO映射到Student吗?答案是肯定的,只需要在映射的最后使用ReverseMap()方法即可:

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;

namespace AutoMapperDemo.AutoMapper
{
    /// <summary>
    /// 继承自Profile类
    /// </summary>
    public class StudentProfile: Profile
    {
        /// <summary>
        /// 构造函数中实现映射
        /// </summary>
        public StudentProfile()
        {
            // Mapping
            // 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)
            // CreateMap<Student, StudentDTO>();

            // 使用自定义映射 Student类的ID映射到StudentDTO类的StudentID
            //CreateMap<Student, StudentDTO>()
            //    .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); });

            // 对多个属性进行自定义映射
            CreateMap<Student, StudentDTO>()
                .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); })
                .ForMember(destinationMember: des => des.StudentName, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Name); })
                .ForMember(destinationMember: des => des.StudentAge, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Age); })
                .ForMember(destinationMember: des => des.StudentGender, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Gender); })
                // ReverseMap表示双向映射
                .ReverseMap();
        }
    }
}

我们修改Data,里面增加一个Add方法,可以将Student添加到集合中:

using AutoMapperDemo.Model;
using System.Collections.Generic;

namespace AutoMapperDemo
{
    public class Data
    {
        public static List<Student> ListStudent { get; set; }

        static Data()
        {
            ListStudent = new List<Student>();
            for (int i = 0; i < 3; i++)
            {
                Student student = new Student()
                {
                    ID = i,
                    Name = $"测试_{i}",
                    Age = 20,
                    Gender = "男"
                };
                ListStudent.Add(student);
            }
        }

        public static List<Student> GetList()
        {
            return ListStudent;
        }

        public static void Add(Student entity)
        {
            ListStudent.Add(entity);
        }
    }
}

修改Student控制器,添加一个Post方法,传入的参数的StudentDTO类型:

using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;
using Microsoft.AspNetCore.Mvc;

namespace AutoMapperDemo.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController : ControllerBase
    {
        private readonly IMapper _mapper;

        /// <summary>
        /// 通过构造函数实现依赖注入
        /// </summary>
        /// <param name="mapper"></param>
        public StudentController(IMapper mapper)
        {
            _mapper = mapper;
        }

        [HttpGet]
        public async Task<List<Student>> Get()
        {
            List<Student> list = new List<Student>();
            list = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });

            return list;
        }

        [HttpGet("GetDTO")]
        public async Task<List<StudentDTO>> GetDto()
        {
            List<StudentDTO> list = new List<StudentDTO>();
            List<Student>  listStudent = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });
            //// 循环给属性赋值
            //foreach (var item in listStudent)
            //{
            //    StudentDTO dto = new StudentDTO();
            //    dto.ID = item.ID;
            //    dto.Name = item.Name;
            //    dto.Age = item.Age;
            //    dto.Gender = item.Gender;
            //    // 加入到集合中
            //    list.Add(dto);
            //}

            // 使用AutoMapper进行映射
            list = _mapper.Map<List<StudentDTO>>(listStudent);
            return list;
        }

        [HttpPost]
        public async Task<List<Student>> Post([FromBody]StudentDTO entity)
        {
            List<Student> list = new List<Student>();
            // 将StudentDTO反向映射为Student类型
            Student student = _mapper.Map<Student>(entity);
            // 添加到集合中
            Data.Add(student);
            // 返回增加后的数组,这里返回Student
            list = await Task.Run<List<Student>>(() =>
            {
                return Data.GetList();
            });

            return list;
        }
    }
}

使用Postman进行测试:

返回结果:

这样就实现了映射的反转。

具体其它API功能,参考AutoMapper官网:https://automapper.readthedocs.io/en/latest/index.html

到此这篇关于ASP.NET Core使用AutoMapper实现实体映射的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • ASP.NET Core中间件用法与官方常用中间件介绍

    目录 一.什么是中间件 中间件和过滤器的区别 二.中间件常用方法 1.Run方法 2.Use方法 3.Map方法 4.Mapwhen方法 三.自定义中间件 四.官方常用中间件 1.异常处理中间件 2.HTTPS重定向中间件 3.静态文件中间件 4.Cookie中间件 5.路由中间件 6.身份认证中间件 7.授权中间件 8.会话中间件 9.终结点路由中间件 一.什么是中间件 我们都知道,任何的一个web框架都是把http请求封装成一个管道,每一次的请求都是经过管道的一系列操作,最终才会到达我们写的

  • Asp.net core 使用SignalR推送消息过程详解

    1).SignalR简介 ASP.NET Core SignalR 是为 ASP.NET 开发人员提供的一个库,可以简化开发人员将实时 Web 功能添加到应用程序的过程. 实时 Web 功能是指这样一种功能:当所连接的客户端变得可用时服务器代码可以立即向其推送内容,而不是让服务器等待客户端请求新的数据. 2).SignalR主要用途: 它出现的主要用途:可以用在聊天室.Web实时推送消息 (Real-Push-Message).单点和多点通讯.扫码登陆.甚至可以结合其他技术用来做视频聊天等等.

  • ASP.NET Core中使用Swagger

    一.什么是Swagger 随着技术的不断方法,现在的网站开发基本都是使用前后端分离的模式,这样使前端开发者和后端开发者只需要专注自己擅长的即可.但这种方式会存在一种问题:前后端通过API接口的方式进行调用,接口文档的好坏可以决定开发的进度.以前如果使用Word的形式提供接口文档,或多或少的都会存在各种问题.前端抱怨说后端给的接口文档与实际情况不一致.而后端开发人员又觉得编写以及维护接口文档很费精力,文档经常不能及时更新,导致前端看到的还是旧的接口文档.这时候就需要使用Swagger了. 那么什么

  • ASP.NET Core项目中调用WebService的方法

    一.前言 现实生产中,有一些比较老的系统对外提供的接口都是WebService形式的,如果是使用.NET Framework创建的项目调用WebService非常方便,网上有很多代码示例,这里不在讲解,下面我们讲解如何在ASP.NET Core项目里面调用WebService.首先我们需要创建一个WebService项目和一个ASP.NET Core WebApi项目.创建的WebService代码如下: using System.Web.Services; namespace CoreCall

  • ASP.NET Core依赖注入详解

    目录 一.什么是依赖注入 二.使用框架提供的服务 三.注册服务 四.生命周期 五.请求服务 六.设计你的依赖服务 ASP.NET Core的底层设计支持和使用依赖注入.ASP.NET Core应用程序可以利用内置的框架服务将它们注入到启动类的方法中,并且应用程序服务能够配置注入.由ASP.NET Core提供的默认服务容器提供了最小功能集,并不是要取代其它容器. 一.什么是依赖注入 依赖注入(Dependency injection,DI)是一种实现对象及其合作者或依赖项之间松散耦合的技术.将类

  • ASP.NET Core中使用Redis实现缓存

    目录 一.前言 二.安装StackExchange.Redis 三.添加配置 四.Redis帮助类 五.添加服务依赖项 六.在控制器中使用 七.测试 一.前言 我们这里以StackExchange.Redis为例,讲解如何在ASP.NET Core中如何使用Redis实现缓存.首先需要安装Redis和RedisDesktopManager.RedisDesktopManager用来查看Redis缓存里面的数据.如何安装Redis这里不在讲述. 二.安装StackExchange.Redis 在N

  • ASP.NET Core 6.0对热重载的支持实例详解

    目录 一.整体介绍 二.代码示例 1. VS Code新建Blazor Server project 2. dotnet watch 运行 3. 修改index.razor中的代码 总结 .NET 热重载技术支持将代码更改(包括对样式表的更改)实时应用到正在运行的程序中,不需要重启应用,也不会丢失应用状态. 一.整体介绍 目前 ASP.NET Core 6.0 项目都支持热重载.在以下情况下支持应用的热重载: 1. 仅运行一次的应用启动逻辑代码 中间件,除非代码更新是委托给内联中间件进行的. 已

  • ASP.NET Core使用AutoMapper实现实体映射

    一.前言 在实际的项目开发过程中,我们使用各种ORM框架可以使我们快捷的获取到数据,并且可以将获取到的数据绑定到对应的List<T>中,然后页面或者接口直接显示List<T>中的数据.但是我们最终想要显示在视图或者接口中的数据和数据库实体之间可能存在着差异,一般的做法就是去创建一些对应的“模型”类,然后对获取到的数据再次进行处理,从而满足需求. 因此,如果便捷的实现数据库持久化对象与模型对象之间的实体映射,避免在去代码中手工实现这一过程,就可以大大降低开发的工作量.AutoMapp

  • ASP.NET Core扩展库之实体映射使用详解

    在分层设计模式中,各层之间的数据通常通过数据传输对象(DTO)来进行数据的传递,而大多数情况下,各层数据的定义结构大同小异,如何在这些定义结构中相互转换,之前我们通过使用AutoMapper库,但AutoMapper功能庞大,使用较为复杂,而在很多场景下,可能我们只需要一些基础的对象映射功能,那么此时你可以选择扩展库中的轻量级AutoMapper实现. 实体映射包含以下核心功能: 在使用之前无需手动定义类型之间的映射关系 采用动态编译.缓存转换委托,提升性能. 支持通过特性定义属性映射关系 支持

  • ASP.NET Core使用AutoMapper组件

    1.什么是AutoMapper? AutoMapper是一个对象-对象映射器.对象-对象映射通过将一种类型的输入对象转换为另一种类型的输出对象来工作.使AutoMapper变得有趣的是,它提供了一些有趣的约定,免去用户不需要了解如何将类型A映射为类型B.只要类型B遵循AutoMapper既定的约定,就需要几乎零配置来映射两个类型.映射代码虽然比较无聊,但是AutoMapper为我们提供简单的类型配置以及简单的映射测试,而映射可以在应用程序中的许多地方发生,但主要发生在层之间的边界中,比如,UI

  • AutoMapper实体映射基本用法

    目录 AutoMapper安装 AutoMapper 基本使用 映射配置 映射检查 性能 Profile 配置 依赖注入 表达式与 DTO AutoMapper安装 在 Nuget 搜索即可安装,目前笔者使用的版本是 10.1.1,AutoMapper 的程序集大约 280KB. AutoMapper 主要功能是将一个对象的字段的值映射到另一个对象相应的字段中,AutoMapper 大家应该很熟悉,这里就不赘述了. AutoMapper 基本使用 假如两个如下类型: public class T

  • asp.net core实体类生产CRUD后台管理界面

    目录 前言介绍 演示功能 机制设定 1.添加.修改数据 2.列表查询.过滤筛选 3.删除数据 思考人生 前言介绍 喜欢小规模团队的"单打独斗",有的时候即使在大公司,也经常做着3-5个人团队的小项目,相信很多人有类似的经历. 本文介绍如何将项目中已存在的[实体类],直接生产出 CRUD 后台管理界面. 对于通用后台管理系统的生成,除了单纯的对单表 crud 操作外,我还喜欢利用导航属性的操作,比如: 1.Song.Tag 多对多场景,添加/更新 Song 时可以把 Tag 一起保存: 2.列表页

  • .NET CORE中使用AutoMapper进行对象映射的方法

    简介 AutoMapper uses a fluent configuration API to define an object-object mapping strategy. AutoMapper uses a convention-based matching algorithm to match up source to destination values. AutoMapper is geared towards model projection scenarios to flat

  • ASP.NET Core扩展库的相关功能介绍

    亲爱的.Neter们,在我们日复一日的编码过程中是不是会遇到一些让人烦恼的事情: 日志配置太过复杂,各种模板.参数也搞不清楚,每次都要去查看日志库的文档,还需要复制粘贴一些重复代码,好无赖 当需要类型转换时,使用AutoMapper时感觉配置又复杂,自己写人肉转换代码又冗长,又枯燥,好无聊 当调用其他服务时,总是不放心,于是在调用前.调用后总是不断重复地记录请求和应答日志? 当其他服务需要令牌时,我们不得不管理令牌的生命周期,而且不同第三方服务令牌的认证.维护过程还不一样,有时调用每一个接口时都

  • ASP.NET Core MVC学习教程之路由(Routing)

    前言 ASP.NET Core MVC 路由是建立在ASP.NET Core 路由的,一项强大的URL映射组件,它可以构建具有理解和搜索网址的应用程序.这使得我们可以自定义应用程序的URL命名形式,使得它在搜索引擎优化(SEO)和链接生成中运行良好,而不用关心Web服务器上的文件是怎么组织的.我们可以方便的使用路由模板语法定义路由,路由模板语法支持路由值约束,默认值和可选值. 基于约束的路由允许全局定义应用支持的URL格式,以及这些格式是怎样各自在给定的控制器中映射到指定的操作方法(Action

  • Asp.Net Core 中的“虚拟目录”实现

    写在前面 现在部署Asp.Net Core应用已经不再限制于Windows的IIS上,更多的是Docker容器.各种反向代理来部署.也有少部分用IIS部署的,IIS部署确实是又快又简单,图形化操作三下五除二就可以发布好一个系统了.在过去Asp.Net MVC 项目部署的时候,还常常使用IIS一个功能--虚拟目录. 虚拟目录可以直接定位到非项目的其他路径,将路径作为网站的一部分,可实现上传文件保存到其他盘符或间接的使用项目以外的静态文件.在Asp.Net MVC中从虚拟路径中存取文件也很简单,如S

  • 详解如何在ASP.NET Core中编写高效的控制器

    通过遵循最佳实践,可以编写更好的控制器.所谓的"瘦"控制器(指代码更少.职责更少的控制器)更容易阅读和维护.而且,一旦你的控制器很瘦,可能就不需要对它们进行太多测试了.相反,你可以专注于测试业务逻辑和数据访问代码.瘦控制器的另一个优点是,它更容易维护控制器的多个版本. 这篇文章讨论了使控制器变胖的坏习惯,然后探索了使控制器变瘦和易于管理的方法.我列出编写控制器的最佳实践可能并不全面,但我已经讨论了最重要的一些,并在适当的情况下提供了相关的源代码.在接下来的几节中,我们将研究什么是胖控制

随机推荐