【发布时间】:2020-10-25 23:03:24
【问题描述】:
我在 .net core 3.1 中有一个带有角前端的应用程序。我想将装饰器用于基本控制器,以便在整个应用程序中记录 CUD 操作。我在项目中使用 Scrutor nuget 包。
基本控制器如下
using System.Collections.Generic;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Xenagos.Data;
using Xenagos.Data.EFCore;
using Xenagos.ViewModels;
namespace Xenagos.Controllers
{
[Route("api/[controller]")]
[ApiController]
public abstract class BaseController<TEntity, TViewEntity, TRepository> : ControllerBase, IBaseController<TEntity, TViewEntity>
where TEntity : class
where TViewEntity : class, IViewEntity
where TRepository : IRepository<TEntity>
{
private readonly IRepository<TEntity> repository;
private readonly IMapper mapper;
public BaseController(TRepository repository, IMapper mapper)
{
this.repository = repository;
this.mapper = mapper;
}
// GET: api/[controller]
[HttpGet]
public virtual async Task<ActionResult<ComplexData<TViewEntity>>> Get()
{
var results = await repository.GetAll();
List<TViewEntity> resultsView =
this.mapper.Map<List<TEntity>, List<TViewEntity>>(results);
return Ok(new ComplexData<TViewEntity>(resultsView));
}
// GET: api/[controller]/5
[HttpGet("{id}")]
public async Task<ActionResult<TEntity>> Get(int id)
{
var entity = await repository.Get(id);
if (entity == null)
{
return NotFound();
}
return entity;
}
// PUT: api/[controller]/5
[HttpPut("{id}")]
public virtual async Task<IActionResult> Put(string id, TViewEntity entity)
{
if (!id.Equals(entity.Id))
{
return BadRequest();
}
await repository.Update(this.mapper.Map<TEntity>(entity));
return NoContent();
}
// POST: api/[controller]
[HttpPost]
public virtual async Task<ActionResult<TEntity>> Post(TViewEntity entity)
{
await repository.Add(this.mapper.Map<TEntity>(entity));
return CreatedAtAction("Get", new { id = entity.Id }, entity);
}
// DELETE: api/[controller]/5
[HttpDelete("{id}")]
public async Task<ActionResult<TViewEntity>> Delete(int id)
{
var entity = await repository.Delete(id);
if (entity == null)
{
return NotFound();
}
return this.mapper.Map<TViewEntity>(entity);
}
}
}
我做的装饰器如下
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Xenagos.Controllers;
using Xenagos.ViewModels;
namespace Xenagos.Data
{
public class LoggingDecorator<T, TViewEntity, TRepository> : IBaseController<T, TViewEntity>
where T : class
where TViewEntity : class, IViewEntity
where TRepository : IRepository<T>
{
private IBaseController<T, TViewEntity> _baseController;
private readonly ILogger<LoggingDecorator<T, TViewEntity, TRepository>> _logger;
public LoggingDecorator(IBaseController<T, TViewEntity> baseController, ILogger<LoggingDecorator<T, TViewEntity, TRepository>> logger)
{
_baseController = baseController;
_logger = logger;
}
Task<ActionResult<TViewEntity>> IBaseController<T, TViewEntity>.Delete(int id)
{
_logger.LogWarning($"Deleting record from ... with ID:{id}");
Task<ActionResult<TViewEntity>> result = _baseController.Delete(id);
return result;
}
public Task<ActionResult<ComplexData<TViewEntity>>> Get()
{
return _baseController.Get();
}
Task<ActionResult<T>> IBaseController<T, TViewEntity>.Get(int id)
{
return _baseController.Get(id);
}
public Task<ActionResult<T>> Post(TViewEntity entity)
{
_logger.LogWarning($"Adding new record from ... with object data :{JsonConvert.SerializeObject(entity)}");
return _baseController.Post(entity);
}
public Task<IActionResult> Put(string id, TViewEntity entity)
{
_logger.LogWarning($"updating record from ... with object data :{JsonConvert.SerializeObject(entity)}");
Task<IActionResult> result = _baseController.Put(id, entity);
return result;
}
}
}
在public void ConfigureServices(IServiceCollection) 的启动类中,我使用以下几行
services.AddScoped<IBaseController<Models.Property, PropertyViewModel>, BaseController<Models.Property, PropertyViewModel, PropertyRepository>>();
services.Decorate<IBaseController<Models.Property, PropertyViewModel>, LoggingDecorator<Models.Property, PropertyViewModel, PropertyRepository>>();
我已经从基本控制器中提取了一个接口,在所有先前的操作之上。 当应用程序运行时,它不会调用/传递装饰器。我在这里缺少什么? 我之前没有将装饰器模式与 .net 核心和依赖注入一起使用。所有添加的代码都在后端,我根本没有改变前端。
提前谢谢你。
【问题讨论】:
-
你能把你的非抽象控制器的注册包括进来吗?
-
问题是是否有可能用控制器做到这一点。这是您用
[ApiController]装饰的BaseController,asp.net 使用它来检测项目中的控制器。因此,当请求进来时,将始终是具有该属性的类而不是您的LoggingDecorator。您无需注册控制器即可使其工作。我认为您可以将 structor 用于除控制器之外的任何其他内容。一个更安全的选择可能是使用操作过滤器。 -
@devNull 我也从非抽象控制器中提取了一个接口,并将其添加为作用域。到目前为止它没有帮助。我还应该做其他事情吗?
-
@Michael,所以,如果我理解,我应该尝试装饰从执行操作(例如更新)的控制器调用它的类?
-
@Tony,如果你想坚持
structor,那么可以。但我认为还有其他解决方案。
标签: c# asp.net-core dependency-injection decorator scrutor