Introducing WebApiProxy: Providing JavaScript & C# proxies with Intellisense including documentation for ASP.NET Web API

Thursday, January 16, 2014

WebApiProxy extends your ASP.NET Web API service with a proxy endpoint, providing a ready-to-use JavaScript client as well as metadata, exposing the types used in the service. If you are using the documentation provider from ASP.NET Web API Help Pages, the usage documentation is also included inside the metadata, giving the client-side developer a rich experience with Intellisense.

This release has been updated and includes much more great features. Read more on the update here.
A while ago, I wrote about the concept of using T4 templates, to generate C# client proxies for RESTful Web APIs in ASP.NET; and received good feedback. I’ve received plenty of e-mails requesting more information on the official release date. At that time, there were already some super cool implementations around, like ProxyApi, that provides a JavaScript proxy for ASP.NET Web APIs, but no C# proxy (yet).
The idea of JavaScript proxy generation is inspired by SignalR whereby the code is scanned for controllers and methods. Based on the type information, it compiles a JavaScript proxy that can be referenced from HTML. This got me thinking – why not expose the metadata as well? By doing this, it gives us the opportunity to create a client side generator, like a build task, to generate a proxy based on the metadata for communicating to a ASP.NET Web API service, in any language – like C#.
Currently, we have the following technologies:
I’ve noticed that ASP.NET Web API 2 comes stock standard with an ApiExplorer that retrieves the type information of the service, so I built a proxy provider that installs a message handler, using the ApiExplorer to return the service metadata as the response. Also, if the documentation provider (from ASP.NET Web API 2 Help Pages) is used in your service, the documentation will also appear in the metadata response.

The WebApiProxy Provider

This extension provides a proxy endpoint in your service as /api/proxies that serves a JavaScript client and service metadata. All you need to do is install it from NuGet:
PM> Install-Package WebApiProxy

Note: This package requires the core libraries of ASP.NET Web API (version 5 or higher)
Given a Person API on the server:
Allows you to use it in JavaScript like this:
Simply reference the proxy endpoint provided inside your HTML and you're good to go:
This functionality was adopted from ProxyApi - kudos to Stephen Greatrex :)
Invoke the service on its proxy endpoint with the request header  X-PROXY-TYPE  as "metadata" and the service metadata (including documentation*) will be in the response.

…Then The WebApi C# Proxy Generator was born…

The WebApi C# Proxy Generator is a build task to seamlessly generate a client-side C# Proxy upon project build, for communicating to a ASP.NET Web API service that implements the WebApi Proxy Provider on the server.
PM> Install-Package WebApiProxy.CSharp
Note: This package requires the libraries of ASP.NET Web API Client (version 5 or higher)
The C# proxy code will be generated every time you re-build the project and is based on specific configuration in the WebApiProxy.config file:
Note: The generated code is cached to avoid compilation errors if the service isn't reachable at that time
Now, given a PeopleController on the service-side:
It can be used like this on a client like a Console Application or Windows Phone app:
Note: If the types are not found (or resolved) after build, simply give your project a restart or restart Visual Studio.
It even has nice Intellisense including documentation provided by the documentation provider:

Note: The documentation on the Intellisense will only appear if the service uses the documentation provider. You can use the ASP.NET Web API Help Page package on NuGet
You can follow the project on Github here
Till next time!
@FanieReynders

