Making ASP.NET Web API Help Page work on self-hosted services

Even though ASP.NET Web API Help Page is implemented using ASP.NET MVC, which won’t work on self-hosted services, most of the code in the package however can be reused to support the generation of Help Page on self host. I’ve created a sample to illustrate how this can be done. The code can be downloaded at: https://code.msdn.microsoft.com/ASPNET-Web-API-Help-Page-40e1a68e.

The idea is simple, replace MVC components with Web API. So instead of implementing the HelpController as a MVC Controller, implement it as an ApiController. For the rendering of HTML, I used T4 in the sample, but you’re free to use any templating engine you like. Now let’s look at the sample.

Web Api Help Page Self Host Sample

The sample contains two projects: WebApiHelpPageSelfHost.csproj and SampleWebApiSelfHost.csproj. To run the sample, make sure you Enable NuGet Package Restore. (Inside VS, go to Tools -> Options... -> Package Manager -> check "Allow NuGet to download missing packages during build" option)

WebApiHelpPageSelfHost.csproj

This project contains the source code for the Help Page. All the files come from the ASP.NET Web API Help Page package, except for the HelpControllerBase.cs and the files under the Views folder.

The HelpControllerBase is a ApiController as noted previously and it has two actions that will return the help page in “text/html” format.

 [ApiExplorerSettings(IgnoreApi = true)]
 public abstract class HelpControllerBase : ApiController
 {
     public string HelpPageRouteName = "Default";
  
     [HttpGet]
     public virtual HttpResponseMessage Index()
     {
         Index template = new Index
         {
             Model = Configuration.Services.GetApiExplorer().ApiDescriptions,
             ApiLinkFactory = apiName =>
             {
                 string controllerName = Regex.Replace(GetType().Name, "controller", "", RegexOptions.IgnoreCase);
                 return Url.Route(HelpPageRouteName, new { controller = controllerName, apiId = apiName });
             }
         };
         string helpPage = template.TransformText();
         return new HttpResponseMessage
         {
             Content = new StringContent(helpPage, Encoding.UTF8, "text/html")
         };
     }
  
     [HttpGet]
     public virtual HttpResponseMessage Api(string apiId)
     {
         if (!String.IsNullOrEmpty(apiId))
         {
             HelpPageApiModel apiModel = Configuration.GetHelpPageApiModel(apiId);
             if (apiModel != null)
             {
                 string controllerName = Regex.Replace(GetType().Name, "controller", "", RegexOptions.IgnoreCase);
                 Api template = new Api
                 {
                     Model = apiModel,
                     HomePageLink = Url.Link(HelpPageRouteName, new { controller = controllerName })
                 };
                 string helpPage = template.TransformText();
                 return new HttpResponseMessage
                 {
                     Content = new StringContent(helpPage, Encoding.UTF8, "text/html")
                 };
             }
         }
  
         return Request.CreateErrorResponse(HttpStatusCode.NotFound, "API not found.");
     }
 }

The files under the Views folder are T4 templates used to render the HTML. I used partial classes (Index and Api) to pass the data to the templates.

 partial class Index
 {
     public Collection<ApiDescription> Model { get; set; }
  
     public Func<string, string> ApiLinkFactory { get; set; }
 }
  
 partial class Api
 {
     public HelpPageApiModel Model { get; set; }
  
     public string HomePageLink { get; set; }
 }

SampleWebApiSelfHost.csproj

This project contains a self-hosted Web API service with the help page enabled. It references the WebApiHelpPageSelfHost.csproj. You can simply build and run this project to see the self-hosted Help Page in action.

image

Open a browser and go to https://localhost:8080/help to see the following pages.

image

image

Note that the HelpControllerBase from WebApiHelpPageSelfHost.csproj is an abstract class so it won’t be added to your service unless you derive from it.

 // Change the controller name if you want a different URI.
 public class HelpController : HelpControllerBase { }

 

Have fun playing with the sample!

Yao