16 Jun

How to use Custom Attributes within Swagger in .NET

Swagger

The Swagger framework is a very handy framework to create, document and test your API’s. By default it already supports or has a lot of attributes in the .NET Framework. However sometimes you’ll want to add your own attributes so you’re able to add specific information. In this post I want to show you how you can add your own custom attributes and add specific info to your Swagger file.

User Story

An API was using pagination to get a certain amount of objects.
Unfortunately our filterobject inherited from a base class which was included in our project through NuGet and which we didn’t have any control over. By default, the page and pagesize (the amount of items you want to have on your page) was set to 1 and 10. The properties however didn’t contain the DefaultValue attribute. So we needed to add our own attribute to enable us to show the default value inside the Swagger documentation.



Code

The Attribute

[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = true)]
public class SwaggerDefaultValue : Attribute
{
	public string Parameter { get; set; }
	public string Value { get; set; }
}

As you can see, we put the attribute on a method so not on the property itself, because in this case we didn’t have control over that property. We could’ve overridden the properties, but we didn’t find it a elegant solution and by adding it to our controller actions we were able to group all our Swagger attributes in our controller.
We also allow multiple uses of the attribute, since there could be more properties with a default value, in our case there’re two.

As properties we have our Parameter and our value.

OperationFilter

public class AddDefaultValues : IOperationFilter
{
	public void Apply(Operation operation, OperationFilterContext context)
	{
		var defaultValues = context.ApiDescription.ActionAttributes().Where(x => x.GetType() == typeof(SwaggerDefaultValue)).Select(x => (SwaggerDefaultValue)x).ToDictionary(x => x.Parameter.ToLower(), x => x.Value);
		foreach (var param in operation.Parameters.Where(x => defaultValues.ContainsKey(x.Name.ToLower())))
			param.Description = FormatDescription(param.Description, defaultValues[param.Name]);
	}
	
	private string FormatDescription(string description, string value)
	{
		var dvDescription = $"Default value: {value}";
		if (string.IsNullOrEmpty(description))
			return dvDescription;
		else
			return $"{description}<br />{dvDescription}";
	}
}

To add the default values to our Swagger documentation, we need to add an Operationfilter. In this filter, we’ll search the OperationFilterContext for our attribute. Once we’ve found our attributes, if any, we’re looking into the Operation itself in search of the Properties. Once we’ve found those, we’ll add the default value. Depending on whether there’s already a description, we’ll add the default value on a new line.

Implement it

[SwaggerDefaultValue(Parameter = "pagesize", Value = "10")]
[SwaggerDefaultValue(Parameter = "page", Value = "1")]
public override async Task<IActionResult> GetAll(Filter filter)
{
	// add code...
}

Not only do you need to add the Attributes to the actions in your controller. You should also add the OperationFilter to your Startup.cs class.

services.ConfigureSwaggerGen(options =>
{
	options.SwaggerDoc("v1",
		  new Info
		  {
			  Title = "Title",
			  Version = "v1",
			  Description = "Some Description",
			  TermsOfService = "None",
			  Contact = new Contact()
			  {
				  Email = "mr.awesome@sause.com",
				  Name = "Mr. Awesome"
			  }
		  }
	   );
	   
	options.OperationFilter<AddDefaultValues>();

	var location = Assembly.GetEntryAssembly().Location;
	string xmlComments = Path.Combine(Path.GetDirectoryName(location), Path.GetFileNameWithoutExtension(location) + ".xml");
	if (File.Exists(xmlComments))
		options.IncludeXmlComments(xmlComments);
});


Changing the description is only one of the few things you can do to your properties. You can also change the name, set it required,…
This is only an example to add Default Values, but there are more possibilities by using custom attributes with Swagger.

Sources

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.