20 comments

  1. Great article Fanie. Have you considered making a min version of the proxies script?

    ReplyDelete
    Replies
    1. Hi Graham, thanks for the feedback. I haven't really focused too much on the JavaScript side of the proxy, and are aware of a few issues that need to be fixed, but I would most certainly build it in to serve min versions as well. Great suggestion, thanks!

      Delete
    2. I have found a bug which will take you seconds to fix!

      when generating the proxies output you need to prefix the url with a '/' to force the url to come from the route, currently its trying to resolve relatively which will only work when your on the base url.

      Output,..
      /* Proxies */

      $.proxies.customerapi = {
      defaultOptions: {},
      antiForgeryToken: defaultAntiForgeryTokenAccessor,



      getCustomerById: function (customerId) {
      return invoke.call(this, "api/customers/" + customerId, "get",
      {
      customerId: customerId,
      }
      );
      },

      needs to be "/api/customers/"

      Thanks again

      Delete
  2. Hi Graham, can I ask you to please log this issue on my GitHub repository at https://github.com/faniereynders/WebApiProxy/issues so it can be attended to as soon as possible. Thanks again for your great input.

    ReplyDelete
  3. Hey Fanie,

    I am confused. Does the Javascript version solve cross-site-scripting issues? I.e. if my WebAPI service is on a different domain from my Javascript UI, does your solution support this?

    Thanks,

    -Phil

    ReplyDelete
  4. Hi Phil, no this solution is merely for creating a proxy to communicate with your web API service. The current version only supports requests from the same domain but it will support cross domain in the future, given that your web API service allows for CORS

    ReplyDelete
  5. Hi,
    I am trying to use the proxy generator for server side code (C#)

    I create the webapi project and I am running it on port 52892 on the localhost so the endpoint url is: http://localhost:52892/api/.

    When I am building the the proxy generator project I am getting compile time error:

    Error 2 The "ProxyGenerationTask" task failed unexpectedly.
    WebApiProxy.ConnectionException: WebApiProxy: Could not connect to remote server - http://localhost:52892/api/proxies
    at WebApiProxy.Tasks.ProxyGenerationTask.tryReadFromCache()
    at WebApiProxy.Tasks.ProxyGenerationTask.Execute()
    at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
    at Microsoft.Build.BackEnd.TaskBuilder.d__20.MoveNext() riddler.webapi.proxies

    The WebApiProxy.config is:



    Any idea ?

    ReplyDelete
    Replies
    1. Hi, you need to make sure that the server is running. I've found that on VS 2013, IIS Express only runs when the project is actually in debug mode. You can disable this from the project properties, by un-checking the 'Enable edit and continue' on the web section.

      If this is not the case, make sure that your firewall or other proxies are not blocking it.

      Delete
    2. I had the same problem. Running Visual Studio as Administrator seems to have fixed it.

      On another note, I see "WebApiProxySource.cache" being generated in the root of my project, and "WebApiProxySource.cs" is in obj\Debug directory. Is this the expected output?

      Delete
  6. Hello Fanie,

    A kudos to you for an excellent contribution. I see that proxy generation takes into account annotation with ActionName attributes on the web service methods of a controller (and the inclusion of the {action} placeholder in the route template). This is very useful.

    When I tried experimenting using Web API 2.x Attribute Routing, things didn't seem to go as well. Is Attribute Routing supported, or, if not, will it be? If it is supported, is there any guidance on correct usage available?

    ReplyDelete
    Replies
    1. Hi Vito,

      Thank you. Apologies for the late reply.

      Yes AttributeRouting is supported. WebApiProxy uses the built-in standard documentation provider from ASP.NET Web API.

      If you still have issues, please do let me know.

      Delete
  7. Hi Fanie,

    First of all I want to congratulate you for the great Job,

    I am writing to you to just ask for tips you might have about an error I am facing while using this lib, In fact, I am getting a run time error in the ProxyHandler.SendAsync method. I am getting an exception with the message "Collection was modified; enumeration operation may not execute." while returning the response object created by request.CreateResponse(System.Net.HttpStatusCode.OK, metadata);

    Any ideas or tips are welcome!!

    ReplyDelete
    Replies
    1. Hi Saoudi,

      Apologies for the late reply. Could you elaborate on this issue by outlining your controller actions? There was a bug with the metadata generation for specific actions and it was fixed but not released on Nuget yet. I am planning to do another official release soon, in the meanwhile you can pull the latest source and use that if it will help?

      Delete
  8. Hi Fanie,

    Is there a way that I can customize the client classes that get generated. Can I modify the T4 templates if I've installed WebProxyAPi via Nuget? I need all my httpClient classes that are generated to inherit from a base class so that I can implement spme security requirements etc.

    Also, I've cloned your gitHub code but it doesn't appear to be the same version you used to publish the nuget package because it does contain some build errors.

    Thanks,
    Pedro

    ReplyDelete
    Replies
    1. Hi Pedro,

      You are right, the Nuget version is a few releases behind. I left it that way for stability reasons. It is however possible to extend the generated code because the classes are partial and allow for extension. Do let me know if you need any further information, I am happy to help where possible.

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Hi Fanie,
    first off, nice work!

    I'm trying to put this to work, but when I try to access the /api/proxies, I keep getting the following error:
    " No HTTP resource was found that matches the request URI 'http://localhost:19236/api/proxies'. "
    I've checked that the RegisterProxyRoutes (with default routeTemplate) is being called (just at the end of my Register(HttpConfiguration) .

    What am I missing?
    Thanks,
    Cláudio

    ReplyDelete
    Replies
    1. Well... by putting the config.RegisterProxyRoutes(); instruction on the top of the Register(...) method, things got a little bit further.

      Now, when acessing that same url (/api/proxies) I get a javascript file that's interpreting my controllers. But then, the WebApiProxy-Generate-CSharp nugget command cannot finish its job, stating that "Could not connect to remote server
      - http://localhost:19236/api/proxies " -> the same url I'm seing with a get request.

      Other interesting fact: sendind the X-Proxy-Type: metadata on the headers has no effect on the response (always a javascript like file).

      Any ideias?

      thanks!

      Delete
  11. Well.. it turns out that the culprit was the jsonpformatter I had on the Application_Start:
    (GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter(new JsonMediaTypeFormatter())); ) .

    Only after close inspection I was able to pinpoint that. If the jsonpformatter is commented out, then everything goes smoothly. BTW, the error generated y the jsonpformatter was related to the lack of a callback method, when calling the /api/proxies link, with the metadata header.

    ReplyDelete

Community

Popular Posts

Archives