Restrict accepted Media Types in ASP.NET Core Controller action

风格不统一 提交于 2020-01-11 08:38:27

问题


I have an ASP.NET Core Service that produces both JSON and XML responses. However, I like to restrict the accepted Media Type for only one action, so Swagger can only list application/json as a valid response content type. How can I achieve this in ASP.Net Core?

Please, consider I am using ASP.Net Core (ASP.NET MVC 6), not ASP.NET WebAPI.

UPDATE

Ok, so I'll add the answer as part of the same question. Thanks to @Helen, I was able to add the required classes to achieve this in ASP.Net Core (ASP.Net MVC 6). The answer is based on this answer but modified to use ASP.NET Core classes.

Step 1. Create a custom action filter attribute so the pipeline reacts to a forbiden content type:

/// <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); 

    }

}

Step 2. Create a Swagger Operation Filter so the UI can reflect the restriction

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

Step 3. Configure Swagger UI service in Startup.cs, inside the method ConfigureServices, so it can use the newly created 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>();
        });
    }

Step 4. Annotate the action

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

回答1:


You can use the annotations Consumes and Produces. These are also picked up by Swashbuckle. Like so:

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


来源:https://stackoverflow.com/questions/51158971/restrict-accepted-media-types-in-asp-net-core-controller-action

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!