Update: the doubled namespace issue has been fixed. Future readers may need to adjust the code below. Specifically, you might need to change "${namespace}${namespace}${class}"
to "${namespace}${class}"
. Don't say I didn't warn you!
The problem arises because of two bugs related to how XML documentation is generated for F# record types:
"When the F# compiler generates the documentation file, it actually documents the internal field instead of the public property of the record member."—Axel Habermaier
The namespace of a record member is doubled in the generated XML.
Barring an update to Visual Studio 2013 (or perhaps just the F# compiler), the best fix for this would probably be a post-build action that cleans up the generated XML. For now, I have a temporary fix that involves changing the method that gets the documentation for members.In Areas/HelpPage/XmlDocumentationProvider
, find the method with the signature:
public string GetDocumentation(MemberInfo member)
…and replace the definition with:
public string GetDocumentation(MemberInfo member)
{
string selectExpression;
bool isRecord = FSharpType.IsRecord(member.DeclaringType, FSharpOption<BindingFlags>.None);
if (isRecord)
{
// Workaround for a bug in VS 2013.1: duplicated namespace in documentation for record types.
Regex matchTypeName = new Regex(@"(?<namespace>(?:[_\p{L}\p{Nl}]+\.)*)(?<class>[_\p{L}\p{Nl}]+)$");
string classExpression = matchTypeName.Replace(GetTypeName(member.DeclaringType), "${namespace}${namespace}${class}");
string memberExpression = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", classExpression, member.Name);
selectExpression = String.Format(CultureInfo.InvariantCulture, FieldExpression, memberExpression);
}
else
{
string expression = member.MemberType == MemberTypes.Field ? FieldExpression : PropertyExpression;
string memberName = String.Format(CultureInfo.InvariantCulture, "{0}.{1}", GetTypeName(member.DeclaringType), member.Name);
selectExpression = String.Format(CultureInfo.InvariantCulture, expression, memberName);
}
XPathNavigator propertyNode = _documentNavigator.SelectSingleNode(selectExpression);
return GetTagValue(propertyNode, "summary");
}
This is a very temporary fix! It will be overwritten if you update the Web API Help Pages package, and will break things if the aforementioned bugs are fixed. I'd really appreciate any help finding a better solution.