user616076
user616076

Reputation: 4001

How do I map the DTO files to my Models in my .Net Core project

I've never worked with a .Net Core project before but have a history with .Net including MVC and entity framework. I'm working with a new .Net Core project which has five solution folders, EHA.PROJ.API, EHA.PROJ.DTO,EHA.PROJ.Repository, EHA.PROJ.Repository.Test and EHA.PROJ.Web. The EHA.PROJ.DTO folder has a number of files such as CategoryDTO.cs which looks like this

namespace EHA.PROJ.DTO
{
    public class CategoryDescDTO
    {
        public int CategoryRef { get; set; }

        public string CategoryName { get; set; }
    }
}

I'm looking to set up a mapping arrangement to get the data from the EHA.PROJ.DTO files to the model files in my models folder in my EHA.PROJ.Web folder. I've been browsing as I've never done anything like this before as I've previously worked with data from a DAL folder using entity framework and connection done through connection strings. I'm guessing that there must be some process to map the data in my dbContext to connect the files in both folders. I did find some information on AutoMapper but was unsure how to implement it.

This arrangement with .Net Core is new to me so if anyone can help with any examples or point me in the right direction I would be grateful.

Upvotes: 1

Views: 13683

Answers (3)

umutesen
umutesen

Reputation: 2640

I have been using Automapper for quite some time in .NET Core projects due to ease of use and built-in dependency injection.

Install from PM:

Install-Package AutoMapper
Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Register in the Startup.cs, ConfigureServices method:

services.AddAutoMapper(typeof(Startup));

Create a class to keep your mappings, e.g. MappingProfile.cs using Profile from automapper, you can define mappings.

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Operator, OperatorDto>().ReverseMap();
    }
}

}

The above mapping tells automapper that Operator can be mapped to OperatorDto and OperatorDto can be mapped to Operator.

In your controller, you can inject an IMapper

    private readonly IMapper _mapper;

    public OperatorsController(IMapper mapper)
    {
        _mapper = mapper;
    }

and map values like below:

var dto = _mapper.Map<OperatorDto>(op); // Map op object to dto

var op = _mapper.Map<Operator>(dto); // Map dto to op object

Automapper offers custom mappings, should you need it.

While it is very easy to perform mappings with Automapper, you need to learn the framework.

I believe it is worth the effort to learn it as it will save you a lot of time writing mapping code in the future.

Upvotes: 3

MarioMendieta
MarioMendieta

Reputation: 312

This article is a good reference to start: https://buildplease.com/pages/repositories-dto/

My suggestion is to have a DTO assembler that maps your model to the DTO object. So, you start with your DTO class:

namespace EHA.PROJ.DTO
{
    public class CategoryDescDTO
    {
        public int CategoryRef { get; set; }

        public string CategoryName { get; set; }
    }
}

Then build the assembler:

public class CategoryDescAssembler {
    public CategoryDescDTO WriteDto(CategoryDesc categoryDesc) {
        var categoryDescDto = new CategoryDescDTO();
        categoryDescDto.CategoryRef = categoryDesc.CategoryRef;
        categoryDescDto.CategoryName = categoryDesc.CategoryName;
        return categoryDescDto;
    }
}

Now you implement the service to do all the work required to get the DTO object:

public class CategoryDescService : ICategoryDescService {
    private readonly IRepository<CategoryDesc> _categoryDescRepository;
    private readonly CategoryDescAssembler _categoryDescAssembler;

    public CategoryDescService(IRepository<CategoryDesc> categoryDescRepository, CategoryDescAssembler categoryDescAssembler) {
        _categoryDescRepository= categoryDescRepository;
        _categoryDescAssembler= categoryDescAssembler;
    }

    public CategoryDescDTO GetCategoryDesc(int categoryRef) {
        var categDesc = _categoryDescRepository.Get(x => x.CategoryRef == categoryRef);
        return _categoryDescAssembler.WriteDto(categDesc);
    }
}

With the interface looking like this:

public interface ICategoryDescService
{
    CategoryDescDTO GetCategoryDesc(int categoryRef);
} 

You would then need to add the service to your Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddTransient<ICategoryDescService, CategoryDescService>();
}

Now you can call your service from you view controller.

Upvotes: 1

Chris Pratt
Chris Pratt

Reputation: 239270

Your first problem is having your entities in your web project. Right off the bat, you have tight-coupling between the web project and your data layer, which then pretty much negates the point of all your other layers: DTO, repository, etc. You want to move out your entities and context into a true data layer (i.e. a class library project separate from your web project).

Then, you want to decide how far your data layer should extend. If the API is to feed the Website, then you want to actually remove all dependencies on the data layer from the web project. Your DTO project would be shared between the API and Web projects and your API would send/receive your DTOs, mapping back and forth from your entities under the hood.

However, if you're going to do that, then the repository project should just go away entirely. Just have your API work directly with EF and your entities. Your abstraction is the API itself; there is no need for another. The only reason to have the repository layer is if both the API and Web will both directly utilize the repositories, which isn't a very good pattern actually. You'll inevitably end up with a bunch of duplicated logic specific to each project.

Simply, the repository pattern is superfluous when using an ORM like EF. The ORM is your data layer. You're simply using a DAL provided by a third-party, rather than one you created yourself. The repository pattern only makes sense when working directly with SQL using something like ADO.NET directly. Otherwise, get rid of it.

Having an API is enough of an abstraction, if your goal is simply to hide the data layer. The website knows nothing of the underlying data source, and an API is really just a service layer that returns JSON over HTTP rather than object instances directly, i.e. the API is essentially your "repository" layer.

The situation can be improved even further by moving to a microservices-based architecture. With that, you essentially have multiple small, self-contained APIs that work with just one part of your domain or piece of functionality. Each can utilize EF directly, or an entirely different ORM, or even an entirely different stack. You could have APIs build on Node.js or python, etc. The website simply makes requests to the various services to get the data it needs and doesn't know or care how those services actually work.

Upvotes: 5

Related Questions