1
votes

Comment mapper les fichiers DTO à mes modèles dans mon projet .Net Core

Je n'ai jamais travaillé avec un projet .Net Core auparavant, mais j'ai un historique avec .Net, y compris MVC et le framework d'entité. Je travaille avec un nouveau projet .Net Core qui a cinq dossiers de solution, EHA.PROJ.API, EHA.PROJ.DTO, EHA.PROJ.Repository, EHA.PROJ.Repository.Test et EHA.PROJ.Web. Le dossier EHA.PROJ.DTO contient un certain nombre de fichiers tels que CategoryDTO.cs qui ressemble à ceci

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

        public string CategoryName { get; set; }
    }
}

Je cherche à mettre en place un arrangement de mappage pour obtenir les données de l'EHA. PROJ.DTO aux fichiers de modèle dans mon dossier modèles dans mon dossier EHA.PROJ.Web. J'ai navigué comme je n'avais jamais rien fait de tel auparavant, car j'ai déjà travaillé avec des données d'un dossier DAL en utilisant un cadre d'entité et une connexion effectuée via des chaînes de connexion. Je suppose qu'il doit y avoir un processus pour mapper les données dans mon dbContext pour connecter les fichiers dans les deux dossiers. J'ai trouvé des informations sur AutoMapper mais je ne savais pas comment l'implémenter.

Cet arrangement avec .Net Core est nouveau pour moi, donc si quelqu'un peut aider avec des exemples ou me diriger dans la bonne direction, je serais reconnaissant.


1 commentaires

L'outil AutoMapper fonctionne dans les deux sens, il vous permet de récupérer les données de vos modèles et de revenir du côté client dans vos DTO et vice versa, vous devez absolument vous pencher sur AutoMapper.


3 Réponses :


0
votes

Cet article est une bonne référence pour commencer: https://buildplease.com/pages/repositories -dto /

Ma suggestion est d'avoir un assembleur DTO qui mappe votre modèle à l'objet DTO. Donc, vous commencez avec votre classe DTO:

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

Ensuite, construisez l'assembleur:

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

Maintenant vous implémentez le service pour faire tout le travail nécessaire pour obtenir l'objet DTO:

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);
    }
}

Avec l'interface ressemblant à ceci:

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

Vous puis devez ajouter le service à votre Startup.cs:

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

        public string CategoryName { get; set; }
    }
}

Vous pouvez maintenant appeler votre service depuis votre contrôleur de vue.


3 commentaires

Merci MarioMendieta, cela ressemble exactement à ce dont j'ai besoin, mais puis-je poser quelques questions. Je suppose que CategoryDescAssembler se trouve du côté Web et que j'aurai besoin d'un assembleur différent pour chaque fichier DTO (il y en a environ 25 pour le moment) qui existera à côté de CategoryDescService.cs et répéter le processus pour chaque fichier DTO?


Tout dépend de votre logique métier. Vous pouvez avoir un service comme CategoryService.cs qui s'occupera de toute la logique concernant les catégories. Ainsi, un service peut consommer de nombreuses entités, et il peut y avoir de nombreuses entités qui ne sont pas du tout consommées par un seul service. De plus, l'assembleur ne se trouve pas nécessairement sur la couche Web. Vous pouvez avoir une couche intermédiaire entre votre référentiel et votre couche Web qui s'occupe de cela. Encore une fois, cela dépend de votre cas d'utilisation spécifique. Jetez un œil à cette réponse: stackoverflow.com/a/6621636/5090767


Merci, cela m'a donné assez pour continuer



2
votes

Votre premier problème est d'avoir vos entités dans votre projet Web. Dès le départ, vous avez un couplage étroit entre le projet Web et votre couche de données, ce qui annule à peu près le point de toutes vos autres couches: DTO, référentiel, etc. Vous voulez déplacer vos entités et votre contexte dans un véritable couche de données (c'est-à-dire un projet de bibliothèque de classes distinct de votre projet Web).

Ensuite, vous voulez décider de l'étendue de votre couche de données. Si l'API doit alimenter le site Web, vous souhaitez supprimer toutes les dépendances sur la couche de données du projet Web. Votre projet DTO serait partagé entre les projets API et Web et votre API enverrait / recevrait vos DTO, mappant dans les deux sens depuis vos entités sous le capot.

Cependant, si vous voulez faire cela, alors le projet de référentiel devrait disparaître complètement. Faites simplement travailler votre API directement avec EF et vos entités. Votre abstraction est l'API elle-même; il n'y en a pas besoin d'un autre. La seule raison d'avoir la couche référentiel est que l'API et le Web utilisent tous les deux directement les référentiels, ce qui n'est pas un très bon modèle en fait. Vous vous retrouverez inévitablement avec un tas de logique dupliquée spécifique à chaque projet.

Simplement, le modèle de référentiel est superflu lors de l'utilisation d'un ORM comme EF. L'ORM est votre couche de données. Vous utilisez simplement un DAL fourni par un tiers, plutôt que celui que vous avez créé vous-même. Le modèle de référentiel n'a de sens que lorsque vous travaillez directement avec SQL en utilisant directement quelque chose comme ADO.NET. Sinon, débarrassez-vous-en.

Avoir une API est une abstraction suffisante, si votre objectif est simplement de masquer la couche de données. Le site Web ne sait rien de la source de données sous-jacente, et une API n'est en réalité qu'une couche de service qui renvoie JSON sur HTTP plutôt que des instances d'objet directement, c'est-à-dire que l'API est essentiellement votre couche de «référentiel».

La situation peut être encore améliorée en passant à une architecture basée sur des microservices. Avec cela, vous disposez essentiellement de plusieurs petites API autonomes qui ne fonctionnent qu'avec une seule partie de votre domaine ou de votre fonctionnalité. Chacun peut utiliser EF directement, ou un ORM entièrement différent, ou même une pile entièrement différente. Vous pourriez avoir des API construites sur Node.js ou python, etc.


0 commentaires

2
votes

J'utilise Automapper depuis un certain temps dans des projets .NET Core en raison de sa facilité d'utilisation et de sa dans l'injection de dépendances.

Installer depuis PM:

    private readonly IMapper _mapper;

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

Inscrivez-vous dans la méthode Startup.cs , ConfigureServices :

services.AddAutoMapper(typeof(Startup));

Créez une classe pour conserver vos mappages, par exemple MappingProfile.cs en utilisant Profile de l'Automapper, vous pouvez définir des mappages.

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

}

Le mappage ci-dessus indique à l'Automapper que Operator peut être mappé à OperatorDto et OperatorDto peut être mappé à Operator . p>

Dans votre contrôleur, vous pouvez injecter un IMapper

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

et mapper des valeurs comme ci-dessous:

var dto = _mapper.Map (op); // Mapper l'objet op à dto

var op = _mapper.Map (dto); // Mapper dto à un objet op

Automapper propose des mappages personnalisés, si vous en avez besoin.

Bien qu'il soit très facile d'effectuer des mappages avec Automapper, vous devez apprendre le framework.

Je pense que cela vaut la peine de l'apprendre car cela vous fera gagner beaucoup de temps à écrire du code de cartographie à l'avenir.


0 commentaires