Sembra Swashbuckle non supporta questa out of the box, ma si può allungare per ottenere il risultato desiderato, pur riutilizzando la maggior parte delle infrastrutture di spavalderia. Potrebbe volerci un po 'di tempo e sforzi, ma non molto in generale, ma troppo per me per fornire una soluzione completa in questa risposta. Comunque cercherò almeno di iniziare. Nota che tutto il codice qui sotto non sarà molto pulito e pronto per la produzione.
Ciò che è necessario prima è creare e registrare personalizzato IApiExplorer
. Questa è un'interfaccia utilizzata da Swashbuckle per recuperare le descrizioni della tua API ed è responsabile dell'esplorazione di tutti i controller e le azioni per raccogliere le informazioni richieste. Estenderemo sostanzialmente ApiExplorer esistente con il codice per esplorare le nostre classi di messaggi e creare una descrizione API da loro. Interfaccia stessa è semplice: Descrizione
public interface IApiExplorer
{
Collection<ApiDescription> ApiDescriptions { get; }
}
Api classe contiene varie informazioni sul funzionamento api, ed è quello che viene utilizzato da Swashbuckle per costruire la pagina ui spavalderia. Ha una proprietà problematica: ActionDescriptor
. Rappresenta l'azione asp.net mvc e non abbiamo azioni, non abbiamo controller.È possibile utilizzare un'implementazione fittizia di questo o simulare il comportamento di asp.net HttpActionDescriptor e fornire valori reali. Per semplicità andremo con il primo itinerario:
class DummyActionDescriptor : HttpActionDescriptor {
public DummyActionDescriptor(Type messageType, Type returnType) {
this.ControllerDescriptor = new DummyControllerDescriptor() {
ControllerName = "Message Handlers"
};
this.ActionName = messageType.Name;
this.ReturnType = returnType;
}
public override Collection<HttpParameterDescriptor> GetParameters() {
// note you might provide properties of your message class and HttpParameterDescriptor here
return new Collection<HttpParameterDescriptor>();
}
public override string ActionName { get; }
public override Type ReturnType { get; }
public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken) {
// will never be called by swagger
throw new NotSupportedException();
}
}
class DummyControllerDescriptor : HttpControllerDescriptor {
public override Collection<T> GetCustomAttributes<T>() {
// note you might provide some asp.net attributes here
return new Collection<T>();
}
}
Qui forniamo solo alcune sostituzioni che spavalderia chiamerà e fallirà se non abbiamo fornire i valori per loro.
Ora definiamo alcuni attributi per decorare le classi di messaggio con:
class MessageAttribute : Attribute {
public string Url { get; }
public string Description { get; }
public MessageAttribute(string url, string description = null) {
Url = url;
Description = description;
}
}
class RespondsWithAttribute : Attribute {
public Type Type { get; }
public RespondsWithAttribute(Type type) {
Type = type;
}
}
E alcuni messaggi:
abstract class BaseMessage {
}
[Message("/api/commands/CreateOrder", "This command creates new order")]
[RespondsWith(typeof(CreateOrderResponse))]
class CreateOrderCommand : BaseMessage {
}
class CreateOrderResponse {
public long OrderID { get; set; }
public string Description { get; set; }
}
ApiExplorer Ora personalizzato:
class MessageHandlerApiExplorer : IApiExplorer {
private readonly ApiExplorer _proxy;
public MessageHandlerApiExplorer() {
_proxy = new ApiExplorer(GlobalConfiguration.Configuration);
_descriptions = new Lazy<Collection<ApiDescription>>(GetDescriptions, true);
}
private readonly Lazy<Collection<ApiDescription>> _descriptions;
private Collection<ApiDescription> GetDescriptions() {
var desc = _proxy.ApiDescriptions;
foreach (var handlerDesc in ReadDescriptionsFromHandlers()) {
desc.Add(handlerDesc);
}
return desc;
}
public Collection<ApiDescription> ApiDescriptions => _descriptions.Value;
private IEnumerable<ApiDescription> ReadDescriptionsFromHandlers() {
foreach (var msg in Assembly.GetExecutingAssembly().GetTypes().Where(c => typeof(BaseMessage).IsAssignableFrom(c))) {
var urlAttr = msg.GetCustomAttribute<MessageAttribute>();
var respondsWith = msg.GetCustomAttribute<RespondsWithAttribute>();
if (urlAttr != null && respondsWith != null) {
var desc = new ApiDescription() {
HttpMethod = HttpMethod.Get, // grab it from some attribute
RelativePath = urlAttr.Url,
Documentation = urlAttr.Description,
ActionDescriptor = new DummyActionDescriptor(msg, respondsWith.Type)
};
var response = new ResponseDescription() {
DeclaredType = respondsWith.Type,
ResponseType = respondsWith.Type,
Documentation = "This is some response documentation you grabbed from some other attribute"
};
desc.GetType().GetProperty(nameof(desc.ResponseDescription)).GetSetMethod(true).Invoke(desc, new object[] {response});
yield return desc;
}
}
}
}
E infine registrare IApiExplorer (dopo hai registrato le tue cose Swagger) con:
GlobalConfiguration.Configuration.Services.Replace(typeof(IApiExplorer), new MessageHandlerApiExplorer());
Dopo aver fatto tutto ciò che possiamo vedere il nostro comando messaggio personalizzato nell'interfaccia spavalderia:

Avete bisogno di un po 'di soluzione pronta all'uso, o semplicemente un modo per estendere Swashbuckle di includere i vostri gestori personalizzati documentazione? – Evk
@Evk che estende lo Swashbuckle farebbe assolutamente. – Steven
E come (o sta andando a) documentare i gestori dei messaggi? Decora tu stesso le classi dei messaggi con alcuni attributi personalizzati? – Evk