gri*_*urd 14 asp.net-mvc repository unit-of-work dto n-tier-architecture
我一直在试图解决这个问题,但是在ASP.NET MVC上这个特定主题的信息似乎很少.我一直在谷歌搜索几天,并没有真正能够解决这个特定的问题.
我有一个3层项目.业务,DAL和UI/Web层.在DAL中是dbcontext,存储库和工作单元.在业务层中是包含所有接口和EF模型的域层.在业务层中,还有一个服务层,其中包含用于EF模型的DTO和用于访问存储库的通用存储库服务.这张照片应该有助于解释它.
我的问题是,我似乎无法弄清楚如何使用DTO从业务层传输数据.
我已经为DTO创建了服务类.我有一个ImageDTO和模型和图像锚点相同.我为每个DTO创建了一个服务类.所以我有一个图像服务和主播服务.这些服务继承存储库服务,并且目前实现自己的服务.但就我而言,那就是那个.由于这些服务具有通过IoC接收IUnitOfWork接口的构造函数,因此我几乎陷入困境.
如果我直接从UI引用服务,一切正常,但我无法理解如何使用DTO将数据从服务层传输到UI层,反之亦然.
我的服务层:
业务/服务/ DTO的
public class AnchorDto
{
public int Id { get; set; }
public int x1 { get; set; }
public int y1 { get; set; }
public int x2 { get; set; }
public int y2 { get; set; }
public string description { get; set; }
public int imageId { get; set; }
public int targetImageId { get; set; }
public AnchorDto(int Id, int x1, int y1, int x2, int y2, string description, int imageId, int targetImageId)
{
// Just mapping input to the DTO
}
}
public class ImageDto
{
public int Id { get; set; }
public string name { get; set; }
public string title { get; set; }
public string description { get; set; }
public virtual IList<AnchorDto> anchors { get; set; }
public ImageDto(int Id, string name, string title, string description, IList<AnchorDto> anchors )
{
// Just mapping input to DTO
}
}
Run Code Online (Sandbox Code Playgroud)
业务/服务/服务
public class RepoService<TEntity> : IRepoService<TEntity> where TEntity : class
{
private IRepository<TEntity> repo;
public RepoService(IUnitOfWork repo)
{
this.repo = repo.GetRepository<TEntity>();
}
public IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> filter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null,
string includeProperties = "")
{
return repo.Get(filter, orderBy, includeProperties);
}
public TEntity GetByID(object id)
{
return repo.GetByID(id);
}
public void Insert(TEntity entity)
{
repo.Insert(entity);
}
public void Delete(object id)
{
repo.Delete(id);
}
public void Delete(TEntity entityToDelete)
{
repo.Delete(entityToDelete);
}
public void Update(TEntity entityToUpdate)
{
repo.Update(entityToUpdate);
}
}
Run Code Online (Sandbox Code Playgroud)
Image Service,IImageService接口当前是空的,直到我弄清楚我需要实现什么.
public class ImageService : RepoService<ImageModel>, IImageService
{
public ImageService(IUnitOfWork repo)
: base(repo)
{
}
}
Run Code Online (Sandbox Code Playgroud)
目前我的控制器并没有真正工作,并且没有使用服务层,所以我决定不包括任何这些.我计划在将此问题排序后,使用自动映射器将DTO映射到ViewModel.
那么现在,请那些知识渊博的人给我这个想法,我已经失踪了,这样我才能弄清楚这一点?
Dan*_*.G. 39
您的服务应该接收DTO,将它们映射到业务实体并将它们发送到存储库.它还应该从存储库中检索业务实体,将它们映射到DTO并将DTO作为响应返回.因此,您的业务实体永远不会从业务层退出,只有DTO才会这样做.
然后您的UI\Weblayer应该不知道业务实体.Web层应该只知道DTO.要强制执行此规则非常重要,因为您的UI层不使用服务实现类(应该是私有的),只使用接口.服务接口不应该依赖于业务实体,而只依赖于DTO.
因此,您需要基于DTO的服务接口,并且您的基本服务类需要DTO的另一个通用参数.我喜欢为实体和DTO设置基类,因此它们可以声明为:
//Your UI\presentation layer will work with the interfaces (The inheriting ones)
//so it is very important that there is no dependency
//on the business entities in the interface, just on the DTOs!
protected interface IRepoService<TDto>
where TDto: DTOBase
{
//I'm just adding a couple of methods but you get the idea
TDto GetByID(object id);
void Update(TDto entityToUpdateDto)
}
//This is the interface that will be used by your UI layer
public IImageService: IRepoService<ImageDTO>
{
}
//This class and the ones inheriting should never be used by your
//presentation\UI layer because they depend on the business entities!
//(And it is a best practice to depend on interfaces, anyway)
protected abstract class RepoService<TEntity, TDto> : IRepoService<TDto>
where TEntity : EntityBase
where TDto: DTOBase
{
...
}
//This class should never be used by your service layer.
//Your UI layer should always use IImageService
//You could have a different namespace like Service.Implementation and make sure
//it is not included by your UI layer
public class ImageService : RepoService<ImageModel, ImageDto>, IImageService
{
...
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要一种方法将实体和DTO之间的映射添加到该基本服务,而无需实际实现映射(因为它取决于每个具体实体和DTO类).您可以声明执行映射的抽象方法,并且需要在每个特定服务上实现(例如ImageService).基础RepoService的实现如下:
public TDto GetByID(object id)
{
//I'm writing it this way so its clear what the method is doing
var entity = repo.GetByID(id);
var dto = this.EntityToDto(entity);
return dto;
}
public void Update(TDto entityToUpdateDto)
{
var entity = this.DtoToEntity(entityToUpdateDto)
repo.Update(entity);
}
//These methods will need to be implemented by every service like ImageService
protected abstract TEntity DtoToEntity(TDto dto);
protected abstract TDto EntityToDto(TEntity entity);
Run Code Online (Sandbox Code Playgroud)
或者您可以声明映射服务,使用应由IOC提供的适当映射服务添加依赖关系(如果您需要在不同服务上使用相同的映射,则更有意义).RepoService的实现如下:
private IRepository<TEntity> _repo;
private IDtoMappingService<TEntity, TDto> _mappingService;
public RepoService(IUnitOfWork repo, IDtoMappingService<TEntity, TDto> mapping)
{
_repo = repo.GetRepository<TEntity>();
_mappingService = mapping;
}
public TDto GetByID(object id)
{
//I'm writing it this way so its clear what the method is doing
var entity = repo.GetByID(id);
var dto = _mappingService.EntityToDto(entity);
return dto;
}
public void Update(TDto entityToUpdateDto)
{
var entity = _mappingService.DtoToEntity(entityToUpdateDto)
repo.Update(entity);
}
//You will need to create implementations of this interface for each
//TEntity-TDto combination
//Then include them in your dependency injection configuration
public interface IDtoMappingService<TEntity, TDto>
where TEntity : EntityBase
where TDto: DTOBase
{
public TEntity DtoToEntity(TDto dto);
public TDto EntityToDto(TEntity entity);
}
Run Code Online (Sandbox Code Playgroud)
在这两种情况下(抽象方法或映射服务),您可以手动或使用Automapper之类的工具实现实体和DTO之间的映射.但是在使用AutoMapper和实体框架时应该非常小心,尽管这是另一个主题!(谷歌有点关于这一点并收集有关该主题的一些信息.作为第一个建议,请注意在加载数据时对数据库执行的查询,以免加载超过需要或发送许多查询.保存数据时注意你的收藏和关系)
很长的帖子也许,但我希望它有所帮助!
| 归档时间: |
|
| 查看次数: |
13014 次 |
| 最近记录: |