 <p><s>Just found a project called: <strong>ProxyApi</strong> </p> <blockquote> <p>ProxyApi is a library that automatically creates JavaScript proxy objects for your ASP.NET MVC and WebApi Controllers.</p> </blockquote> <p>GitHub: <a href="https://github.com/stevegreatrex/ProxyApi">https://github.com/stevegreatrex/ProxyApi</a></p> <p>Blog: <a href="http://blog.greatrexpectations.com/2012/11/06/proxyapi-automatic-javascript-proxies-for-webapi-and-mvc/">http://blog.greatrexpectations.com/2012/11/06/proxyapi-automatic-javascript-proxies-for-webapi-and-mvc/</a></s></p> <p>ProxyApi generated invalid JavaScript for my solution which contained over a hundred separate WebAPI actions. This is probably because ProxyApi does not cover all WebApi features such as custom ActionName attributes. Moreover the ProxyApi library is a bit on the bulky side to my taste. There has to be a more efficient way to do this...</p> <p>So I decided to take a look at the ASP.NET WebAPI source code and it turns out WebAPI has self-describing functionality built into it. You can use the following code from anywhere in your ASP.NET solution to access WebAPI metadata:</p> <pre><code>var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer(); </code></pre> <p>Based on the output from <code>apiExplorer.ApiDescriptions</code>, I rolled my own metadata provider:</p> <pre><code>public class MetadataController : Controller { public virtual PartialViewResult WebApiDescription() { var apiExplorer = GlobalConfiguration.Configuration.Services.GetApiExplorer(); var apiMethods = apiExplorer.ApiDescriptions.Select(ad =&gt; new ApiMethodModel(ad)).ToList(); return PartialView(apiMethods); } public class ApiMethodModel { public string Method { get; set; } public string Url { get; set; } public string ControllerName { get; set; } public string ActionName { get; set; } public IEnumerable&lt;ApiParameterModel&gt; Parameters { get; set; } public ApiMethodModel(ApiDescription apiDescription) { Method = apiDescription.HttpMethod.Method; Url = apiDescription.RelativePath; ControllerName = apiDescription.ActionDescriptor.ControllerDescriptor.ControllerName; ActionName = apiDescription.ActionDescriptor.ActionName; Parameters = apiDescription.ParameterDescriptions.Select(pd =&gt; new ApiParameterModel(pd)); } } public class ApiParameterModel { public string Name { get; set; } public bool IsUriParameter { get; set; } public ApiParameterModel(ApiParameterDescription apiParameterDescription) { Name = apiParameterDescription.Name; IsUriParameter = apiParameterDescription.Source == ApiParameterSource.FromUri; } } } </code></pre> <p>Use this controller in conjunction with the following view:</p> <pre><code>@model IEnumerable&lt;Awesome.Controllers.MetadataController.ApiMethodModel&gt; &lt;script type="text/javascript"&gt; var awesome = awesome || {}; awesome.api = { metadata: @Html.Raw(Json.Encode(Model)) }; $.each(awesome.api.metadata, function (i, action) { if (!awesome.api[action.ControllerName]) { awesome.api[action.ControllerName] = {}; } awesome.api[action.ControllerName][action.ActionName] = function (parameters) { var url = '/' + action.Url; var data; $.each(action.Parameters, function (j, parameter) { if (parameters[parameter.Name] === undefined) { console.log('Missing parameter: ' + parameter.Name + ' for API: ' + action.ControllerName + '/' + action.ActionName); } else if (parameter.IsUriParameter) { url = url.replace("{" + parameter.Name + "}", parameters[parameter.Name]); } else if (data === undefined) { data = parameters[parameter.Name]; } else { console.log('Detected multiple body-parameters for API: ' + action.ControllerName + '/' + action.ActionName); } }); return $.ajax({ type: action.Method, url: url, data: data, contentType: 'application/json' }); }; }); &lt;/script&gt; </code></pre> <p>The controller will use the <code>ApiExplorer</code> to generate metadata about all available WebAPI actions. The view will render this data as JSON and then execute some JavaScript to transform this data to actual executable JavaScript functions. </p> <p>To use this little bit of magic, insert the following line in the head of your Layout page <strong>after</strong> your jQuery reference.</p> <pre><code>@Html.Action(MVC.Metadata.WebApiDescription()) </code></pre> <p>From now on, you can make your WebAPI calls look like this:</p> <pre><code>// GET: /Api/Notes?id={id} awesome.api.Notes.Get({ id: id }).done(function () { // .. do something cool }); // POST: /Api/Notes awesome.api.Notes.Post({ form: formData }).done(function () { // .. do something cool }); </code></pre> <p>This simple proxy will automatically distinguish query string parameters from request body parameters. Missing parameters or multiple body-parameters will generate an error to prevent typo's or other common WebAPI development errors.</p>