Skip to content

Commit

Permalink
Removing all my changes to metadata.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tony Chow committed Mar 10, 2012
1 parent 05ae5bf commit d4026c0
Show file tree
Hide file tree
Showing 12 changed files with 1,082 additions and 0 deletions.
Binary file added lib/tests/ServiceStack.OrmLite.SqliteNET.dll
Binary file not shown.
Binary file added lib/tests/System.Data.SQLite.dll
Binary file not shown.
@@ -0,0 +1,33 @@
using System;
using System.Xml.Linq;

namespace ServiceStack.WebHost.Endpoints.Metadata
{
/// <summary>
/// The base class for code elements (classes and properties
/// in this case) that are XML-documented.
/// </summary>
public abstract class DocumentedCodeElementBase
{
/// <summary>
/// <para>Gets or sets the name of the code element.
/// For instance, if this instance represents a class,
/// it would be the name of the class.</para>
/// </summary>
/// <value>
/// <para>A <see cref="String"/> providing the name of the
/// documented code element; never <see langword="null"/>.</para>
/// </value>
public string Name { get; set; }

/// <summary>
/// <para>Gets or sets the XML documentation attached to this
/// code element.</para>
/// </summary>
/// <value>
/// <para>An <see cref="XElement"/> class providing the documentation;
/// <see langword="null"/> if documentation is not available.</para>
/// </value>
public XElement XmlDocumentation { get; set; }
}
}
26 changes: 26 additions & 0 deletions src/ServiceStack/WebHost.EndPoints/Metadata/DtoDoc.cs
@@ -0,0 +1,26 @@
using System.Collections.Generic;

namespace ServiceStack.WebHost.Endpoints.Metadata
{
/// <summary>
/// Represents a documented DTO, such as a request or a response.
/// </summary>
public sealed class DtoDoc: DocumentedCodeElementBase
{
/// <summary>
/// <para>Initializes an instance of the <see cref="DtoDoc"/> class.</para>
/// </summary>
internal DtoDoc()
{
Properties = new List<PropertyDoc>();
}

/// <summary>
/// Gets the collection of objects encapsulating documentation on DTO properties.
/// </summary>
/// <value>
/// A collection of <see cref="Properties"/> objects; could be empty, but never <see langword="null"/>.
/// </value>
public List<PropertyDoc> Properties { get; private set; }
}
}
45 changes: 45 additions & 0 deletions src/ServiceStack/WebHost.EndPoints/Metadata/Operation.cs
@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ServiceStack.WebHost.Endpoints.Metadata
{
/// <summary>
/// Encapsulates the metadata of an operation.
/// </summary>
public sealed class Operation
{
/// <summary>
/// <para>Initializes an instance of the <see cref="Operation"/> class.</para>
/// </summary>
internal Operation()
{
}

/// <summary>
/// Gets the name of this operation.
/// </summary>
/// <value>
/// A <see cref="String"/> value providing the name of this operation;
/// never <see langword="null"/>.
/// </value>
public string Name { get; internal set; }

/// <summary>
/// Gets the type of the request DTO associated with this operation.
/// </summary>
/// <value>
/// The <see cref="Type"/> of the request DTO; never <see langword="null"/>.
/// </value>
public Type RequestType { get; internal set; }

/// <summary>
/// Gets the documentation of this operation.
/// </summary>
/// <value>
/// An <see cref="OperationDoc"/> instance; never <see langword="null"/>.
/// </value>
public OperationDoc Doc { get; internal set; }
}
}
160 changes: 160 additions & 0 deletions src/ServiceStack/WebHost.EndPoints/Metadata/OperationDoc.cs
@@ -0,0 +1,160 @@
using System;
using System.Collections.Generic;
using System.Xml.Linq;
using System.IO;
using System.Xml.XPath;
using System.Reflection;

