C# 在.netCore 3.1中用Scrutor装饰BaseController

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

我在.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 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>();
    });