我正在构建一个Web应用程序,其中将有很多控制器及其相应的操作方法。
我想将每个异常保存在数据库中,因此我创建了 ExceptionService(在其中注入了DbContext)。
让我们说这是我的控制器的一般形式:
[Route("api/[controller]")]
[ApiController]
public class UserController : ControllerBase
{
private readonly UserManager userManager;
private readonly IExceptionService exceptionService;
public UserController(UserManager userManager, IExceptionService exceptionService)
{
this.userManager = userManager;
this.exceptionService = exceptionService;
}
[HttpPost]
public async Task<IActionResult> Post([FromBody] User user)
{
try
{
//some code
}
catch (Exception e)
{
exceptionService.Save(e);
//some code
}
}
}
为了避免那么多try-catch块,我决定创建一个看起来像这样的过滤器:
public class ApiExceptionFilterAttribute : ExceptionFilterAttribute
{
private readonly IExceptionService exceptionService;
public ApiExceptionFilterAttribute(IExceptionService exceptionService)
{
this.exceptionService = exceptionService;
}
public override void OnException(ExceptionContext context)
{
Exception e = context.Exception;
exceptionService.Save(e);
//some code
}
}
StartUp.cs中ConfigureServices方法中的代码如下(为简单起见删除了一些代码):
services
.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
services
.AddDbContext<AppDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("Default")));
services.AddScoped<UserManager>();
services.AddScoped<SignInManager>();
services.AddScoped<IExceptionService, ExceptionService>();
services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();
ConfgureMvcOptions类如下:
public class ConfigureMvcOptions : IConfigureOptions<MvcOptions>
{
private readonly IExceptionService exceptionService;
public ConfigureMvcOptions(IExceptionService exceptionService)
{
this.exceptionService = exceptionService;
}
public void Configure(MvcOptions options)
{
options.Filters.Add(new ApiExceptionFilterAttribute(exceptionService));
}
}
运行此应用程序时,出现以下错误:
System.InvalidOperationException: 'Cannot consume scoped service 'SmartWay.Services.IExceptionService' from singleton 'Microsoft.Extensions.Options.IConfigureOptions`1[Microsoft.AspNetCore.Mvc.MvcOptions]'.'
如果我将IExceptionServcise的生存期更改为瞬态,那么我必须这样做 Dbcontext,然后是DbContextOptions ...看来这不是正确的方法。
那么,我该如何解决这个问题?
答案 0 :(得分:1)
要从单例服务解析作用域服务,请尝试_serviceProvider.CreateScope
。
请按照以下步骤操作:
ExceptionService
public interface IExceptionService
{
void Save(Exception ex);
}
public class ExceptionService : IExceptionService
{
private readonly IServiceProvider _serviceProvider;
public ExceptionService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public void Save(Exception ex)
{
using (var scope = _serviceProvider.CreateScope())
{
var _context = scope.ServiceProvider.GetRequiredService<MVCProContext>();
_context.Add(new Book() { Title = ex.Message });
_context.SaveChanges();
}
}
}
Startup.cs
services.AddSingleton<IExceptionService, ExceptionService>();
services.AddSingleton<IConfigureOptions<MvcOptions>, ConfigureMvcOptions>();