C# 在.netCore 3.1中用Scrutor装饰BaseController
我在.NETCore3.1中有一个应用程序,前端有角度。我想对基本控制器使用decorator,以便在整个应用程序中记录CUD操作。我在项目中使用Scrutor nuget包 基本控制器如下所示C# 在.netCore 3.1中用Scrutor装饰BaseController,c#,asp.net-core,dependency-injection,decorator,scrutor,C#,Asp.net Core,Dependency Injection,Decorator,Scrutor,我在.NETCore3.1中有一个应用程序,前端有角度。我想对基本控制器使用decorator,以便在整个应用程序中记录CUD操作。我在项目中使用Scrutor nuget包 基本控制器如下所示 using System.Collections.Generic; using System.Threading.Tasks; using AutoMapper; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging
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;
}
}
}
我已经从基本控制器中提取了一个接口,它位于前面的所有操作之上。
当应用程序运行时,它不会调用/传递装饰程序。我错过了什么?
我以前没有在.net内核和依赖项注入中使用过decorator模式。所有添加的代码都只在后端,我根本没有更改前端
提前感谢。使用
ActionFilter
记录进入/退出控制器操作:
public class LoggingActionFilter : IActionFilter
{
ILogger _logger;
public LoggingActionFilter(ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger<LoggingActionFilter>();
}
public void OnActionExecuting(ActionExecutingContext context)
{
// do something before the action executes
_logger.LogInformation($"Action '{context.ActionDescriptor.DisplayName}' executing");
}
public void OnActionExecuted(ActionExecutedContext context)
{
// do something after the action executes
_logger.LogInformation($"Action '{context.ActionDescriptor.DisplayName}' executed");
}
}
公共类LoggingActionFilter:IActionFilter
{
ILogger\u记录器;
公共LoggingActionFilter(iLogger工厂Logger工厂)
{
_logger=loggerFactory.CreateLogger();
}
ActionExecuting(ActionExecutingContext上下文)上的公共void
{
//在动作执行之前做些什么
_logger.LogInformation($“Action'{context.ActionDescriptor.DisplayName}'正在执行”);
}
public void OnActionExecuted(ActionExecutedContext上下文)
{
//在动作执行后做些什么
_logger.LogInformation($“Action'{context.ActionDescriptor.DisplayName}'已执行”);
}
}
启动
services.AddMvc()
.AddMvcOptions(options =>
{
options.Filters.Add<LoggingActionFilter>();
});
services.AddMvc()
.addmvcopions(选项=>
{
options.Filters.Add();
});
您可能还希望为异步操作实现iasyncationfilter
要了解有关操作筛选器的更多信息,请参阅
您还可以添加异常过滤器以记录所有异常。您是否可以包括非抽象控制器的注册?问题是,是否可以使用控制器执行此操作。正是您用
[ApiController]
修饰的BaseController
,asp.net使用它来检测项目中的控制器。因此,当请求传入时,解析该属性的总是类,而不是您的LoggingDecorator
。您无需注册控制器即可使其工作。我认为除了控制器之外,你还可以使用structor。更安全的做法是使用操作过滤器。@devNull我也从非抽象控制器中提取了一个接口,并将其添加为作用域。到目前为止,它没有起到任何作用。我还应该做些什么吗?@Michael,所以,如果我理解,我应该尝试修饰从执行操作的控制器调用的类(例如更新)?@Tony,如果你想坚持使用structor
,那么是的。但是我认为还有其他的解决方案。谢谢你的回复,我会尝试实现它,并让你知道结果,这真的很有帮助!谢谢你的帮助。但是有一个问题,在您发布的代码片段中,您向MVC过滤器添加了一个新的LoggingActionFilter对象。在第一个代码段中,您放置了一个构造函数参数。当我添加ILoggerFacotry时,如何将它传递给MVC过滤器上的对象实例化?啊,是的,我错了。您应该使用通用版本,asp.net将使用serviceProvider。编辑了我的答案。
services.AddMvc()
.AddMvcOptions(options =>
{
options.Filters.Add<LoggingActionFilter>();
});