In che modo la documentazione Xml per Web Api può includere documentazione oltre il progetto principale?


102

La documentazione per abilitare l'integrazione XmlDoc nei tuoi progetti Web Api sembra gestire solo le situazioni in cui tutti i tuoi tipi di API fanno parte del tuo progetto WebApi. In particolare, discute come reindirizzare la documentazione XML App_Data/XmlDocument.xmle decommentare una riga nella configurazione che consumerà quel file. Ciò consente implicitamente solo il file di documentazione di un progetto.

Tuttavia, nella mia configurazione ho i miei tipi di richiesta e risposta definiti in un progetto "Modelli" comune. Ciò significa che se ho un endpoint definito come:

[Route("auth/openid/login")]
public async Task<AuthenticationResponse> Login(OpenIdLoginRequest request) { ... }

Where OpenIdLoginRequestè definito in un progetto C # separato in questo modo:

public class OpenIdLoginRequest
{
    /// <summary>
    /// Represents the OpenId provider that authenticated the user. (i.e. Facebook, Google, etc.)
    /// </summary>
    [Required]
    public string Provider { get; set; }

    ...
}

Nonostante i doccomments XML, le proprietà del requestparametro non contengono documentazione quando si visualizza la pagina della guida specifica dell'endpoint (cioè http://localhost/Help/Api/POST-auth-openid-login).

Come posso fare in modo che i tipi nei sottoprogetti con documentazione XML vengano visualizzati nella documentazione XML dell'API Web?

Risposte:


165

Non esiste un modo integrato per ottenere questo risultato. Tuttavia, richiede solo pochi passaggi:

  1. Abilita la documentazione XML per il tuo sottoprogetto (dalle proprietà / build del progetto) come hai fatto per il tuo progetto API Web. Tranne questa volta, indirizzalo direttamente a in XmlDocument.xmlmodo che venga generato nella cartella principale del tuo progetto.

  2. Modifica l'evento post-compilazione del tuo progetto API Web per copiare questo file XML nella tua App_Datacartella:

    copy "$(SolutionDir)SubProject\XmlDocument.xml" "$(ProjectDir)\App_Data\Subproject.xml"

    Dove Subproject.xmldovrebbe essere rinominato qualunque sia il nome del progetto più .xml.

  3. Quindi apri Areas\HelpPage\App_Start\HelpPageConfige individua la riga seguente:

    config.SetDocumentationProvider(new XmlDocumentationProvider(
        HttpContext.Current.Server.MapPath("~/App_Data/XmlDocument.xml")));
    

    Questa è la riga che inizialmente hai decommentato per abilitare la documentazione della guida XML in primo luogo. Sostituisci quella riga con:

    config.SetDocumentationProvider(new XmlDocumentationProvider(
        HttpContext.Current.Server.MapPath("~/App_Data")));
    

    Questo passaggio garantisce che XmlDocumentationProvidervenga passata la directory che contiene i file XML, anziché il file XML specifico per il progetto.

  4. Infine, modifica Areas\HelpPage\XmlDocumentationProvidernei seguenti modi:

    un. Sostituisci il _documentNavigatorcampo con:

    private List<XPathNavigator> _documentNavigators = new List<XPathNavigator>();

    b. Sostituisci il costruttore con:

    public XmlDocumentationProvider(string appDataPath)
    {
        if (appDataPath == null)
        {
            throw new ArgumentNullException("appDataPath");
        }
    
        var files = new[] { "XmlDocument.xml", "Subproject.xml" };
        foreach (var file in files)
        {
            XPathDocument xpath = new XPathDocument(Path.Combine(appDataPath, file));
            _documentNavigators.Add(xpath.CreateNavigator());
        }
    }
    

    c. Aggiungi il seguente metodo sotto il costruttore:

    private XPathNavigator SelectSingleNode(string selectExpression)
    {
        foreach (var navigator in _documentNavigators)
        {
            var propertyNode = navigator.SelectSingleNode(selectExpression);
            if (propertyNode != null)
                return propertyNode;
        }
        return null;
    }
    

    d. Infine, correggi tutti gli errori del compilatore (dovrebbero essercene tre) risultanti in riferimenti _documentNavigator.SelectSingleNodee rimuovi la _documentNavigator.parte in modo che ora chiami il nuovo SelectSingleNodemetodo che abbiamo definito sopra.

Questo ultimo passaggio è ciò che modifica il fornitore del documento per supportare la ricerca all'interno di più documenti XML per il testo della guida piuttosto che solo per il progetto principale.

Ora, quando esamini la documentazione della Guida, includerà la documentazione XML dai tipi nel progetto correlato.


7
Ottima risposta. In realtà penso che sia un po 'più facile per il costruttore accettare un array di stringhe: public XmlDocumentationProvider (string appDataPath) ed enumerare questo elenco nel provider di documentazione.
Capitano John

14
Fantastico, questo era proprio quello che stavo cercando !! Suggerisci di sostituire la var files...riga con var files = Directory.GetFiles(documentPath, "*.xml");se tu (come me) non sempre saprai i nomi / il numero dei file di documentazione xml che saranno lì. Potrebbe anche eseguire ulteriori filtri, se necessario.
dal

2
@ Leandro, grazie per aver migliorato la risposta! :) Sono contento che tu l'abbia trovato utile.
Kirk Woll

5
Se potessi, ti farei +10 per questa risposta dettagliata e corretta
Mark van Straten

2
Vorrei aggiungere le mie modifiche in cima ad alcune delle altre qui. Ho usato la notazione ... \ per creare il file xml nella cartella App_Data \ documentazione del progetto radice. Ho quindi utilizzato il metodo @ sǝɯɐſ per estrarre tutti i file xml da quella directory. Funziona magnificamente e sono sorpreso che non sia solo così che funziona fuori dagli schemi. Grazie molto.
Darroll

