Reputation: 7692
We have a set of REST services. The services accept models in json in the POST request, and return models in json in the POST response. These models however are not physically compiled types in our ASP.NET Core 2.0 projects. Instead, they are mapped objects that map on to our internal types. I.e. the json that is served up is merely a layer over the top of our core entities which are cut down for the purpose of exposing the data to 3rd parties.
However the entities need to be documented with Swagger. Swashbuckle does a nice job of this. It does so via the namespace Microsoft.AspNetCore.Mvc.ApiExplorer. I'm now trying to define metadata for the entities served up in json with this namespace. However, I'm not having much luck. I want to define a type that is not based on a physical type in my project. I am happy to define the name and the properties etc. but I can't get anywhere with what I've done. For example, the abstract class ModelMetadata requires an argument of type ModelMetadataIdentity, but this type doesn't take any arguments in the constructor, and all of the important properties are Get only. So, for example, I literally cannot set the Name property on ModelMetadataIdentity. I'm guessing that it's a glitch in the code that I can even construct a ModelMetadataIdentity. I'm guessing that the class was meant to be abstract.
There is for example a static method called ForType which compiles, and doesn't throw any exceptions, like so:
var customModelMetadataProvider = new CustomModelMetadataProvider(ModelMetadataIdentity.ForType(typeof(TaskInfo)));
context.ApiDescription.SupportedResponseTypes.Add(new Microsoft.AspNetCore.Mvc.ApiExplorer.ApiResponseType { ModelMetadata = customModelMetadataProvider });
But, this does nothing. No documentation appears for TaskInfo in the Swagger documentation. But, more importantly, this is no good to me because TaskInfo is precompiled type, and I am trying to define a conceptual type, not a physical type.
To get an idea of what I am talking about, you can look at a sample here: https://github.com/Microsoft/aspnet-api-versioning/tree/master/samples/webapi/SwaggerODataWebApiSample . For example, Order, and Person are defined as types in the project, but I want to construct the meta data for these types dynamically.
How can I define a conceptual (dynamic) type using the Microsoft.AspNetCore.Mvc.ApiExplorer namespace? How do I force Swashbuckle to recognize metadata that I have defined using this namespace?
PS: I know that some people are going to be thinking "Why wouldn't you just write the models in code and compile them?". Well, obviously this could be done, but this adds an extra step to configuring the REST services that should not be necessary. The mapping from our internal entities to external entities is done with configuration - not code! A configuration person shouldn't have to compile anything to expose these entities.
Upvotes: 3
Views: 1125
Reputation: 7692
This can be done with Swashbuckle like this:
public class SwaggerOperationFilter : IOperationFilter
{
#region Fields
private const string testpropertyname = "TestProperty";
private const string TestSchemaRef = "ADef";
private static Schema TestSchema = new Schema { Required = new List<string> { testpropertyname }, Example = new { TestProperty = "Test" }, Description = "This is a Description", Title = "TestSchema", Properties = new Dictionary<string, Schema>() };
#endregion
#region Static Constructor
static SwaggerOperationFilter()
{
TestSchema.Properties.Add(testpropertyname, new Schema { Type = "string" });
}
#endregion
#region Implementation
public void Apply(Operation operation, OperationFilterContext context)
{
if (!context.SchemaRegistry.Definitions.ContainsKey(TestSchemaRef))
{
context.SchemaRegistry.Definitions.Add(TestSchemaRef, TestSchema);
}
operation.Responses["200"] = new Response
{
Description = "This is a Response Description",
Schema = TestSchema
};
}
#endregion
}
Upvotes: 1