限制ASP.NET Core控制器操作中接受的媒体类型

17

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

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

enter image description here

更新

好的,所以我会将答案添加到同一个问题中。多亏了@Helen,我能够添加所需的类来在ASP.Net Core(ASP.Net MVC 6)中实现这一点。答案基于此答案,但修改为使用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);
        }
    }
}

第三步。 在Startup.cs文件的ConfigureServices方法中配置Swagger UI服务,以便它可以使用新创建的Operation Filter。

    // 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进行请求并且它也能正常工作。我想在控制器操作中实际限制接受的媒体类型。 - Alfredo A.
这有帮助吗?(https://dev59.com/rmrXa4cB1Zd3GeqPEfRc) - Helen
options.OutputFormatters.RemoveType<XmlDataContractSerializerOutputFormatter>() 是什么意思? - Mark G
关键是我希望一般情况下都可以使用 XML 序列化器。我只是不希望它在特定的操作中可用。 - Alfredo A.
我也想要,为什么还没有这个属性? - Victorio Berra
2个回答

37

您可以使用注释 Consumes 和 Produces。这些注释也会被 Swashbuckle 捕捉到。就像这样:

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

14

我知道这是一个老问题,但在这里我正在尝试这样做,因此为了让其他人更容易理解,我将通过@joeystdio的答案添加一种"通用"的方法,以为所有端点添加相同的produce/consume属性。(对于我的用例,为所有端点设置东西要比一个一个去设置更容易)。

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

6
不确定为什么这个被踩了,这个解决方案适用于所有情况!专业提示:您可以使用MediaTypeNames.Application.Json而不是硬编码字符串。 - ivanmartinvalle
不错。我不知道有MediaTypeNames,这很好用来保持一致性。我之前使用了一个包含几个常量的常量,现在使用正确的类更容易了。 - Morilon
1
翻-翻-精彩!所有的好东西,但我会说这是正确的答案。 - Gabriel Kunkel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接