2011-04-14 81 views
6

使用.net 4.0 /预览工具包2,我们可以为WCF REST生成帮助页面。如何为Asp.Net MVC生成文档?

无论如何,我们可以为MVC做同样的事吗?

www.somewebsite.com/search/help

我可以创建帮助页面(视图)和揭露他们。

我可以生成XSD架构并吐出为XML。

任何其他指导/建议?

我想生成类似的东西。

UriTemplate http://somewebsite.com/Search/

方法PUT

响应格式的XML

响应架构http://somewebsite.com/help/response/schema

响应示例http://somewebsite.com/help/response/example

更新:

我能够使用下面的代码创建文档。

Route : somewebsite.com/Media/ 
HelpRoute : somewebsite.com/Media/Help (Append help to the parent route) 

Add routes accordingly. See below example. 

routes.MapRoute("Search", 
      "Search/Quick/", 
      new { controller = "Search", action = "Search" }, 
      new { httpMethod = new HttpMethodConstraint("PUT") } 
      ); 

     routes.MapRoute("SearchHelp", 
      "Search/Quick/Help", 
      new { controller = "Search", action = "Search" }, 
      new { helpConstraint = new HelpConstraint { Help = true, SampleType = typeof(Search) } } 
     ); 

public class HelpResult : ViewResult 
{ 
    private string HelpPage { get; set; } 
    private string folderName = "HelpFiles"; 
    private HttpServerUtilityBase server { get; set; } 
    private Type sampleType { get; set; } 
    private string schemaName { get; set; } 

    const string htmlFormat = 
      @" 
     <html> 
     <head> 
      <title>Help</title> 
     </head> 
     <body>   

     <li>URL - {0}</li> 
     <li>Verb - {1}</li> 
     {2} 

     </body> 
     </html> 
     "; 

    public override void ExecuteResult(ControllerContext context) 
    { 
     server = context.HttpContext.Server; 
     StringBuilder parentUrl = new StringBuilder(); 
     var data = context.RouteData.Route.GetRouteData(context.HttpContext); 

     //Getting requested route url. 
     string url = ((Route)(data.Route)).Url; 

     //Getting parent route from requested route url by removing "Help" from the route. 
     string newUrl = url.Substring(0, url.Length - 4); 
     parentUrl.Append("/" + newUrl); 

     sampleType = data.GetSampleType(); 
     var validVerbs = GetValidVerbs(MakeAppRelative(parentUrl.ToString())); 
     CreateSchema(sampleType, true); 
     HelpPage = string.Format(htmlFormat, newUrl, validVerbs, CreateInputSampleText()); 
     context.HttpContext.Response.Output.Write(HelpPage); 
    } 

    private string CreateInputSampleText() 
    { 
     if (sampleType != null && !string.IsNullOrEmpty(sampleType.Name)) 
     { 
      string sampleText = 
       @"<li>Input Sample Xml - <a href='\HelpFiles\{0}.xml'>Click Here</a></li>   
     <li>Input Sample Json - <a href='\HelpFiles\{0}.txt'>Click Here</a></li> 
     <li>Input Schema - <a href='\HelpFiles\{1}'>Click Here</a></li>"; 
      sampleText = string.Format(sampleText, sampleType.Name, schemaName); 
      return sampleText; 
     } 

     return string.Empty; 
    } 

    private static string MakeAppRelative(string url) 
    { 
     if (!url.StartsWith("~")) 
     { 
      if (!url.StartsWith("/")) 
       url = "~/" + url; 
      else 
       url = "~" + url; 
     } 
     return url; 
    } 

    private static string GetValidVerbs(string Url) 
    { 
     StringBuilder validVerbs = new StringBuilder(); 
     var httpMethodOptions = new[] { "GET", "POST", "PUT", "DELETE", "HEAD" }; 
     foreach (var httpMethodOption in httpMethodOptions) 
     { 
      var fakeContext = new FakeHttpContext(MakeAppRelative(Url), httpMethodOption); 
      foreach (Route route in RouteTable.Routes) 
      { 
       var rd = route.GetRouteData(fakeContext); 
       if (rd != null) 
       { 
        bool errorControllerApplied = route.IsErrorController(); 
        if (!errorControllerApplied) 
        { 
         validVerbs.Append(httpMethodOption); 
        } 
       } 
      } 
     } 

     return validVerbs.ToString(); 
    } 

    private void CreateFile(Type type, Stream stream) 
    { 
     using (Stream inputStream = stream) 
     { 
      schemaName = sampleType + "Schema.xml"; 
      string folder = Path.GetFullPath(Path.Combine(server.MapPath("~"), folderName)); 
      string file = Path.Combine(folder, schemaName); 
      if (!Directory.Exists(folder)) 
       Directory.CreateDirectory(folder); 

      using (FileStream fileStream = new FileStream(file, FileMode.Create)) 
      { 
       byte[] fileContent = new byte[inputStream.Length]; 
       inputStream.Read(fileContent, 0, fileContent.Length); 
       fileStream.Write(fileContent, 0, fileContent.Length); 
       fileStream.Flush(); 
      } 
     } 
    } 

