Con .net 4.0/Preview kit 2, podemos generar páginas de ayuda para WCF REST.¿Cómo generar documentación para Asp.Net MVC?
¿Hay alguna forma en que podamos hacer lo mismo para MVC?
www.somewebsite.com/search/help
puedo crear páginas de ayuda (vistas) y exponerlos.
Puedo generar el esquema XSD y escupir como xml.
¿Alguna otra orientación/sugerencia?
Quiero generar algo similar a esto.
UriTemplate http://somewebsite.com/Search/
método PUT
Formato de respuesta XML
esquema de respuesta http://somewebsite.com/help/response/schema
Ejemplo de respuesta http://somewebsite.com/help/response/example
Actualización:
Pude crear documentación usando el código siguiente.
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
Este código no está libre de errores. Por favor, publique mejoras si tiene alguna. Úselo bajo su propio riesgo.
¿Está hablando de documentar su código (dll), si es así, yo personalmente uso Sandcastle, el html de salida, y luego puede volcarlo en su sitio web –