Làm cách nào để Tài liệu Xml cho Web Api có thể bao gồm tài liệu từ bên ngoài dự án chính?


102

Các tài liệu cho phép tích hợp vào các dự án XMLdoc Api web của bạn dường như chỉ những tình huống xử lý mà tất cả các loại API của bạn là một phần của dự án WebAPI của bạn. Đặc biệt, nó thảo luận về cách định tuyến lại tài liệu XML đến App_Data/XmlDocument.xmlvà bỏ ghi chú một dòng trong cấu hình của bạn sẽ sử dụng tệp đó. Điều này mặc nhiên chỉ cho phép một tệp tài liệu của dự án.

Tuy nhiên, trong thiết lập của mình, tôi đã xác định các loại yêu cầu và phản hồi trong dự án "Mô hình" chung. Điều này có nghĩa là nếu tôi có một điểm cuối được xác định như:

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

Nơi OpenIdLoginRequestđược xác định trong một dự án C # riêng biệt như vậy:

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

    ...
}

Mặc dù doccomments XML, các thuộc tính của requesttham số không chứa tài liệu khi bạn xem trang trợ giúp dành riêng cho điểm cuối (tức là http://localhost/Help/Api/POST-auth-openid-login).

Làm cách nào để tôi có thể thực hiện nó để các loại trong dự án con có tài liệu XML được hiển thị trong tài liệu XML của Web API?

Câu trả lời:


165

Không có cách tích hợp nào để đạt được điều này. Tuy nhiên, nó chỉ yêu cầu một vài bước:

  1. Bật tài liệu XML cho dự án con của bạn (từ các thuộc tính / bản dựng của dự án) giống như bạn có cho dự án API Web của mình. Ngoại trừ lần này, hãy định tuyến nó trực tiếp để XmlDocument.xmlnó được tạo trong thư mục gốc của dự án của bạn.

  2. Sửa đổi sự kiện tạo sau của dự án API Web của bạn để sao chép tệp XML này vào App_Datathư mục của bạn :

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

    Nơi Subproject.xmlnên được đổi tên thành bất cứ điều gì cộng với tên dự án của bạn .xml.

  3. Tiếp theo, mở Areas\HelpPage\App_Start\HelpPageConfigvà tìm dòng sau:

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

    Đây là dòng ban đầu bạn đã bỏ ghi chú để kích hoạt tài liệu trợ giúp XML ngay từ đầu. Thay thế dòng đó bằng:

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

    Bước này đảm bảo rằng XmlDocumentationProviderthư mục chứa các tệp XML của bạn được chuyển qua, thay vì tệp XML cụ thể cho dự án của bạn.

  4. Cuối cùng, sửa đổi Areas\HelpPage\XmlDocumentationProvider theo những cách sau:

    a. Thay thế _documentNavigatortrường bằng:

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

    b. Thay thế hàm tạo bằng:

    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. Thêm phương thức sau vào bên dưới hàm tạo:

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

    d. Và cuối cùng, hãy sửa tất cả các lỗi trình biên dịch (nên có ba) dẫn đến các tham chiếu đến _documentNavigator.SelectSingleNodevà loại bỏ _documentNavigator.phần để bây giờ nó gọi SelectSingleNodephương thức mới mà chúng tôi đã xác định ở trên.

Bước cuối cùng này là những gì sửa đổi trình cung cấp tài liệu để hỗ trợ tìm kiếm trong nhiều tài liệu XML cho văn bản trợ giúp thay vì chỉ của dự án chính.

Bây giờ khi bạn kiểm tra tài liệu Trợ giúp của mình, nó sẽ bao gồm tài liệu XML từ các loại trong dự án liên quan của bạn.


7
Câu trả lời xuất sắc. Tôi thực sự nghĩ rằng sẽ dễ dàng hơn một chút để hàm tạo chấp nhận một mảng chuỗi: public XmlDocumentationProvider (string appDataPath) và liệt kê danh sách này trong nhà cung cấp Tài liệu.
Thuyền trưởng John

14
Tuyệt vời, đây chính là thứ tôi đang tìm kiếm !! Đề xuất thay thế var files...dòng bằng var files = Directory.GetFiles(documentPath, "*.xml");nếu bạn (như tôi) không phải lúc nào cũng biết tên / số lượng tệp tài liệu xml sẽ ở đó. Cũng có thể thực hiện lọc bổ sung nếu cần.
sǝɯɐſ

2
@Leandro, cảm ơn vì đã cải thiện câu trả lời! :) Vui mừng bạn đã tìm thấy nó hữu ích.
Kirk Woll

5
Nếu tôi có thể tôi sẽ +10 bạn cho câu trả lời chi tiết và chính xác này
Mark van Straten