32

Mi sono imbattuto anche in questo, ma non volevo modificare o duplicare il codice generato per evitare problemi in seguito.

Basandosi sulle altre risposte, ecco un fornitore di documentazione autonomo per più origini XML. Inseriscilo nel tuo progetto:

/// <summary>A custom <see cref="IDocumentationProvider"/> that reads the API documentation from a collection of XML documentation files.</summary>
public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
    /*********
    ** Properties
    *********/
    /// <summary>The internal documentation providers for specific files.</summary>
    private readonly XmlDocumentationProvider[] Providers;


    /*********
    ** Public methods
    *********/
    /// <summary>Construct an instance.</summary>
    /// <param name="paths">The physical paths to the XML documents.</param>
    public MultiXmlDocumentationProvider(params string[] paths)
    {
        this.Providers = paths.Select(p => new XmlDocumentationProvider(p)).ToArray();
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetDocumentation(MemberInfo subject)
    {
        return this.GetFirstMatch(p => p.GetDocumentation(subject));
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetDocumentation(Type subject)
    {
        return this.GetFirstMatch(p => p.GetDocumentation(subject));
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetDocumentation(HttpControllerDescriptor subject)
    {
        return this.GetFirstMatch(p => p.GetDocumentation(subject));
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetDocumentation(HttpActionDescriptor subject)
    {
        return this.GetFirstMatch(p => p.GetDocumentation(subject));
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetDocumentation(HttpParameterDescriptor subject)
    {
        return this.GetFirstMatch(p => p.GetDocumentation(subject));
    }

    /// <summary>Gets the documentation for a subject.</summary>
    /// <param name="subject">The subject to document.</param>
    public string GetResponseDocumentation(HttpActionDescriptor subject)
    {
        return this.GetFirstMatch(p => p.GetResponseDocumentation(subject));
    }


    /*********
    ** Private methods
    *********/
    /// <summary>Get the first valid result from the collection of XML documentation providers.</summary>
    /// <param name="expr">The method to invoke.</param>
    private string GetFirstMatch(Func<XmlDocumentationProvider, string> expr)
    {
        return this.Providers
            .Select(expr)
            .FirstOrDefault(p => !String.IsNullOrWhiteSpace(p));
    }
}

... e abilitalo nel tuo HelpPageConfigcon i percorsi ai documenti XML che desideri:

config.SetDocumentationProvider(new MultiXmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/Api.xml"), HttpContext.Current.Server.MapPath("~/App_Data/Api.Models.xml")));

Questa è un'ottima soluzione. Lo preferisco rispetto alle soluzioni che richiedono la modifica delle classi HelpPage predefinite in quanto verranno sovrascritte negli aggiornamenti.
AronVanAmmers

3
Funziona brillantemente, grazie per aver postato. Per risparmiare un po 'di tempo a chiunque lo utilizzi, devi ancora eseguire le prime due fasi della risposta accettata da kirk sopra, ovvero 1) Abilita la documentazione XML per il tuo sottoprogetto e 2) Modifica l'evento post-compilazione del tuo progetto API Web per copiare questo file XML in la tua cartella App_Data.
tomRedox

1
e quindi questa riga diventa: config.SetDocumentationProvider (new MultiXmlDocumentationProvider (HttpContext.Current.Server.MapPath ("~ / App_Data / [nome file xml del progetto api web originale, il valore predefinito è XmlDocument] .xml"), HttpContext.CurrentPath.Server.Map ("~ / App_Data / [Qualunque sia il nome del file xml del tuo progetto secondario] .xml")));
tomRedox

Ho seguito i passaggi ma non ha funzionato :(. Non ci sono errori, quindi non sono sicuro di cosa sia andato storto. Mostra ancora solo il documento api ma non il documento aggiuntivo del progetto. Ho anche provato i passaggi nella risposta accettata ed è la stessa cosa Dovrei controllare qualcosa in particolare?
stt106

Per qualche motivo vedo ancora l'API / me GET predefinito fornito con il modello di progetto per iniziare in VS.
John Zabroski



0

Il modo più semplice per risolvere questo problema è creare la cartella App_Code sul server che hai distribuito. Quindi copia il XmlDocument.xml che hai nella tua cartella bin localmente nella cartella App_Code


Grazie per il suggerimento !! Non più -1 per una risposta così utile. Sì, se lo si distribuisce nel servizio app cloud di Azure, si verificano molti problemi con la distribuzione di più file * .xml, quindi renderli disponibili per spavalderia, ad esempio, potrebbe essere davvero complicato. Ma preferirei scegliere un'altra cartella lato server ASP.Net standard, ovvero App_GlobalResources, poiché i file xmldoc sono praticamente simili alle risorse. È particolarmente vero perché non avevo ancora la cartella App_Code nel mio progetto e non importava quale cartella standard creare.
moudrick

La seguente cartella standard ha funzionato per me: App_Code - non è visibile dal client nelle impostazioni predefinite App_GlobalResources - non è visibile dal client nelle impostazioni predefinite App_LocalResources - non è visibile dal client nelle impostazioni predefinite
moudrick

Vorrei anche elencare i problemi con ciascuna delle cartelle standard che non funzionavano per me. bin - solo * .xml per l'assemblaggio principale viene distribuito in App_Data - l'impostazione più pratica è saltare tutto in questa cartella durante la distribuzione nel cloud
moudrick

Qualcuno che fosse interessato potrebbe modificare questa risposta per riflettere tutte queste considerazioni di cui sopra, probabilmente con speculazioni estese?
moudrick
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.