Introducing the ASP.NET Web API Help Page (Preview)


Today, following the announcement of the official release for ASP.NET Web API , we also released a preview for the ASP.NET Web API Help Page, which is available as a NuGet package. This package automatically generates help page content for Web APIs on your site. Visitors to your help page can use this content to learn how to call your web APIs. Everything generated by the help page is fully customizable using ASP.NET MVC and Razor.

Here is a quick intro video to get you started.

 

In the next few weeks I’m planning to publish a series of blog posts that will cover the following help page scenarios:

Part 1: Basic Help Page customizations

Changing the help page URI

Providing API documentations

Customizing the view

Part 2: Providing custom samples on the Help Page

Setting custom sample objects

Setting the samples when the action returns an HttpResponseMessage

Part 3: Advanced Help Page customizations

Adding additional information to the HelpPageApiModel

Creating new sample display templates

Give it a try and play with the help page preview package. We would love to hear your comments and feedbacks.

Thanks,

Yao

Comments (54)

  1. fedak says:

    What is needed to get this to work with a WebApi service hosted via HttpSelfHostServer?

  2. Jonas says:

    Cool, does it work with custom routes aswell?

  3. Yao - MSFT says:

    @fedak

    Basically you'll need to generate the HTML without using MVC. I'm going to explain that on a different blog post in the next couple days.

    @Jonas

    Yup, it should work with custom routes.

  4. Dervanil Junior says:

    Great tool! It's open souce? Because i would to fork it and port to use Twitter Bootstrap.

    Thanks!

  5. Yao - MSFT says:

    @Dervanil Junior

    Yes, it's available on CodePlex now: aspnetwebstack.codeplex.com/…/897bf750a622

  6. Nick says:

    Hi Yao,

    I installed the ASP.NET Web API Help Page, and noticed that after doing so my Route object no longer has any DataTokens, including the namespaces.

               Route r;

               r = routes.MapHttpRoute(

                   name: "HelloWorld v1.0",

                   routeTemplate: "helloworld/v1.0/{controller}/{id}",

                   defaults: new { id = RouteParameter.Optional }

               );

               r.DataTokens["Namespaces"] = new string[] { typeof(API.Controllers.HelloWorld.v1_0.GetStartedController).Namespace };

    The above code use to work but now I'm getting a NullReferenceException.  This is the typical solution most developers are using right now to define namespaces for the API routes.

    Nick

  7. Yao - MSFT says:

    @Nick

    The Help Page should not have any effect on Web API routes. By any chance, were you using earlier version of Web API and got upgraded when installing the Help Page?

  8. Fred says:

    are there plans to create something like WADL with the help pages api?

  9. Grahame Horner says:

    Is there any attribute that can be used to document the data annontations which are placed on the parameters of an action?

  10. Magnus says:

    Hi

    I return a HttpResponseMessage in my function. The help page doesn't seem to handle that. I don't get any detailed response information or examples generated. Is there something I can do about this or is it a known issue?

    public HttpResponseMessage Get(int id)

           {

               var p = new Product{ Id = 1, Name = "Test"};

               return Request.CreateResponse(HttpStatusCode.OK, p);

           }

    -Magnus

  11. André Bires says:

    It doesn't works with AttributeRouting because of this:

    github.com/…/86

  12. Yao - MSFT says:

    @Fred, currently we don't have any plan to generate WADL using the help page API. You can consider using ApiExplorer to create WADL-like metadata.

    @Grahame Horner, there isn't any built-in attribute but you should be able to define your own attribute and access it through ApiDescription.ActionDescriptor.GetCustomAttributes or ApiParameterDescription.ParameterDescriptor.GetCustomAttributes. Note that ApiDescriptions are returned by ApiExplorer.

    @Magnus, yes, you can use the provided extension method "SetActualResponseType" to hint what's being return in the HttpResponseMessage. E.g. config.SetActualResponseType(typeof(Product), "YourController", "Get", "id");

    *config is an instance of HttpConfiguration

  13. Mattias says:

    Thank you, very nice!

    When I click in to se the Response Information I only gets this kind of messages for all formats, the application/json, text/json, application/xml and text/xml.. ? Do you know what to do..?

    An exception has occurred while using the formatter 'JsonMediaTypeFormatter' to generate sample for media type 'application/json'. Exception message: Ett eller flera fel har uppstått.

    An exception has occurred while using the formatter 'JsonMediaTypeFormatter' to generate sample for media type 'text/json'. Exception message: Ett eller flera fel har uppstått.

    An exception has occurred while using the formatter 'XmlMediaTypeFormatter' to generate sample for media type 'application/xml'. Exception message: Ett eller flera fel har uppstått.

    An exception has occurred while using the formatter 'XmlMediaTypeFormatter' to generate sample for media type 'text/xml'. Exception message: Ett eller flera fel har uppstått.

    Thank you

    /Mattias

  14. Hi Yao,

    Thanks very much for this, setting up your project was fairly straightforward once I updated my solution to use RTW packages.

    I've got a question regarding the comments on methods returning HttpResponseMessage though.

    Setting up the custom sample data was easy enough with

    config.SetActualResponseType(typeof(MyCustomType), "MyController", "Get");

    However, the XML comments decorating the method are not getting picked up for the standard "description".

    Does this require some additional configuration as well?

    Thanks again,

    Jaume

  15. Hi Yao,

    Please disregard my comment above, the descriptions are getting picked up just fine.

    My issues was that I had a typo in my ///summary clauses, which was ultimately creating malformed XML.

    Thanks,

    Jaume

  16. Hi Yao,

    This looks like a great start. Some suggestions (sorry if there are quite a few but I would love to see your work become part of the product and i wasn't sure where else to submit ideas):

    1) If an action has an enum parameter, you could list the options and use the XML comment on each enum value to describe the option.

    2) The parameters table could have a "Default" column to indicate what the default value is for any parameter that has a default

    3) Is it possible to generate and create a link to an XSD for the request/response XML format

    4) It might be nice to either allow for multiple manually created samples with some descriptive text or allow for formatting within the sample string.

    5) a client side test harness built in to the help page would allow the user to try the API out directly

    6) To my mind, ideally this documentation would be "inline" with the actual API (i.e. from your example /api/users would be the API and /api/users?format=help would give the help page for part of the API)… the help page could then also contain the representation from the current resource.

    7) Could your samples include comments derived from the Xml Documentation for the objects being submitted / retrieved? So for your example, the sample might be:

    <User>

      <!– The name of the user –>

      <Name>sample string 1</Name>

      …

    </User>

    8) If not required, can the sample XML not contain xmlns:xsi="http://www.w3.org/…/XMLSchema-instance&quot; xmlns:xsd="http://www.w3.org/…/XMLSchema&quot;. To do this, you neeed to call the XmlSerializer with a blank namespace:

       var xmlSerializerNamespaces = new XmlSerializerNamespaces();

       xmlSerializerNamespaces.Add(String.Empty, defaultNamespace);

       xmlSerializer.Serialize(xmlWriter, objectToBeSerialised, xmlSerializerNamespaces);

    where defaultNamespace should be either string.Empty or the value of the XmlRootAttribute's Namespace property if the root object has this attribute.

    9) In the case of the actions having an Authorize attribute, could the help check whether the current user would be able to use the action before documenting it?

    Piers

  17. Couple of Documentattion tags are not working.

    returns

    example

    Also how do I show the link to sample url which user click to run a sample.?

  18. How do I leverage using this Help doc to display information for Return data class?

  19. Sancho Ore says:

    I was wondering when you are going to put the next part of this series?

  20. Chandra R says:

    Is there any sample where I can create my own implementation for IApiExplorer? Since I need to support versioning in my uri (eg: api/v1/products/123). Currently the GetApiExplorer() method doesn't return any api descriptions for the URI that I previously mentioned.

    I would appreciate if you provide me with any directions to solve the above mentioned problem.

  21. Maciek says:

    I've run into a problem with API eplorer,

    All works fine while it enumerates over my controllers, however :

    When evaulating a  Controller : ApiController – all methods show up,

    When evaluating a Controller : MyCustomController<T> – only GET methods show up

    (where T : IUnitOfWork) – I'm using Mindscape Lightspeed as my ORM.

  22. Yao - MSFT says:

    @Mattias

    Sorry for the late reply, for now can you change the following in HelpPageSampleGenerator.cs to display the full exception message?

                   sample = new InvalidSample(String.Format(

                       CultureInfo.CurrentCulture,

                       "An exception has occurred while using the formatter '{0}' to generate sample for media type '{1}'. Exception message: {2}",

                       formatter.GetType().Name,

                       mediaType.MediaType,

                       e.Message <== change this to e.ToString()));

    @Piers Lawson

    Thanks for the suggestions. Feel free to submit your ideas on aspnetwebstack.codeplex.com/…/basic.

    @KingAnil2010

    Currently it doesn't support returns tag but we'll consider adding the support.

    Sorry I didn't undertand your question about "link to sample url", can you elaborate?

    What kind of information are you looking to display on the return data class? Can you give me an example?

    @Sancho Ore

    Sorry I was away on vacation but will post the series as soon as possible.

    @Chandra R

    You can register your CustomApiExplorer through config (HttpConfiguration):

                   config.Services.Replace(typeof(IApiExplorer), new CustomApiExplorer());

    you can look at the default ApiExplorer implementation for reference: aspnetwebstack.codeplex.com/…/10f94d855cc9

    @Maciek

    I couldn't repro what you described with the following controllers. Can you share your controllers? (feel free to upload a repro on SkyDrive or something)

       public class CustomController<T> : ApiController

       {

           public int Get(T a)

           {

               return 0;

           }

           public void Post(T a)

           {

           }

       }

       public class CustomIntController : CustomController<int>

       {

           public int Post()

           {

               return 0;

           }

       }

  23. Great article, Waiting in part 2 particularly on 'Setting the samples when the action returns an HttpResponseMessage' which i use a lot.

  24. Found out how to 'Setting the samples when the action returns an HttpResponseMessage'

    Use the following in Helpage.config/Register Method

    //// The sample will be generated as if the controller named "Values" and action named "Post" were returning YourType.

    config.SetActualResponseType(typeof(YourType), "Values", "Post");

  25. Rahul says:

    I am taking an object as input parameter such as

    public string GetData([FromUri]Product product)

    {

           //…..

    }

    But while generating the help page i want to include the properties of product class. Is it possible??

  26. Yao - MSFT says:

    @Rahul

    By default, it doesn't display the properties. However you can add some extra logic to the "GenerateApiModel" method in HelpPageConfigurationExtensions.cs to handle this case. Here is rough code snippet just to give you an idea: gist.github.com/c231426e036421d4dc78

  27. Broersa says:

    Does someone know it works on Azure? Deployed it to Azure and got a yellow screen of death. Haven't testedany further, was late friday afternoon, but I think it is a right problem.

  28. Yao - MSFT says:

    @Broersa

    It does work on Azure. I have a sample deployed here: webapisample.azurewebsites.net/Help

    In case you are using XML documentation file, make sure you include it in the project and enable "Copy to Output Directory".

    Hope this helps,

    Yao

  29. Broersa says:

    @Yao

    It was indeed the xml file that didn't get copied. Works like a charm now.

  30. Daniel Hilgarth says:

    Yao, thanks for this package. It works great for most use cases!

    However, it has problems with controllers with generic types.

    1. In XmlDocumentationProvider.GetMemberName you use method.DeclaringType.FullName. This produces a string that contains the concrete types of the generic type parameters. A combination of method.DeclaringType.Namespace and method.DeclaringType.Name produces the correct class name.

    2. Methods on those generic types that don't have generic parameters themselves but use a generic parameter from the class as parameter type will result in a member name in the XML doc file that doesn't contain a parameter type but simply a reference to the generic type argument of the class, e.g. `0. I haven't found a fix for this yet.

    Please also see stackoverflow.com/…/how-to-get-methodinfo-for-open-generic-type-from-methodinfo-of-closed-type

  31. Thomas C says:

    Hi, i am having trouble getting it to work.

    I have followed the video but are not getting the info for the controllers.

    I get the "empty" help page, where only the hardcoded stuff is shown.

    It's like it can´t se my Web Api controllers.

    Any thoughts on how I can fix this?

  32. Daniel Hilgarth says:

    @Thomas C:

    Did you uncomment the line containing XmlDocumentationProvider in the help page config file?

  33. Thomas C says:

    @Daniel Hilgarth:

    Yup, it is as if none of my controllers is getting noticed by help page.

    All the stuff in the video i have done.

    Got it working on a test project that i set up in same way as the real one, and that one works.

    I´m trying to debug at the moment, but i am getting nowhere, unfortunately.

  34. Daniel Hilgarth says:

    @Thomas C:

    Set a break point in the XmlDocumentationProvider to verify if it gets hit. If not, there is still something wrong with your configuration.  

    I still think that is your problem, because if the XmlDocumentationProvider doesn't find your XML file, you will get an exception when trying to view the help page. And when it does find the find XML file but doesn't find documentation for one particular method, it would still display your controller and its actions.

  35. Thomas C says:

    @Daniel Hilgarth:

    It hits and parses without any problem.

    But i still get no output in the view.

  36. Yao - MSFT says:

    @Daniel Hilgarth

    Thanks for letting me know about the issue, Daniel. Please feel free to report it on our codeplex site ( aspnetwebstack.codeplex.com/…/basic) This will help us keep track of the issue so that we can address it in a future iteration.

    @Thomas C

    Thomas, it would be great if you can share a simple repro so that more folks can help out. From your description, it seems like ApiExplorer is not returning any ApiDescriptions for some reason. Put a breakpoint in the HelpController.Index and see if that's actually the case.

  37. Thomas C says:

    @Yao:

    I put the breakpoint and you are correct, no ApiDescriptions are returned.

    I am working on a stripped version of the code, do you have anywhere you want me to send it?

  38. Thomas C says:

    @Yao:

    Here is a stripped version that has the same problem.

    dl.dropbox.com/…/AutoKPI-StrippedVersion.zip

    I will leave it up for a couple of days.

  39. Yao - MSFT says:

    @Thomas C

    I think there's a small issue with the route parameters. I see you have the route "api/{controller}/{action}/{id}/{folderID}/{projectID}/{queryDate}" where all parameters except {controller} have the RouteParameter.Optional as the default. Eventhough your intention is to have them as optionals the reality is that they are not if they come before the action parameter.

    Take the following action in your "Project" controller for example:

       Get(int folderID)

    In this case, one might think "api/Project/Get/6" would be the URL for it where {folderID}=6. But in reality this translate into {controller}=Project, {action}=Get, {id}=6. The actual URL for the action above is "api/Project/Get/5/6" where {controller}=Project, {action}=Get, {id}=5, {folderID}=6. Therefore can you try changing the action to Get(int id, int folderID) and see if it works?

    Here is another idea if the parameters are not required to be on the URL path – get them as query strings. You can change the route to "api/{controller}/{action}" and the URL for the above action would be "api/Project/Get?folderID=6" instead of "api/Project/Get/5/6". Notice that you don't need to add the extra 5 as {id} anymore.

    Hope this helps,

    Yao

  40. Perhaps this is not best practice, but we are using a controller to do a file upload, where we use: var myFile = HttpContext.Current.Request.Files["myFile"];  and I have no way of indicating that this is a required peice of data to be passed in via a file <input> in the form post. I tried adding a [Frombody] parameter for the file, but couldn't find the correct syntax. Meanwhile if I add a <param name="myFile">The file expected to be uploaded in the request</param> it doesn't show on the help detail page because it's not a real parameter. Perhaps something could be added that would allow me to add a 'Other Requirements' row to the parameters list?

  41. Yao - MSFT says:

    @t_elsmore

    You can try creating a custom attribute to specify the 'Other Requirements' and add it to the parameter list in HelpPageConfigurationExtensions.cs. Here is rough code snippet to give you an idea: gist.github.com/42d5e9c0fa9dd9e3bf30

  42. Thomas C says:

    @Yao

    Thanks for youre suggestions. I have modified them to work with the Api the way I intended and it works like a charm 🙂

    I now have another problem, I don´t get any Response Information generated for the ones where I return a HttpResponseMessage. Is there a way to fix this?

    Thanks again!

  43. Yao - MSFT says:

    @Thomas C

    Glad to hear that it's working for you now 🙂

    Yes. For actions returning HttpResponseMessage please see part 2 of this series:

    blogs.msdn.com/…/asp-net-web-api-help-page-part-2-providing-custom-samples-on-the-help-page.aspx

  44. Colin Bowern says:

    Any thoughts on how this might leverage, merge with Swagger?

    http://swagger.wordnik.com/

  45. francisco says:

    I have a problem. im working with

    routes.MapHttpRoute(

                   name: "ActionApi",

                   routeTemplate: "api/{controller}/{action}/{id}",

                   defaults: new { id = RouteParameter.Optional, action = "" }

               );

    in some call the action are "" because im calling to the root then i got this error

    The route template separator character '/' cannot appear consecutively. It must be separated by either a parameter or a literal value.

    Parameter name: routeTemplate

    i think its because the action "Configuration.Services.GetApiExplorer().ApiDescriptions" cannot build the correct route

    can you give me a choice?????? or can you fix it????????????

  46. Yao - MSFT says:

    @Colin Bowern

    You can checkout the ApiExplorer (blogs.msdn.com/…/asp-net-web-api-introducing-iapiexplorer-apiexplorer.aspx). It's more suitable for that scenario.

    @francisco

    Unfortunately I cannot repro your issue with the route you provided. Can you open an issue on aspnetwebstack.codeplex.com/…/basic and attach a simple repro?

    Thanks,

    Yao

  47. Sam says:

    Is this supposed to work with WebForms?  I created a simple set of API's.  The API's work perfectly fine – returning the right results. BUT I cannot get the Help Page.  

    I have installed "Microsoft.AspNet.WebApi.HelpPage"

  48. Yao - MSFT says:

    Hi Sam,

    Can you try the steps from the following blog post about using help page on web forms?

    blogs.msdn.com/…/enabling-asp-net-web-api-help-pages-for-asp-net-web-forms-applications.aspx.

    Let me know if it worked for you.

    Thanks,

    Yao

  49. Erik says:

    Hi, i have some entitysetcontrollers is it possible to display them in the help page aswell?

  50. Yao - MSFT says:

    Hi Erik,

    Currently the Help Page doesn't support entitysetcontrollers by default because our OData implementation uses different routing mechanism. However, we might consider providing the support in the future.

  51. Colin says:

    Are there any issues with using StructureMap and the WebApi help page?

    I created an empty WebApi project, and added StructureMap.MVC4.

    When I browse to the API link, I get the exception

        Activation error occured while trying to get instance of type HelpController, key ""

    with an inner exception

       StructureMap Exception Code:  202nNo Default Instance defined for PluginFamily     System.Web.Http.HttpRouteCollection, System.Web.Http

    but if I hit continue the page does appear.

  52. Adam says:

    Yao, is there anywhere where I can 'vote' to add support for entitysetcontroller to this?

  53. Re: No default instance found for HttpRouteCollection says:

    In reply to Colin (yes, I know it's old, but still…) – StructureMap by default chooses the greediest constructor. I resolved this by adding the following line to my initialization statement for StructureMap: x.SelectConstructor(() => new HelpController()); This will configure StructureMap to use the default constructor for HelpController.

  54. jon says:

    how to use help pages with MultipartFormDataStreamProvider