[英].NET Core API action with generics and AutoMapper
我正在构建一个ASP.NET Core API。 我有一个动作,我希望在一组控制器上基本相同。 因此,我创建了那些控制器从其继承的EntityController
,如下所示。
注意:在下面两个类中使用的省略号表示更多的操作及其相关服务,遵循为简单起见而省略的相同模式。
public class EntityController : BaseController
{
protected readonly SeedService SeedService;
protected EntityController(IMemoryCache memoryCache, SeedService seedService) : base(memoryCache)
{
SeedService = seedService;
}
[HttpGet]
public async Task<IActionResult> Seed()
{
var controllerName = ControllerContext.RouteData.Values["controller"].ToString();
return await GetSeed(controllerName);
}
private async Task<IActionResult> GetSeed(string controllerName)
{
switch (controllerName)
{
case "lists":
return await MemoryCache.GetOrCreateAsync(CacheKeys.Entry, async entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Json(await SeedService.GetAllFilterLists());
});
case "languages":
return await MemoryCache.GetOrCreateAsync(CacheKeys.Entry, async entry =>
{
entry.SlidingExpiration = TimeSpan.FromSeconds(3);
return Json(await SeedService.GetAllLanguages());
});
...
default:
return await Task.FromResult(NotFound());
}
}
}
以下是这些操作调用的服务方法:
public class SeedService
{
private readonly FilterListsDbContext filterListsDbContext;
public SeedService(FilterListsDbContext filterListsDbContext)
{
this.filterListsDbContext = filterListsDbContext;
}
public async Task<IEnumerable<FilterListSeedDto>> GetAllFilterLists()
{
return await filterListsDbContext.Set<FilterList>().ProjectTo<FilterListSeedDto>().ToListAsync();
}
public async Task<IEnumerable<LanguageSeedDto>> GetAllLanguages()
{
return await filterListsDbContext.Set<Language>().ProjectTo<LanguageSeedDto>().ToListAsync();
}
...
}
如何使用泛型(或替代方法)减少复制/粘贴重复? 我试图用类似一个Dictionary<string, Type>
查找的Type
从控制器名称动态,但我不知道是怎么产生的GetAll<T>()
的方法SeedService
会看? 下面的方法无效,因为该方法取决于AutoMapper投影的实体和DTO模型的类型。
public async Task<IEnumerable<T>> GetAll<T>()
{
return await filterListsDbContext.Set<T>().ProjectTo<T>().ToListAsync();
}
您可以轻松地将所有样板代码删除为一个通用方法:
public async Task<IEnumerable<TResult>> GetAll<TEntry, TResult>() where TEntry : class
{
return await filterListsDbContext.Set<TEntry>()
.ProjectTo<TResult>()
.ToListAsync();
}
由于返回的是IEnumerable
,因此您可能需要更改为.ToArrayAsync()
。 另外,由于要投影到非实体,因此上下文不会接受更改,因此可以进一步添加.AsNoTracking()
以避免将实体添加到上下文:
public async Task<IEnumerable<TResult>> GetAll<TEntry, TResult>() where TEntry : class
{
return await filterListsDbContext.Set<TEntry>()
.AsNoTracking()
.ProjectTo<TResult>()
.ToArrayAsync();
}
正如我在评论中提到的,您可以将其放在基本控制器中,然后执行以下操作:
public class BaseController<TEntity, TViewModel>
{
public async Task<IEnumerable<TViewModel>> GetAll()
{
return await filterListsDbContext.Set<TEntity>()
.AsNoTracking()
.ProjectTo<TViewModel>()
.ToArrayAsync();
}
}
public class LanguageController : BaseController<Language, LanguageSeedDto>
{
(in some action)
var data = await GetAll();
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.