2016-03-23 16 views
7

Tôi đang tìm cách hiển thị/ẩn các tuyến đường WebAPI trong tài liệu Swagger bằng SwashBuckle theo cách có thể cấu hình. Thêm [ApiExplorerSettings(IgnoreApi = true)] thực sự sẽ ẩn các tuyến đường nhưng tôi cần phải biên dịch lại mỗi khi tôi muốn thay đổi.Xóa tuyến đường bằng IOperationFilter trong SwashBuckle

Tôi đã xem xét việc tạo một IOperationFilter để làm việc với Thuộc tính tùy chỉnh mà tôi đã xác định. Bằng cách đó tôi có thể trang trí các tuyến đường với một số [SwaggerTag("MobileOnly")] và kiểm tra web.config hoặc một cái gì đó để xem tuyến đường có được hiển thị hay không. Các thuộc tính được định nghĩa như vậy:

public class SwaggerTagAttribute : Attribute 
{ 
    public string[] Tags { get; private set; } 

    public SwaggerTagAttribute(params string[] tags) 
    { 
     this.Tags = tags; 
    } 
} 

các IOperationFilter phát hiện các thuộc tính được định nghĩa và các IDocumentFilter mà loại bỏ các con đường được xác định ở đây:

public class RemoveTaggedOperationsFilter : IOperationFilter, IDocumentFilter 
{ 
    private List<string> TagsToHide; 

    public RemoveTaggedOperationsFilter() 
    { 
     TagsToHide = ConfigurationManager.AppSettings["TagsToHide"].Split(',').ToList(); 
    } 

    public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription) 
    { 
     var tags = apiDescription.ActionDescriptor 
      .GetCustomAttributes<SwaggerTagAttribute>() 
      .Select(t => t.Tags) 
      .FirstOrDefault(); 

     if (tags != null && TagsToHide.Intersect(tags).Any()) 
     { 
      operation.tags = new List<string> {"Remove Me "}; 
     } 
    } 

    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer) 
    { 
     foreach (var value in swaggerDoc.paths.Values) 
     { 
      if (value.post != null && value.post.tags.Contains("Remove Me")) 
       value.post = null; 

      if (value.get != null && value.get.tags.Contains("Remove Me")) 
       value.get = null; 

      if (value.put != null && value.put.tags.Contains("Remove Me")) 
       value.put = null; 

      if (value.delete != null && value.delete.tags.Contains("Remove Me")) 
       value.delete = null; 
     } 
    } 
} 

Và đăng ký như vậy:

GlobalConfiguration.Configuration 
      .EnableSwagger(c => 
       { 
        c.OperationFilter<RemoveTaggedOperationsFilter>(); 
        c.DocumentFilter<RemoveTaggedOperationsFilter>(); 
       }); 

Tôi cảm thấy rằng điều này là không hiệu quả và bị hack để gắn thẻ thứ gì đó để xóa sau này khi tôi có quyền truy cập vào nó trước đó. Có cách nào để tôi chỉ xóa tuyến đường từ trong vòng IOperationFilter.Apply thay vì đợi IDocumentFilter và quét qua tuyến đường đó không?

Trả lời

3

Ai đó đã đăng câu trả lời trước đó và cho biết họ sẽ đăng mã khi họ có cơ hội. Họ đã xóa câu trả lời của họ vì lý do nào đó nhưng nó đã đưa tôi đến một giải pháp tốt hơn.

Thay vì sử dụng IOperationFilter để gắn thẻ tuyến đường và sau đó IDocumentFilter để xóa tuyến đường sau này, bạn chỉ có thể sử dụng IDocumentFilter để tìm thuộc tính tùy chỉnh và xóa thuộc tính đó trong một lần ngã. Mã này là dưới đây:

public class HideTaggedOperationsFilter : IDocumentFilter 
{ 
    private List<string> TagsToHide; 

    public HideTaggedOperationsFilter() 
    { 
     TagsToHide = ConfigurationManager.AppSettings["TagsToHide"].Split(',').ToList(); 
    } 

    public void Apply(SwaggerDocument swaggerDoc, SchemaRegistry schemaRegistry, IApiExplorer apiExplorer) 
    { 
     if (_tagsToHide == null) return; 

     foreach (var apiDescription in apiExplorer.ApiDescriptions) 
     { 
      var tags = apiDescription.ActionDescriptor 
       .GetCustomAttributes<SwaggerTagAttribute>() 
       .Select(t => t.Tags) 
       .FirstOrDefault(); 

      if (tags == null || !_tagsToHide.Intersect(tags).Any()) 
       continue; 

      var route = "/" + apiDescription.Route.RouteTemplate.TrimEnd('/'); 
      swaggerDoc.paths.Remove(route); 
     } 
    } 
} 

public class SwaggerTagAttribute : Attribute 
{ 
    public string[] Tags { get; } 

    public SwaggerTagAttribute(params string[] tags) 
    { 
     this.Tags = tags; 
    } 
} 

Đăng ký IDocumentFilter:

GlobalConfiguration.Configuration.EnableSwagger(c => 
{ 
    ... 
    c.DocumentFilter<HideTaggedOperationsFilter>(); 
}); 

Sau đó chỉ cần trang trí một tuyến đường như vậy:

[SwaggerTag("MobileOnly")] 
public IHttpActionResult SendTest(Guid userId) 
{ 
    return OK(); 
} 

Edit: Có một số bài viết vấn đề trên trang GitHub cho SwashBuckle khuyên bạn nên đặt từng động từ HTTP thành null trên swaggerDoc.path trong Apply. Tôi tìm thấy điều này để phá vỡ rất nhiều máy phát điện tự động mã như AutoRest vì vậy tôi chỉ đơn giản là loại bỏ đường dẫn như một toàn thể. (Nó trông gọn gàng hơn)

+0

Cách tiếp cận này sẽ không hoạt động nếu bạn có cùng một tuyến đường với các động từ khác nhau, nhưng chỉ muốn vô hiệu hóa một số. Tức là có GET/transcations và POST/transaction, cả hai đều bị xóa khi chỉ có 1 phương thức hành động được trang trí với thuộc tính tùy chỉnh. Bạn cũng cần phải xem xét phương pháp http. –

+0

@ParaJaco đó là một điểm tuyệt vời. Nó có thể sẽ không quá khó khăn để mở rộng nó để đưa các động từ HTTP vào tài khoản. – LukeP

+0

Tôi có thể trang trí toàn bộ bộ điều khiển không? – Rbacarin

Các vấn đề liên quan