简体   繁体   English

如何将依赖注入与 [SwaggerOperationFilter] 一起使用?

[英]How to use Dependency Injection with [SwaggerOperationFilter]?

I'm using Swashbuckle to implement an OpenAPI documentation for my web api.我正在使用 Swashbuckle 为我的 web api 实现 OpenAPI 文档。 I have decided to use a [SwaggerOperationFilter] attribute in one of my operations in order to improve its Response Body example.我决定在我的一项操作中使用[SwaggerOperationFilter]属性,以改进其响应正文示例。

According to the documentation , Swashbuckle's filter pipelines can use Dependency Injection, as per the following exerpt:根据文档,Swashbuckle 的过滤器管道可以使用依赖注入,根据以下摘录:

NOTE: Filter pipelines are DI-aware.注意:过滤器管道是 DI 感知的。 That is, you can create filters with constructor parameters and if the parameter types are registered with the DI framework, they'll be automatically injected when the filters are instantiated也就是说,您可以使用构造函数参数创建过滤器,如果参数类型已在 DI 框架中注册,它们将在过滤器实例化时自动注入

Here's a simplified version of a controller这是 controller 的简化版本

/// <summary>Some sample controller.</summary>
[ApiController]
[Route("/my-controller")]
public class MyController : ControllerBase {
    /// <summary>Simple action returning some string array.</summary>
    /// <response code="200">All went well.</response>
    [HttpGet]
    [SwaggerOperationFilter(typeof(MyOperationFilter))]
    public IEnumerable<string> GetSomeStrings() => new[] { "abc", "def" };
}

and the IOperationFilter I'm trying to implement:和我正在尝试实现的IOperationFilter

public class MyOperationFilter : IOperationFilter {
    public MyOperationFilter(ILogger<MyOperationFilter> logger) {   // <--- Dependency Injection will fail to call this constructor
        logger.LogInformation("DI won't work!");
    }


    public void Apply(OpenApiOperation operation, OperationFilterContext context) {
        var responseExample = new OpenApiArray();
        responseExample.AddRange(new [] {
            new OpenApiString("text-1"),
            new OpenApiString("text-2"),
            new OpenApiString("text-3"),
        });

        var response = operation.Responses["200"];
        response.Content["application/json"].Example = responseExample;
    }
}

This code fails to execute while trying to access the OpenAPI Document and the Swagger UI with the following exception:此代码在尝试访问 OpenAPI 文档和 Swagger UI 时无法执行,但出现以下异常:

MyProject.MyControllers.UnhandledExceptionsController[0]
      Unhandled exception of type SwaggerGeneratorException on path "/api-docs/my-api-v1/openapi.json"
      Swashbuckle.AspNetCore.SwaggerGen.SwaggerGeneratorException: Failed to generate Operation for action - MyProject.MyControllers.MyController.GetSomeStrings (my-project). See inner exception  
       ---> System.MissingMethodException: No parameterless constructor defined for type 'MyProject.MyControllers.MyOperationFilter'.
         at System.RuntimeType.CreateInstanceDefaultCtorSlow(Boolean publicOnly, Boolean wrapExceptions, Boolean fillCache)
         at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, Boolean wrapExceptions)
         at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
         at Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.ApplySwaggerOperationFilterAttributes(OpenApiOperation operation, OperationFilterContext context, IEnumerable`1 controllerAndActionAttributes)
         at Swashbuckle.AspNetCore.Annotations.AnnotationsOperationFilter.Apply(OpenApiOperation operation, OperationFilterContext context)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
         --- End of inner exception stack trace ---
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperation(ApiDescription apiDescription, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GenerateOperations(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GeneratePaths(IEnumerable`1 apiDescriptions, SchemaRepository schemaRepository)
         at Swashbuckle.AspNetCore.SwaggerGen.SwaggerGenerator.GetSwagger(String documentName, String host, String basePath)
         at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
         at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.<Invoke>g__Awaited|6_0(ExceptionHandlerMiddleware middleware, HttpContext context, Task task)

I understand that if I register the IOperationFilter in the services.AddSwagerGen(...) call, my operation filter will be DI-enabled .我知道如果我在services.AddSwagerGen(...)调用中注册IOperationFilter ,我的操作过滤器将启用 DI But the problem with that approach is that the registered IOperationFilter will be registered as a "global" filter, and will be applied to every action method in my project, and I wanted to avoid that, as this filter was supposed to affect a single action method in my project.但是这种方法的问题是注册的IOperationFilter将被注册为“全局”过滤器,并将应用于我项目中的每个操作方法,我想避免这种情况,因为这个过滤器应该影响单个操作我项目中的方法。

Is there any way to keep using a local ("non-global") IOperationFilter (via [SwaggerOperationFilter] ) and have my filter injected with dependencies?有什么方法可以继续使用本地(“非全局”) IOperationFilter (通过[SwaggerOperationFilter] )并让我的过滤器注入依赖项?

Is there any way to keep using a local ("non-global") IOperationFilter (via [SwaggerOperationFilter] ) and have my filter injected with dependencies?有什么方法可以继续使用本地(“非全局”) IOperationFilter (通过[SwaggerOperationFilter] )并让我的过滤器注入依赖项?

Not according to their source code不是根据他们的源代码

AnnotationsOperationFilter注释操作过滤器

//...

public static void ApplySwaggerOperationFilterAttributes(
    OpenApiOperation operation,
    OperationFilterContext context,
    IEnumerable<object> controllerAndActionAttributes)
{
    var swaggerOperationFilterAttributes = controllerAndActionAttributes
        .OfType<SwaggerOperationFilterAttribute>();

    foreach (var swaggerOperationFilterAttribute in swaggerOperationFilterAttributes)
    {
        var filter = (IOperationFilter)Activator.CreateInstance(swaggerOperationFilterAttribute.FilterType);
        filter.Apply(operation, context);
    }
}

//...

Where it can seen that they use Activator.CreateInstance , which required a default constructor as already indicated in the stack trace of the exception given.可以看出他们使用了Activator.CreateInstance ,这需要一个默认构造函数,正如给定异常的堆栈跟踪中已经指出的那样。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM