1

I'm new to ASP.NET Core and I have built an ASP.NET Core MVC with EF Core appplication using Code First approach when creating the database.

Now, I want to use DTOs and AutoMapper in this simple app.

In the code below you may find the Employee.cs from Models folder:

public class Employee
    {
        [Key]
        public int EmployeeId { get; set; }
        [Column(TypeName ="nvarchar(250)")]
        [Required(ErrorMessage ="This field is required.")]
        [DisplayName("Full Name")]
        public string FullName { get; set; }
        [Column(TypeName = "varchar(10)")]
        [DisplayName("Emp. Code")]
        public string EmpCode { get; set; }
        [Column(TypeName = "varchar(100)")]
        public string Position { get; set; }
        [Column(TypeName = "varchar(100)")]
        [DisplayName("Office Location")]
        public string OfficeLocation { get; set; }
    }

Below you may find the EmployeeController.cs file:

public class EmployeeController : Controller
    {
        private readonly EmployeeContext _context;

        public EmployeeController(EmployeeContext context)
        {
            _context = context;
        }

        // GET: Employee
        public async Task<IActionResult> Index()
        {
            return View(await _context.Employees.ToListAsync());
        }


        // GET: Employee/Create
        public IActionResult AddOrEdit(int id = 0)
        {
            if (id == 0)
                return View(new Employee());
            else
                return View(_context.Employees.Find(id));
        }

        // POST: Employee/Create
        // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
        // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> AddOrEdit([Bind("EmployeeId,FullName,EmpCode,Position,OfficeLocation")] Employee employee)
        {
            if (ModelState.IsValid)
            {
                if (employee.EmployeeId == 0)
                    _context.Add(employee);
                else
                    _context.Update(employee);
                await _context.SaveChangesAsync();
                return RedirectToAction(nameof(Index));
            }
            return View(employee);
        }


        // GET: Employee/Delete/5
        public async Task<IActionResult> Delete(int? id)
        {
            var employee =await _context.Employees.FindAsync(id);
            _context.Employees.Remove(employee);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
    }

Additionally, you may find below the Startup.cs file:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<CookiePolicyOptions>(options =>
            {
                // This lambda determines whether user consent for non-essential cookies is needed for a given request.
                options.CheckConsentNeeded = context => true;
                options.MinimumSameSitePolicy = SameSiteMode.None;
            });


            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

            services.AddDbContext<EmployeeContext>(options => 
            options.UseSqlServer(Configuration.GetConnectionString("DevConnection")));
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Home/Error");
            }

            app.UseStaticFiles();
            app.UseCookiePolicy();

            app.UseMvc(routes =>
            {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Employee}/{action=Index}/{id?}");
            });
        }
    }

What changes should I make to my app in order to use DTOs and AutoMapper?

Please let me know whether you need other files from the app.

Thanks.

onetwo
  • 13
  • 1
  • 4

1 Answers1

0

You can do following steps.

  1. Create your EmployeeDTO.cs
public class EmployeeDTO
{
    public int EmployeeId { get; set; }
    public string FullName { get; set; }
    public string EmpCode { get; set; }
    public string Position { get; set; }
    public string OfficeLocation { get; set; }
}
  1. Install the corresponding NuGet package

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Note : If we install the AutoMapper.Extensions.Microsoft.DependencyInjection package, it will automatically install the AutoMapper package for us since it references it.

  1. Create MappingProfile.cs

Add using AutoMapper;

public class MappingProfile : Profile
{
    public MappingProfile()
    {
          CreateMap<Employee, EmployeeDTO>();
          CreateMap<EmployeeDTO, Employee>();
    }
}
  1. Configure the services. Let’s do it in the Startup.cs class.
services.AddAutoMapper(typeof(Startup));
  1. First, we inject the mapper object into the controller. Then, we call the Map()method, which maps the Employee object to the EmployeeDTO object.
public class EmployeeController : Controller
{
     private readonly EmployeeContext _context;
     private readonly IMapper _mapper;

     public EmployeeController(EmployeeContext context,, IMapper mapper)
     {
         _context = context;
         _mapper = mapper;
     }

     // GET: Employee
     public async Task<IActionResult> Index()
     {

        List<EmployeeDTO> employees = _mapper.Map<List<Employee>, List<EmployeeDTO>>(await _context.Employees.ToListAsync());
        return View(employees);
     }
}
  • It wasn't me that downvoted your answer, but you are registering AutoMapper wrong. Whole sense of using `AutoMapper.Extensions.Microsoft.DependencyInjection` NuGet package is to leverage extension methods it provides for `IServiceCollection`. Calling `.AddAutoMapper()` like shown in [here](https://automapper.readthedocs.io/en/latest/Dependency-injection.html#asp-net-core), also registers other services like value resolvers etc., which you would have to register manually. – Prolog Jan 19 '20 at 10:45
  • See the [source code](https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/src/AutoMapper.Extensions.Microsoft.DependencyInjection/ServiceCollectionExtensions.cs) if you will. – Prolog Jan 19 '20 at 10:45
  • @Prolog ```services.AddAutoMapper(typeof(MappingProfile));``` . this is correct right. – Binara Thambugala Jan 19 '20 at 12:01
  • 1
    Yes, `services.AddAutoMapper(typeof(Startup))` is fine as long as OP keeps Mapping Profiles in the same assembly as `Startup` class, but generally it should be fine. – Prolog Jan 19 '20 at 14:54