3

Let's say you have an ASP.NET MVC 4 Web API project. One of your resources, when you call it by URL, waits while it gets performance monitoring data for a specified amount of time and then returns it all in JSON form once it has completed. However, between entering the URL and when the process has completed, is there a way to return data dynamically, ie. at each second when performance data is retrieved and display it in the browser.

Here's the issue: Calling an API resource via URL is static as far as I know and as far as anyone seems to know. Meaning, the JSON won't appear until the resource has retrieved all of its information, which is not what I want. I want to be able to constantly update the JSON in the browser WHILE the API resource is retrieving data.

Since I'm working in a repository class and a controller class, Javascript is not an option. I've tried using SignalR, but apparently that does not work in this scenario, especially since I'm not able to use Javascript.

Is there any possible way to get real-time data with a URL call to the API?

Case in point: Google Maps. The only way you can call the Google Maps API via URL is if you want a "static" map, that displays a single image of a specific location. No interaction of any kind. If you want a dynamic, "real time" map, you need to build a web application and consume the API resource in your application with Javascript in a view page. There is no way to call it via URL.

j0k
  • 22,600
  • 28
  • 79
  • 90
praetor
  • 3,195
  • 2
  • 23
  • 21

3 Answers3

1

I think what you're asking for is a sort of streaming mechanism over HTTP. Of course doing that would require sending a response of unknown content length.

This question deals with that sort of chunked transfer encoding which is probably part of the solution. Not knowing what is on the client side, I can't say how it would deal with the JSON you want to push through.

Great question.

Community
  • 1
  • 1
pilotcam
  • 1,749
  • 14
  • 22
1

You can certainly start streaming the response back to the browser as soon as you want. It's normally buffered, but it doesn't have to be. I've used this trick in the past. In fact SignalR does something similar in some operational modes, although I should add (now I've re-read your question) that although HTTP supports this, it won't be obvious by default from a Web API controller. I think you'll need to get a little lower into the response handling so you can flush the buffer than simply returning a POCO from your web method if that's what you mean.

Essentially, you'll be wanting to write and flush the buffer after you've gathered each piece of information, so I don't think you'll be able to do that with the typical model. I think you'll need a custom message handler http://www.asp.net/web-api/overview/working-with-http/http-message-handlers to get at the payload in order to do that.

I'm curious though, you say you want to send back JSON but you're not allowed JavaScript?

cirrus
  • 5,624
  • 8
  • 44
  • 62
  • When you call an API resource via URL in the browser, at least in ASP.NET MVC Web API, you are only working through a model class and a controller. First, according to the routing you have, the coordinating method in the model is called, which is then called in the API controller, which returns JSON or XML in the browser (depending on what you have specified). As a result, there is no contact with Views, and thus, no possible association with client-side scripting (JS) since all of this is done server-side. – praetor Sep 02 '12 at 22:39
  • So you're hitting the API resource directly with the browser? Why don't you create an HTML page "view" that loads the API resource with Ajax. Then you can render it in the browser any way you like, with JavaScript as necessary? – cirrus Sep 02 '12 at 22:51
  • Certainly. That's the next (and easier) phase. :) Just saw your edit by the way. So by sending an HttpResponseMessage, the client (the browser in this case) can receive it and display it? – praetor Sep 02 '12 at 23:12
  • Well you get direct access to the response stream, but I'm not sure how that will help you. I think you need to be even deeper into the pipeline. If it were me, I'd ditch Web API for this method and just build a simple IHttpHandler instead. Then you'll have access to the raw message AND be able to control the buffering without having to navigate all the Web API plumbing you probably don't need. – cirrus Sep 03 '12 at 00:21
  • This plumbing is brutal, but I just need to find out one thing: how to send the created HttpResponseMessage to the client (browser). Once I can do that, I'm golden. My repository method has a yield return, so it sends a value to the controller every time a value is retrieved (each second). How can I send the response to the browser right then and there, rather than "returning" it from the controller once all the data has been retrieved? – praetor Sep 03 '12 at 00:44
  • In other words, how can I flush the HttpRequestMessage and override the controller action return when everything is retrieved? But on the subject of the IHttpHandler, how can it ignore the Repository --> Controller --> JSON in browser pipelining? – praetor Sep 03 '12 at 01:19
1

You can put together an old-school ASP.Net IHttpHandler implementation regardless of MVC controllers and routing pipeleline. http://support.microsoft.com/kb/308001. You would then have full acesss to the response stream and you could buffer or not as you see fit. You've got to consider though whether you want to tie up worker thread for that long and if you're planning on streaming more or less continuously then you definately want to use IAsyncHttpHandler while you await further responses from your repo.

Having said that, Web API supports Async too but it's a little more sophisticated. If you plan on sending back data as-and-when, then I'd strongly recommend you take another look at SignalR which does all this out of the box if you are planning on having some JavaScript client side eventually. It's much, much easier.

If you really want to write Async stuff in Web API though, here's a couple of resources that may help you;

http://blogs.msdn.com/b/henrikn/archive/2012/02/24/async-actions-in-asp-net-web-api.aspx

And this one looks like exactly what you need; http://blogs.msdn.com/b/henrikn/archive/2012/04/23/using-cookies-with-asp-net-web-api.aspx

In order to use that PushStreamContent() class in the example though, you'll not find that in your System.Net.Http.dll, you'll need to go get that from the Web API stack nightly builds at http://aspnetwebstack.codeplex.com/SourceControl/list/changesets

YMMV - good luck!

cirrus
  • 5,624
  • 8
  • 44
  • 62
  • Thanks a ton. PushStreamContent() is in System.Net.Http, though. It's just that it has a different constructor than the one in the example in the 2nd link. So what namespace in the nightly build (already got it) has it then? Because apparently, it's not overriding the System.Net.Http one. – praetor Sep 03 '12 at 21:54
  • Nevermind, apparently that tutorial is a bit misconstrued. It's passing an incorrect parameter to the PushStreamContent constructor. – praetor Sep 04 '12 at 00:17