I have managed to write something that correctly converts links.
An outline is:
In the Help Controller's constructor create a new Lazy IDictionary mapping between the strings found in the cref (e.g. M:Api.Method.Description(System.String) and the associated ApiDescription
_methodReferences = new Lazy<IDictionary<string, ApiDescription>>(() => {
var dictionary = new Dictionary<string, ApiDescription>();
var apiExplorer = new ApiExplorer(config);
foreach (var apiDescription in apiExplorer.ApiDescriptions)
{
var descriptor = apiDescription.ActionDescriptor as ReflectedHttpActionDescriptor;
if (descriptor != null)
{
var methodName = string.Format(
@"M:{0}.{1}({2})",
descriptor.MethodInfo.DeclaringType.FullName,
descriptor.MethodInfo.Name,
string.Join(@",",descriptor.GetParameters().Select(x => x.ParameterType.FullName))
);
dictionary[methodName] = apiDescription;
}
}
return dictionary;
});
Pass this lazy to the various models that back the pages (you may need to create extra models). I have given them all a base class with the following code:
public abstract class HelpPageModelBase
{
private static Regex _seeRegex = new Regex("<see cref=\"([^\"]+)\" />");
private readonly Lazy<IDictionary<string, ApiDescription>> _methodReferences;
protected HelpPageModelBase(Lazy<IDictionary<string, ApiDescription>> methodReferences)
{
_methodReferences = methodReferences;
}
protected HelpPageModelBase(HelpPageModelBase parent)
{
_methodReferences = parent._methodReferences;
}
public string ParseDoc(string documentation, UrlHelper url)
{
if (documentation == null)
{
return null;
}
return _seeRegex.Replace(documentation,
match => {
if (_methodReferences.Value.ContainsKey(match.Groups[1].Value))
{
var descriptor = _methodReferences.Value[match.Groups[1].Value];
return string.Format(@"<a href='{0}'>{1} {2}</a>",
url.Action("Api",
"Help",
new {
apiId = descriptor.GetFriendlyId()
}),
descriptor.HttpMethod.Method,
descriptor.RelativePath
);
}
return "";
});
}
}
Anywhere in the views that had api.Documentation.Trim()
- or Html.Raw(api.Documentation)
if you have already followed Web Api Help Page- don't escape html in xml documentation - you now wrap so it becomes
@Html.Raw(Model.ParseDoc(api.Documentation, Url))
You will find that to do this you need to make the various ModelDescriptions inherit from HelpPageModelBase - and pass the parent API models through to them (or the Lazy if easier) but it does work in the end.
I'm not especially happy with this solution; you might find it easier to have some form of static ParseDoc method that uses the default Http Configuration to generate the Lazy (but because of other extensions I've made that doesn't work for my case). If you see better ways of doing it, please share! Hopefully it gives you a starting point.