Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API Help Page can't process Generic Type Controller

I have a question about ASP.NET Web API HelpPages.

Usually HelpPages can generate the WebAPI by XMLDocumentation Sample Code:

public class ValueControllerBase : ApiController
{
    /// <summary>
    /// Base Do
    /// </summary>
    public IEnumerable<string> Do()
    {
       return new string[] { "value1", "value2" };
    }
}

public class ValuesController : ValueControllerBase
{
    /// <summary>
    /// Testing API
    /// </summary>
    public string Get(int id)
    {
        return "value";
    }
}

this can generate successfully, like this:

API
GET api/Values/Get/{id}

Description
Testing API

API
POST api/Values/Do

Description
Base Do

but if I use a generic base controller, it will not generate the API Document.

Sample:

public class ValueControllerBase<T> : ApiController
{
    /// <summary>
    /// Base Do
    /// </summary>
    public IEnumerable<string> Do()
    {
        return new string[] { "value1", "value2" };
    }
}

public class ValuesController<String> : ValueControllerBase
{
    /// <summary>
    /// Testing API
    /// </summary>
    public string Get(int id)
    {
        return "value";
    }
}

If I use the code at the second section, HelpPages can generate the API document, but doesn't generate the API annotation. The difference between my two examples is just second section code use a generic type.

API
GET api/Values/Get/{id}  

Description
Testing API

API
POST api/Values/Do

Description
null

In the method Do(), the annotation doesn't display compared with the first

Is there any solution to fix these problems?

like image 876
user3764380 Avatar asked Jun 22 '14 09:06

user3764380


1 Answers

I was able to solve this by adjusting some code in the XmlDocumentationProvider.

The original implemention of XmlDocumentationProvider.GetTypeName(Type) is the following:

private static string GetTypeName(Type type)
{
    string name = type.FullName;
    if (type.IsGenericType)
    {
        // Format the generic type name to something like: Generic{System.Int32,System.String}
        Type genericType = type.GetGenericTypeDefinition();
        Type[] genericArguments = type.GetGenericArguments();
        string genericTypeName = genericType.FullName;

        // Trim the generic parameter counts from the name
        genericTypeName = genericTypeName.Substring(0, genericTypeName.IndexOf('`'));
        string[] argumentTypeNames = genericArguments.Select(t => GetTypeName(t)).ToArray();
        name = String.Format(CultureInfo.InvariantCulture, "{0}{{{1}}}", genericTypeName, String.Join(",", argumentTypeNames));
    }
    if (type.IsNested)
    {
        // Changing the nested type name from OuterType+InnerType to OuterType.InnerType to match the XML documentation syntax.
        name = name.Replace("+", ".");
    }

    return name;
}

I don't know why, but they attempt to create the type name for the xml lookup to include the actual generic attributes, rather than the generic type name itself (for example, they create Nullable{bool} rather than Nullable`1). Only the generic name itself is defined in the xml file.

A simple change to the code gets it to name/reference the documentation for the generic class correctly:

....
if (type.IsGenericType)
{
    Type genericType = type.GetGenericTypeDefinition();
    name = genericType.FullName;
}
....

After making that change, the annotations began to display correctly for generics types, and for me, this didn't break anything else either.

like image 165
Nathan A Avatar answered Nov 19 '22 10:11

Nathan A