namespace ServiceStack.WebHost.Endpoints.Metadata
{
/// <summary>
/// Represents a documented ServiceStack operation.
/// </summary>
public sealed class OperationDoc: DocumentedCodeElementBase
{
private const string ResponseSuffix = "Response";
private static Dictionary<Type, OperationDoc> _cache = new Dictionary<Type, OperationDoc>();

/// <summary>
/// <para>Gets documentation for the specified request DTO type.</para>
/// </summary>
/// <param name="requestType">
/// The type of the request object for which to locate documentation.
/// </param>
/// <returns>
/// An <see cref="OperationDoc"/> object for the specified request DTO type;
/// never <see langword="null"/>.
/// </returns>
internal static OperationDoc GetForRequestType(Type requestType)
{
lock(_cache)
{
OperationDoc doc;

if (!_cache.TryGetValue(requestType, out doc))
{
doc = new OperationDoc(requestType);
_cache.Add(requestType, doc);
}

return doc;
}
}

private OperationDoc(Type requestType)
{
this.Name = requestType.Name;

var xmlDocument = FindXmlDocumentationFile(requestType);

Request = new DtoDoc
{
Name = requestType.Name,
XmlDocumentation = xmlDocument != null ? ExtractMemberElement(xmlDocument, "T", requestType.FullName) : null,
};

this.XmlDocumentation = Request.XmlDocumentation;

PopulateProperties(Request, requestType, xmlDocument);

Responses = new List<DtoDoc>();

// Support for multiple response types may appear in the future.
// For now, append suffix to find the single response DTO.
var responseType = requestType.Assembly.GetType(requestType.FullName + ResponseSuffix, false);

if (responseType != null)
{
var response = new DtoDoc
{
Name = responseType.Name,
XmlDocumentation =
xmlDocument != null ? ExtractMemberElement(xmlDocument, "T", responseType.FullName) : null,
};

PopulateProperties(response, responseType, xmlDocument);

Responses.Add(response);
}
}

private void PopulateProperties(DtoDoc dto, Type requestType, XDocument xmlDocument)
{
foreach (var propertyInfo in requestType.GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
var propertyDoc = new PropertyDoc
{
Name = propertyInfo.Name,
PropertyType = propertyInfo.PropertyType.Name,
XmlDocumentation =
xmlDocument != null ? ExtractMemberElement(xmlDocument, "P", requestType.FullName + "." + propertyInfo.Name) : null
};

dto.Properties.Add(propertyDoc);
}

dto.Properties.Sort((x, y) => x.Name.CompareTo(y.Name));
}

private XDocument FindXmlDocumentationFile(Type requestType)
{
foreach (var dllLocation in new [] {requestType.Assembly.Location, new Uri(requestType.Assembly.CodeBase).AbsolutePath})
{
if (!File.Exists(dllLocation)) continue;

var xmlLocation = Path.ChangeExtension(dllLocation, "xml");

if (!File.Exists(xmlLocation)) continue;

var doc = XDocument.Load(xmlLocation);

return doc;
}

return null;
}

private XElement ExtractMemberElement(XDocument doc, string prefix, string elementName)
{
var xpath = string.Format("/doc/members/member[@name=\"{0}:{1}\"]", prefix, elementName);

var element = doc.XPathSelectElement(xpath);

if (element != null)
{
// Strip out stuff that is not relevant.
foreach (var child in new List<XElement>(element.Elements()))
{
if (child.Name != "summary"
&& child.Name != "remarks"
&& child.Name != "value"
&& child.Name != "returns")
{
child.Remove();
}
}
}

return element;
}

/// <summary>
/// <para>Gets the documented request DTO.</para>
/// </summary>
/// <value>
/// <para>A <see cref="DtoDoc"/> instance containing documentation
/// for the request DTO; never <see langword="null"/>.</para>
/// </value>
public DtoDoc Request { get; private set; }

/// <summary>
/// <para>Gets the documented response DTOs.</para>
/// </summary>
/// <value>
/// A collection of <see cref="DtoDoc"/> instances containing documentation
/// for all possible response DTOs; <see langword="null"/> if the response
/// DTO cannot be identified.
/// </value>
public IList<DtoDoc> Responses { get; private set; }
}
}
19 changes: 19 additions & 0 deletions src/ServiceStack/WebHost.EndPoints/Metadata/PropertyDoc.cs
@@ -0,0 +1,19 @@
using System;

namespace ServiceStack.WebHost.Endpoints.Metadata
{
/// <summary>
/// Represents a documented object property on a DTO.
/// </summary>
public sealed class PropertyDoc: DocumentedCodeElementBase
{
/// <summary>
/// <para>Gets or sets the type of this property.</para>
/// </summary>
/// <value>
/// <para>A <see cref="String"/> providing the type of this property;
/// never <see langword="null"/>.</para>
/// </value>
public string PropertyType { get; set; }
}
}

0 comments on commit d4026c0

Please sign in to comment.