We're using a FileStreamResult to provide video data to a Silverlight MediaElement based video player:
public ActionResult Preview(Guid id) {
return new FileStreamResult(
Services.AssetStore.GetStream(id, ContentType.Preview),
"application/octet-stream");
}
Unfortunately, the Silverlight video player downloads the entire video file before it starts playing. This behavior is expected as our Preview Action does not support downloading partial content.
(side note: if the file is hosted in an IIS virtual directory we can start playback at any location in the video while it is still downloading. however for security and auditing reasons we can't provide a direct download link. so this is not an option.)
How can we improve the Controller Action to support partial HTTP content?
I assume we first have to inform the client that we support it (adding an "Accept-Ranges:bytes" header to a HEAD request), then we have to evaluate the HTTP "Range" header and stream the requested file range with a response code of 206. Will that work with ASP.NET MVC hosted on IIS6? Is there already some code available?
Also see:
http://en.wikipedia.org/wiki/List_of_HTTP_headers
http://blogs.msdn.com/anilkumargupta/archive/2009/04/29/downloadprogress-downloadprogressoffset-and-bufferprogress-of-the-mediaelement.aspx
http://benramsey.com/archives/206-partial-content-and-range-requests/
There is a project on CodePlex which gives this exact functionality.
http://mediastreamingmvc.codeplex.com/
Take a look. It was created specifically for this scenario where you want to have an action representing a request for a virtual resource and return partial content if so requested without requiring the developer to do much to support it (an Action Filter and choice of Result types.)
You have to implement this by yourself. And yes, this will work on IIS6.
If you can use IIS7 you probably better to leverage on IIS7 extensibility (example).
Then you need to reimplement throttling module :)
The idea is to calculate bitrate of your video stream and then send as much as required to client. So you need (very briefly) to read a block from your stream and send it to client and sleep for a second.
Thread.Sleep(1000) is not really a good idea for handling IIS resources so you need to do stuff in async way. IAsyncResult will be your friend.
There is much room for all kinds of optimisations.
And the last thing... I made it working as plain httphandler, not as MVC ActionResult.
If it's possible in your webiste, I'm recommending to do it as a handler.
Related
I'm working on a collaborative document editing application where clients can open up a document, post edits via a webservice, and subscribe to updates made to the document using SignalR. I'm experimenting with my SignalR setup and can't quite get what I want.
My gut tells me that I should shoot for a setup where each document has an endpoint with a name like "subscribe", so the full path would be "/documents/1/subscribe" for document 1 and "/documents/2/subscribe" for document 2. However, as far as I can tell, SignalR wants me to have a single endpoint, and then manage which clients get updates either by using Groups or by managing the list of subscribers for a document in code myself and send out individual messages.
As a result I have two questions.
Is there a way to do what I want to do what I want to do with SignalR?
Is there a reason what I want to do is totally wrong headed and silly?
Aside from "dedicated", friendly looking URLs I don't really see any value to this vs. just using groups. In fact, the only thing I could see it doing is adding more overhead because of the way the message bus internals of SignalR work with respect to scale.
If you did want to try this, the base thing you'd need to figure out would be registering routes on the fly per document, which, as Phil Haack's RouteMagic has done for MVC, I suppose it might be possible for SignalR route configurations as well.
I am using ASP.NET MVC 4 for a web site. The site manages online events for our group and gives registered users access to online materials, archives of web events and instructional videos. I have built a system for uploading and managing the videos, now I need to build the Controller Actions to send the video files to the web page. We are using VideoJS as the viewer and I am pretty happy with that right now. We need to maintain security on the files so just having the files sit at a location on the web server doesn't seem to work for us.
My main question is what is a good method for returning the files to the viewer? I am used to using ActionResult and JSONResult classes, but they don't quite seem right for video files. The files can be VERY large, sometimes up to a GB or more. I see the MVC FileResult class, the FileStreamResult class and the FileContentResult class. Which one should I use and what other considerations should I be thinking about when I build this?
I appreciate your help.
Doug
You most certainly should not send the entire video as a response to the viewer, as they would be waiting around for a good while for it to download. You need to stream it to them. I imagine you'd need some kind of byte stream being returned from the controller.
There's a reason that places like YouTube offer their videos via flash - because the quality and rate can be controlled easily, and it offers a certain amount of copy protection (though it is not foolproof). I just did a quick Google search, and found this:
http://www.longtailvideo.com/jw-player/download/
Might be useful, but I can't vouch for it personally!
Apparently, Razor offers it's own handling of video files, that you might find useful:
http://www.asp.net/web-pages/tutorials/files,-images,-and-media/10-working-with-video
Also, HTML5 supports video streaming (which I'm sure you knew as VideoJS uses it):
http://www.w3schools.com/html/html5_video.asp
I understand what progressive enhancement is, I'm just fuzzy on some of the details in actually pulling it off. Of course, that could be because I'm looking at it in the wrong way. Let me try to explain my difficulty with a hypothetical:
ASP.NET MVC site. I have a view that has tabbed navigation. Each tab is for a movie category/genre which displays 5-10 links to movies in that category. The movie data is obtained through Netflix's Odata.
My initial thought is to use Ajax to pull and parse the JSON from the proper OData GET requests when each tab is clicked. How would I provide a non-JavaScript version of that? Is it even possible?
For simpler requests where JSON isn't necessary - like, say, having a user log into the system - I see how I could simply set a cookie and dynamically change the page based on it to reflect the change. But what if I need to return and parse JSON? How do I provide an alternative?
The deal with progressive enhancement is that your server side must be fully capable of generating every last bit of HTML that appears in all of your pages. This is obvious, since otherwise (if JS is turned off) there will be no part of your application capable of doing said rendering.
Since the server side must know how to render everything, it doesn't make much sense to generate things (DOM elements/HTML) on the client side from JSON responses the server gives you. Why repeat yourself?
This brings us to the logical conclusion that when doing dynamic updates on the client, you need to get ready-made HTML from the server (since the rendering logic is over there) and insert it into the DOM as appropriate. You are then free to work on the newly inserted elements with jQuery and enhance them all you want.
So -- forget about parsing JSON on the client, otherwise you 're locking yourself out of progressive enhancement. If you want to call a third party, have the server be your intermediary: call the server with all the necessary information for it to call the third party and get ready-made HTML back.
If you do this, then the server can of course provide non-JS versions of everything on your site with no problem. Total non-reliance on JS achieved.
There is no JSON without JS, by definition (JavaScript Object Notation). Without JS you won't make AJAX calls. Your pages will render as is, just like oldschool sites.
If you need to do this progressively, you will have to call the odata service server-side, and provide .net objects to the site in viewdata, or your viewmodel, and have your views/partials render it.
In ASP.Net MVC actions, the httpcontext available via the controller will have a property on this path: this.HttpContext.Request.IsAjaxRequest() and can be used to test whether you want to return a view or just json data, or whatever type of ActionResult you want. This can be an excellent timesaver for building progressive enhancement style sites.
Trying to parse/scrape the course site for memphis. The site is "https://spectrumssb2.memphis.edu/pls/PROD/bwckgens.p_proc_term_date". It appears to be some sort of javascript issue, or dynamic generation of the text. I can see the underlying DOM structure using livehttpdheaders/Firefox, but not when I simply view the underlying source/text of the page..
Thoughts/Comments/Pointers would be appreciated...
Well this modern days the site may be assembled in few steps. First the main structure is pulled in and then, often based on identity of the user additional AJAX calls are executed. Your best bet is to sniff HTTP to see what kind of requests are issued between the site is initially requested and when it's fully built
Since you are using firebug you can get HttpFox add-on which gives you what you need
I'd like to respond to an http request with both a txt file and an html page. This way the client can save the file and see a summary of that file's contents via an html page.
Since the file is generated on the fly, I have to use state management on the server to generate the summary on the second request. I'd like to avoid this and wrap this up in a single response.
What would the custom ActionResult look like?
This was also discussed here on SO.
i answered it like this:
Nope, multipart attachments for
download (like as in email) aren't
supported for security reasons. It's
called a "drive-by download."
Note that Gmail handles this by
dynamically zipping up the files. You
should too.
http://forums.asp.net/t/1240811.aspx
I don't believe any modern browser supports multipart/mixed.
You could send XML with reference to an XSLT stylesheet. The browser can do the transformation and display a resulting HTML output.
And the user may simple do "File->Save as ..." to store the XML file.
Why not render the summary as normal HTML View and provide a link under that summary that points to a separate ActionResult that returns binary data...
public ActionResult SendFile(int id)
{
File file = FileRepository.GetFile(id);
byte[] fileData = file.FileData.ToArray();
return File(fileData, file.FileMimeType, file.FileName);
}
I did some search on this topic and to my surprise, this seems people did this already. I found a description here, but it does not provide a public test URI, so I couldn't test browser behaviour on this. It also mentiones the solution to send an archive file to the client. But I assume that's not what you're looking for, right?
Here is another article showing an example with multipart responses. Sadly, the demo URI seems not to be working any more.
So the situation is this: HTTP multipart responses can be done. There are client (few) libraries to handle those in application code. Browser behaviour is to be tested (Here's a voice). Using this feature seems experimental and may be recommended only you can control both ends of the communication to eliminate interoperability issues.