Swashbuckle.webapi: CancellationToken is documented on async methods

Created on 29 Apr 2015  路  6Comments  路  Source: domaindrivendev/Swashbuckle.WebApi

Web API controller methods can take in a CancellationToken parameter to provide cancellation support.

Swagger currently documents this as a REST parameter, but is an internal Web API thing and shouldn't be documented.

Most helpful comment

Thanks for this. I had to this now:

public class CancellationTokenOperationFilter : IOperationFilter
        {
            public void Apply(Operation operation, OperationFilterContext context)
            {
                var apiDescription = context.ApiDescription;
                var excludedParameters = apiDescription.ParameterDescriptions
                    .Where(p => p.ModelMetadata.ContainerType == typeof(CancellationToken) || p.ModelMetadata.ContainerType == typeof(WaitHandle) || p.ModelMetadata.ContainerType == typeof(SafeWaitHandle))
                    .Select(p => operation.Parameters.FirstOrDefault(operationParam => operationParam.Name == p.Name))
                    .ToArray();

                foreach (var parameter in excludedParameters)
                    operation.Parameters.Remove(parameter);
            }
        }

All 6 comments

Swashbuckle is built on top of WebApis' own metadata layer - ApiExplorer. Despite being an internal WebApi thing, it is still being reported as an API parameter by ApiExplorer so really that's where the issue lies.

To keep complexity down and reduce the potential for compatibility issues, I like to rely on the underlying framework as much as possible so would opt against supporting a workaround out-of-the-box.

However, you can easily workaround this yourself by creating a custom IOperationFilter (see readme) that removes the cancellationToken param from the provided operation.

Anybody has an example on how to filter CancellationToken type out?

@mchambaud: Give this a try.

    public class CancellationTokenOperationFilter : IOperationFilter
    {
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            var excludedParameters = apiDescription.ParameterDescriptions
                .Where(p => p.ParameterDescriptor.ParameterType == typeof (CancellationToken))
                .Select(p => operation.parameters.FirstOrDefault(operationParam => operationParam.name == p.Name))
                .ToArray();

            foreach (var parameter in excludedParameters)
                operation.parameters.Remove(parameter);
        }
    }

Thanks @gisenberg

Thanks for this. I had to this now:

public class CancellationTokenOperationFilter : IOperationFilter
        {
            public void Apply(Operation operation, OperationFilterContext context)
            {
                var apiDescription = context.ApiDescription;
                var excludedParameters = apiDescription.ParameterDescriptions
                    .Where(p => p.ModelMetadata.ContainerType == typeof(CancellationToken) || p.ModelMetadata.ContainerType == typeof(WaitHandle) || p.ModelMetadata.ContainerType == typeof(SafeWaitHandle))
                    .Select(p => operation.Parameters.FirstOrDefault(operationParam => operationParam.Name == p.Name))
                    .ToArray();

                foreach (var parameter in excludedParameters)
                    operation.Parameters.Remove(parameter);
            }
        }

For a clean way (while only abusing c# attributes) to ignore any parameter, I've been using this:

SwaggerIgnoreAttribute.cs

[AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false)]
public sealed class SwaggerIgnoreAttribute : Attribute
{
  public SwaggerIgnoreAttribute()
  {
  }
}

CustomOperationFilter.cs

public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
   // Remove hidden parameters from the documentation
   if (operation.parameters != null)
   {
     foreach (var parameter in apiDescription.ActionDescriptor.GetParameters())
     {
       if (parameter.GetCustomAttributes<SwaggerIgnoreAttribute>().Any())
       {
         operation.parameters.Remove(operation.parameters.First(x => string.Equals(parameter.ParameterName, x.name)));
       }
     }
   }
}

ValuesController.cs

public class ValuesController : ApiController
{
...
  // GET api/values/5
  public async Task<string> GetAsync([SwaggerIgnore] CancellationToken ct, int id)
  {
    return await Task.Run(() => { return "value";});
  }
}

It would be nice if this was baked into Swashbuckle IMO :). Would the package owners be interested?

Was this page helpful?
0 / 5 - 0 ratings