【问题标题】:Restrict accepted Media Types in ASP.NET Core Controller action限制 ASP.NET Core 控制器操作中接受的媒体类型
【发布时间】:2018-07-03 16:08:53
【问题描述】:

我有一个生成 JSON 和 XML 响应的 ASP.NET Core 服务。但是,我喜欢将接受的媒体类型限制为仅一种操作,因此 Swagger 只能将 application/json 列为有效的响应内容类型。如何在 ASP.Net Core 中实现这一点?

请考虑我使用的是 ASP.Net Core (ASP.NET MVC 6),而不是 ASP.NET WebAPI。

更新

好的,所以我会将答案添加为同一问题的一部分。感谢@Helen,我能够在 ASP.Net Core (ASP.Net MVC 6) 中添加所需的类来实现这一点。答案基于this answer,但修改为使用 ASP.NET Core 类。

第 1 步。 创建自定义操作过滤器属性,以便管道对禁止的内容类型做出反应:

/// <summary>
/// SwaggerResponseContentTypeAttribute
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class SwaggerResponseContentTypeAttribute : ActionFilterAttribute
{
    /// <summary>
    /// SwaggerResponseContentTypeAttribute
    /// </summary>
    /// <param name="responseType"></param>
    public SwaggerResponseContentTypeAttribute(string responseType)
    {
        ResponseType = responseType;
    }
    /// <summary>
    /// Response Content Type
    /// </summary>
    public string ResponseType { get; private set; }

    /// <summary>
    /// Remove all other Response Content Types
    /// </summary>
    public bool Exclusive { get; set; }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        var accept = context.HttpContext.Request.Headers["accept"];
        var accepted = accept.ToString().ToLower().Contains(ResponseType.ToLower());
        if (!accepted)
            context.Result = new StatusCodeResult((int)HttpStatusCode.NotAcceptable); 

    }

}

第 2 步。创建一个 Swagger 操作过滤器,以便 UI 可以反映限制

public class ResponseContentTypeOperationFilter : IOperationFilter
{

    public void Apply(Swashbuckle.AspNetCore.Swagger.Operation operation, OperationFilterContext context)
    {
        var requestAttributes = context.ControllerActionDescriptor.GetControllerAndActionAttributes(true).Where(c=>c.GetType().IsAssignableFrom(typeof(SwaggerResponseContentTypeAttribute))).Select(c=> c as SwaggerResponseContentTypeAttribute).FirstOrDefault();

        if (requestAttributes != null)
        {
            if (requestAttributes.Exclusive)
                operation.Produces.Clear();

            operation.Produces.Add(requestAttributes.ResponseType);
        }
    }
}

第 3 步。 在 Startup.cs 中的 ConfigureServices 方法中配置 Swagger UI 服务,以便它可以使用新创建的操作过滤器。

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.Configure<MvcOptions>(options =>
        {
            options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());

        });
        // Register the Swagger generator, defining 1 or more Swagger documents
        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new Info { Title = "My API", Version = "v1" });
            c.OperationFilter<ResponseContentTypeOperationFilter>();
        });
    }

第 4 步。注释动作

    // GET api/values
    [HttpGet]
    [WebService.Utils.SwaggerResponseContentType(responseType: "application/json", Exclusive = true)]
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

【问题讨论】:

  • @Helen 感谢您的链接。答案与 ASP.Net Web API 有关。但是,通过一些小的修改,它可以迁移到 ASP.Net Core。不过,这只能解决 Swagger 只会显示 application/json 的问题,但在后台,我仍然可以使用 Accept: application/xml 执行请求,它会起作用。我想实际限制控制器操作中接受的媒体类型。
  • options.OutputFormatters.RemoveType&lt;XmlDataContractSerializerOutputFormatter&gt;() 呢?
  • 关键是我希望 XML 序列化程序普遍可用。我只是希望它不适用于特定操作。

标签: asp.net asp.net-core swagger-ui media-type


【解决方案1】:

您可以使用注释消费和生产。这些也被 Swashbuckle 拾取。 像这样:

[HttpGet]
[Consumes("application/xml")]
[Produces("application/xml")]
public IEnumerable<string> Get()
{
    return new string[] { "value1", "value2" };
}

【讨论】:

    【解决方案2】:

    我知道这是一个老问题,但在这里我试图这样做,所以,为了让其他人更容易,我将使用“通用”方式添加到 @joeystdio 的答案中以添加相同的产品/消费所有端点的属性。 (对于我的用例,为所有端点设置东西比一个一个地设置更容易。

    .AddControllers(options  => 
    {
        options.Filters.Add(new ProducesAttribute("application/json"));
        options.Filters.Add(new ConsumesAttribute("application/json"));
    
        // if you need a specific response type.
        options.Filters.Add(new ProducesResponseTypeAttribute(typeof(ApplicationNotification), StatusCodes.Status500InternalServerError));
    })
    

    【讨论】:

    • 不知道为什么这被否决了,这全面修复了它!专业提示:您可以使用 MediaTypeNames.Application.Json 而不是硬编码字符串。
    • 请注意。我不知道 MediaTypeNames,保持一致性非常好。我有一个常数,有一些常数和类似的东西。更容易使用正确的类。
    • 粉丝-粉丝-太棒了!所有的好东西,但我会说这是现在正确的答案。
    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 2021-08-05
    • 2019-05-10
    • 1970-01-01
    相关资源
    最近更新 更多