Asp.net Web Api帮助页来自多个文件的XML注释

Asp.net Web Api帮助页来自多个文件的XML注释,asp.net,asp.net-web-api,documentation,asp.net-web-api-helppages,Asp.net,Asp.net Web Api,Documentation,Asp.net Web Api Helppages,我的WebAPI项目中有不同的插件,它们有自己的XML文档,并且有一个集中的帮助页面,但问题是WebAPI的默认帮助页面只支持单个文档文件 new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/Documentation.xml")) 如何从不同的文件加载配置?我想做这样的事: new XmlDocumentationProvider("PluginsFolder/*.xml") 您可以在Are

我的WebAPI项目中有不同的插件,它们有自己的XML文档,并且有一个集中的帮助页面,但问题是WebAPI的默认帮助页面只支持单个文档文件

new XmlDocumentationProvider(HttpContext.Current.Server.MapPath("~/App_Data/Documentation.xml"))
如何从不同的文件加载配置?我想做这样的事:

new XmlDocumentationProvider("PluginsFolder/*.xml")

您可以在
Areas\HelpPage
修改已安装的
XmlDocumentationProvider
,以执行以下操作:

将多个Xml文档文件合并到一个文件中:

示例代码(缺少一些错误检查和验证):


Kirans的解决方案非常有效。我最终使用了他的方法,但创建了一个名为MultiXmlDocumentationProvider的XmlDocumentationProvider副本,并修改了构造函数:

public MultiXmlDocumentationProvider(string xmlDocFilesPath)
{
       XDocument finalDoc = null;
        foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
        {
            using (var fileStream = File.OpenRead(file))
            {
                if (finalDoc == null)
                {
                    finalDoc = XDocument.Load(fileStream);
                }
                else
                {
                    XDocument xdocAdditional = XDocument.Load(fileStream);

                    finalDoc.Root.XPathSelectElement("/doc/members")
                        .Add(xdocAdditional.Root.XPathSelectElement("/doc/members").Elements());
                }
            }
        }

        // Supply the navigator that rest of the XmlDocumentationProvider code looks for
        _documentNavigator = finalDoc.CreateNavigator();
}
public XmlDocumentationProvider(IEnumerable<string> documentPaths)
{
    if (documentPaths.IsNullOrEmpty())
    {
        throw new ArgumentNullException(nameof(documentPaths));
    }
    XDocument fullDocument = null;
    foreach (var documentPath in documentPaths)
    {
        if (documentPath == null)
        {
            throw new ArgumentNullException(nameof(documentPath));
        }

        if (fullDocument == null)
        {
            using (var stream = File.OpenRead(documentPath))
            {
                fullDocument = XDocument.Load(stream);
            }
        }
        else
        {
            using (var stream = File.OpenRead(documentPath))
            {
                var additionalDocument = XDocument.Load(stream);
                fullDocument?.Root?.XPathSelectElement("/doc/members").Add(additionalDocument?.Root?.XPathSelectElement("/doc/members").Elements());
            }
        }
    }

    _documentNavigator = fullDocument?.CreateNavigator();
}
我从HelpPageConfig.cs注册新的提供程序:


在升级时,创建新类并保持原有类不变可能更方便。

我同意gurra777的观点,即创建新类是一种更安全的升级方式。我从这个解决方案开始,但它涉及大量的副本/面食,在几次软件包更新后很容易过时

相反,我保留了
XmlDocumentationProvider
子级的集合。对于每种实现方法,我都会调用子对象来获取第一个非空结果

public class MultiXmlDocumentationProvider : IDocumentationProvider, IModelDocumentationProvider
{
    private IList<XmlDocumentationProvider> _documentationProviders;

    public MultiXmlDocumentationProvider(string xmlDocFilesPath)
    {
        _documentationProviders = new List<XmlDocumentationProvider>();

        foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
        {
            _documentationProviders.Add(new XmlDocumentationProvider(file));
        }
    }

    public string GetDocumentation(System.Reflection.MemberInfo member)
    {
        return _documentationProviders
            .Select(x => x.GetDocumentation(member))
            .FirstOrDefault(x => !string.IsNullOrWhiteSpace(x));
    }

    //and so on...

我没有按照XmlMultiDocumentationProvider的思路创建单独的类,而是向现有的XmlDocumentationProvider添加了一个构造函数。它不采用文件夹名称,而是采用字符串列表,这样您仍然可以精确地指定要包含哪些文件(如果文档xml所在的目录中有其他xml文件,则可能会有问题)。这是我的新构造函数:

public MultiXmlDocumentationProvider(string xmlDocFilesPath)
{
       XDocument finalDoc = null;
        foreach (string file in Directory.GetFiles(xmlDocFilesPath, "*.xml"))
        {
            using (var fileStream = File.OpenRead(file))
            {
                if (finalDoc == null)
                {
                    finalDoc = XDocument.Load(fileStream);
                }
                else
                {
                    XDocument xdocAdditional = XDocument.Load(fileStream);

                    finalDoc.Root.XPathSelectElement("/doc/members")
                        .Add(xdocAdditional.Root.XPathSelectElement("/doc/members").Elements());
                }
            }
        }

        // Supply the navigator that rest of the XmlDocumentationProvider code looks for
        _documentNavigator = finalDoc.CreateNavigator();
}
public XmlDocumentationProvider(IEnumerable<string> documentPaths)
{
    if (documentPaths.IsNullOrEmpty())
    {
        throw new ArgumentNullException(nameof(documentPaths));
    }
    XDocument fullDocument = null;
    foreach (var documentPath in documentPaths)
    {
        if (documentPath == null)
        {
            throw new ArgumentNullException(nameof(documentPath));
        }

        if (fullDocument == null)
        {
            using (var stream = File.OpenRead(documentPath))
            {
                fullDocument = XDocument.Load(stream);
            }
        }
        else
        {
            using (var stream = File.OpenRead(documentPath))
            {
                var additionalDocument = XDocument.Load(stream);
                fullDocument?.Root?.XPathSelectElement("/doc/members").Add(additionalDocument?.Root?.XPathSelectElement("/doc/members").Elements());
            }
        }
    }

    _documentNavigator = fullDocument?.CreateNavigator();
}

我不明白为什么这不在默认版本中。这比微软的做法更有意义。
public XmlDocumentationProvider(IEnumerable<string> documentPaths)
{
    if (documentPaths.IsNullOrEmpty())
    {
        throw new ArgumentNullException(nameof(documentPaths));
    }
    XDocument fullDocument = null;
    foreach (var documentPath in documentPaths)
    {
        if (documentPath == null)
        {
            throw new ArgumentNullException(nameof(documentPath));
        }

        if (fullDocument == null)
        {
            using (var stream = File.OpenRead(documentPath))
            {
                fullDocument = XDocument.Load(stream);
            }
        }
        else
        {
            using (var stream = File.OpenRead(documentPath))
            {
                var additionalDocument = XDocument.Load(stream);
                fullDocument?.Root?.XPathSelectElement("/doc/members").Add(additionalDocument?.Root?.XPathSelectElement("/doc/members").Elements());
            }
        }
    }

    _documentNavigator = fullDocument?.CreateNavigator();
}
var xmlPaths = new[]
{
    HttpContext.Current.Server.MapPath("~/bin/Path.To.FirstNamespace.XML"),
    HttpContext.Current.Server.MapPath("~/bin/Path.To.OtherNamespace.XML")
};
var documentationProvider = new XmlDocumentationProvider(xmlPaths);
config.SetDocumentationProvider(documentationProvider);