XmlDocumentforWebApi 如何包含主项目之外的文档?

用于将 XmlDoc 集成到 Web API 项目中的 文件似乎只能处理所有 API 类型都是 WebApi 项目的一部分的情况。特别是,本文讨论了如何将 XML 文档重新路由到 App_Data/XmlDocument.xml,并取消注释配置中将使用该文件的一行。这隐式地只允许一个项目的文档文件。

但是,在我的设置中,我在一个常见的“模型”项目中定义了请求和响应类型。这意味着,如果我定义了一个端点,比如:

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

其中 OpenIdLoginRequest在单独的 C # 项目中定义如下:

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


...
}

尽管有 XML 文档注释,但是在查看端点特定的帮助页面(即 http://localhost/Help/Api/POST-auth-openid-login)时,request参数的属性不包含任何文档。

我如何才能使带有 XML 文档的子项目中的类型在 WebAPI XML 文档中显示出来?

37542 次浏览

There is no built-in way to achieve this. However, it requires only a few steps:

  1. Enable XML documentation for your subproject (from project properties / build) like you have for your Web API project. Except this time, route it directly to XmlDocument.xml so that it gets generated in your project's root folder.

  2. Modify your Web API project's postbuild event to copy this XML file into your App_Data folder:

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

    Where Subproject.xml should be renamed to whatever your project's name is plus .xml.

  3. Next open Areas\HelpPage\App_Start\HelpPageConfig and locate the following line:

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

    This is the line you initially uncommented in order to enable XML help documentation in the first place. Replace that line with:

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

    This step ensures that XmlDocumentationProvider is passed the directory that contains your XML files, rather than the specific XML file for your project.

  4. Finally, modify Areas\HelpPage\XmlDocumentationProvider in the following ways:

    a. Replace the _documentNavigator field with:

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

    b. Replace the constructor with:

    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. Add the following method below the constructor:

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

    d. And last, fix all compiler errors (there should be three) resulting in references to _documentNavigator.SelectSingleNode and remove the _documentNavigator. portion so that it now calls the new SelectSingleNode method we defined above.

This Last step is what modifies the document provider to support looking within multiple XML documents for the help text rather than just the primary project's.

Now when you examine your Help documentation, it will include XML documentation from types in your related project.

One more simplified way of doing this is by merging the xml files. Example code in my below reply:

Web Api Help Page XML comments from more than 1 files

I ran into this too, but I didn't want to edit or duplicate any of the generated code to avoid problems later.

Building on the other answers, here's a self-contained documentation provider for multiple XML sources. Just drop this into your project:

/// <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));
}
}

...and enable it in your HelpPageConfig with the paths to the XML documents you want:

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

Easiest way to fix this issue is creating the App_Code folder on server you deployed. Then copy the XmlDocument.xml you have in your bin folder locally into the App_Code folder

I found a better solution

  1. Go to properties of your solution and on Built, Out Put, Documentation XML File just fill with your folder on your app data.

  2. Add a line with the file you want to insert into your documentation like this.

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

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