2
Tôi muốn thêm các sửa đổi của mình lên trên một số sửa đổi khác ở đây. Tôi đã sử dụng ký hiệu ... \ để tạo tệp xml trong thư mục App_Data \ Documents của dự án gốc. Sau đó, tôi đã sử dụng phương pháp @ sǝɯɐſ để tạo xung tất cả các tệp xml từ thư mục đó. Điều này hoạt động tuyệt vời và ngạc nhiên rằng đây không chỉ là cách nó hoạt động ngoài hộp. Cảm ơn nhiều.
Darroll

32

Tôi cũng gặp phải vấn đề này, nhưng tôi không muốn chỉnh sửa hoặc sao chép bất kỳ mã nào đã tạo để tránh sự cố sau này.

Dựa trên các câu trả lời khác, đây là một nhà cung cấp tài liệu độc lập cho nhiều nguồn XML. Chỉ cần thả cái này vào dự án của bạn:

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

... và kích hoạt nó trong của bạn HelpPageConfigvới các đường dẫn đến các tài liệu XML mà bạn muốn:

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

Đây là một giải pháp tuyệt vời. Tôi thích nó hơn các giải pháp yêu cầu sửa đổi các lớp HelpPage mặc định vì chúng sẽ bị ghi đè khi cập nhật.
AronVanAmmers

3
Điều này hoạt động tuyệt vời, cảm ơn bạn đã đăng. Để tiết kiệm cho bất kỳ ai sử dụng một chút thời gian này, bạn vẫn cần thực hiện hai giai đoạn đầu tiên của câu trả lời được chấp nhận của kirk ở trên, tức là 1) Bật tài liệu XML cho dự án con của bạn và 2) Sửa đổi sự kiện xây dựng lại dự án Web API của bạn để sao chép tệp XML này vào thư mục App_Data của bạn.
tomRedox

1
và sau đó dòng này trở thành: config.SetDocumentationProvider (MultiXmlDocumentationProvider mới (HttpContext.Current.Server.MapPath ("~ / App_Data / [tên tệp xml của dự án web api gốc, mặc định thành XmlDocument] .xml"), HttpContext.Current.Server.MapPath ("~ / App_Data / [Bất cứ thứ gì bạn đã gọi tên tệp SubProject xml của mình] .xml")));
tomRedox

Đã làm theo các bước nhưng không hoạt động :(. Không có lỗi nên không chắc đã xảy ra lỗi gì. Nó vẫn chỉ hiển thị tài liệu api chứ không hiển thị tài liệu dự án bổ sung. Tôi cũng đã thử các bước trong câu trả lời được chấp nhận và điều tương tự . Tôi nên kiểm tra bất cứ điều gì cụ thể?
stt106

Vì lý do nào đó, tôi vẫn thấy api / me GET mặc định đi kèm với mẫu dự án bắt đầu trong VS.
John Zabroski



0

Cách dễ nhất để khắc phục sự cố này là tạo thư mục App_Code trên máy chủ mà bạn đã triển khai. Sau đó sao chép cục bộ XmlDocument.xml bạn có trong thư mục bin của mình vào thư mục App_Code


Cảm ơn đã gợi ý !! Không còn -1 cho câu trả lời hữu ích như vậy. Có, nếu bạn triển khai nó cho Dịch vụ ứng dụng đám mây Azure, nhiều vấn đề xảy ra với việc triển khai nhiều * .xml, vì vậy, chẳng hạn như việc làm cho chúng có sẵn để vênh vang, có thể thực sự khó khăn. Nhưng tôi muốn chọn một thư mục phía máy chủ ASP.Net tiêu chuẩn khác, đó là App_GlobalResources, vì tệp xmldoc khá giống với tài nguyên. Điều này đặc biệt đúng vì tôi vẫn chưa có thư mục App_Code trong dự án của mình và việc tạo thư mục tiêu chuẩn nào không quan trọng.
moudrick

Các thư mục tiêu chuẩn sau đây làm việc cho tôi: App_Code - không nhìn thấy được từ khách hàng trên các thiết lập mặc định App_GlobalResources - không nhìn thấy được từ khách hàng trên các thiết lập mặc định App_LocalResources - không nhìn thấy được từ khách hàng trên các thiết lập mặc định
moudrick

Hãy để tôi cũng liệt kê các vấn đề với từng thư mục tiêu chuẩn không hoạt động với tôi. bin - chỉ * .xml để lắp ráp chính là deplopyed để App_Data - bối cảnh thực tế nhất là để bỏ qua tất cả mọi thứ trong thư mục này vào triển khai để đám mây
moudrick

Bất cứ ai quan tâm có thể chỉnh sửa câu trả lời này để phản ánh tất cả những cân nhắc ở trên, có thể là với những suy đoán mở rộng?
moudrick
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.