    private void CreateSchema(Type type, bool isXmlSerializerType) 
    { 
     System.Collections.IEnumerable schemas; 
     if (isXmlSerializerType) 
     { 
      XmlReflectionImporter importer = new XmlReflectionImporter(); 
      XmlTypeMapping typeMapping = importer.ImportTypeMapping(type); 
      XmlSchemas s = new XmlSchemas(); 
      XmlSchemaExporter exporter = new XmlSchemaExporter(s); 
      exporter.ExportTypeMapping(typeMapping); 
      schemas = s.GetSchemas(null); 
     } 
     else 
     { 
      XsdDataContractExporter exporter = new XsdDataContractExporter(); 
      exporter.Export(type); 
      schemas = exporter.Schemas.Schemas(); 
     } 
     using (MemoryStream stream = new MemoryStream()) 
     { 
      XmlWriterSettings xws = new XmlWriterSettings() { Indent = true }; 
      using (XmlWriter w = XmlWriter.Create(stream, xws)) 
      { 
       w.WriteStartElement("Schemas"); 
       foreach (XmlSchema schema in schemas) 
       { 
        if (schema.TargetNamespace != "http://www.w3.org/2001/XMLSchema") 
        { 
         schema.Write(w); 
        } 
       } 
      } 
      stream.Seek(0, SeekOrigin.Begin); 
      CreateFile(type, stream); 
     } 
    } 
public static class RouteDataExtensions 
{ 
    public static bool IsHelpConstraintApplied(this RouteData data) 
    { 
     if (data != null && data.Route != null) 
     { 
      var constraints = ((Route) (data.Route)).Constraints; 
      var helpConstraint = (from c in constraints.Values 
            where c.GetType().Equals(typeof (HelpConstraint)) 
            select c).FirstOrDefault(); 
      if (helpConstraint != null) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

    public static Type GetSampleType(this RouteData data) 
    { 
     if (data != null && data.Route != null) 
     { 
      var constraints = ((Route)(data.Route)).Constraints; 
      var helpConstraint = (from c in constraints.Values 
            where c.GetType().Equals(typeof(HelpConstraint)) 
            select c).FirstOrDefault(); 
      if (helpConstraint != null) 
      { 
       return ((HelpConstraint) helpConstraint).SampleType; 
      } 
     } 

     return null; 
    } 

    public static string GetMethodType(this RouteData data) 
    { 
     if (data != null && data.Route != null) 
     { 
      var constraints = ((Route) (data.Route)).Constraints; 
      var httpMethodConstraint = (from c in constraints.Values 
             where c.GetType().Equals(typeof (HttpMethodConstraint)) 
             select c).FirstOrDefault(); 
      if (httpMethodConstraint != null) 
      { 
       return ((HttpMethodConstraint) httpMethodConstraint).AllowedMethods.Single(); 
      } 
     } 

     return null; 
    } 

    public static bool IsErrorController(this Route data) 
    { 
     if (data != null) 
     { 
      var defaults = ((Route)(data)).Defaults; 
      var controllerName = (from c in defaults.Values 
             where c.ToString().Contains("Error") 
             select c).FirstOrDefault(); 
      if (controllerName != null) 
      { 
       return true; 
      } 
     } 

     return false; 
    } 

    public static RouteData GetRouteDataByUrl(this string url) 
    { 
     string httpMethod = "PUT"; 
     var fakeContext = new FakeHttpContext(MakeAppRelative(url), httpMethod); 
     return RouteTable.Routes.GetRouteData(fakeContext); 
    } 

    private static string MakeAppRelative(string url) 
    { 
     if (!url.StartsWith("~")) 
     { 
      if (!url.StartsWith("/")) 
       url = "~/" + url; 
      else 
       url = "~" + url; 
     } 
     return url; 
    } 
} 

public class HelpConstraint : IRouteConstraint 
{ 
    public bool Help { get; set; } 
    public Type SampleType { get; set; } 

    public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection) 
    { 
     if(Help) 
     { 
      return true; 
     } 

     return false; 
    } 
} 

References 
http://stephenwalther.com/blog/archive/2008/08/03/asp-net-mvc-tip-29-build-a-controller-to-debug-your-custom-routes.aspx 
http://aspnet.codeplex.com/releases/view/24644 

此代码不是无bug的。如果有任何问题,请发布改进。需要您自担风险使用它。

+0

你说的是记录你的代码(dll),如果是的话,我个人使用Sandcastle,输出html,然后你可以把它转储到你的网站 – 2011-04-14 17:47:23

回答

1

很可能你现在已经解决了你的问题。无论如何,我认为你需要IApiExplorer。看看this blog

+0

Lone链接被认为是一个不好的答案(参见[faq# ),因为它本身毫无意义,并且**目标资源不能保证在将来活着**。 [这将是最好的](http://meta.stackexchange.com/q/8259)在这里包括答案的基本部分,并提供链接供参考。 – j0k 2013-02-08 16:42:25