How to stream video content in asp.net? - c#

I have the following code which downloads video content:
WebRequest wreq = (HttpWebRequest)WebRequest.Create(url);
using (HttpWebResponse wresp = (HttpWebResponse)wreq.GetResponse())
using (Stream mystream = wresp.GetResponseStream())
{
using (BinaryReader reader = new BinaryReader(mystream))
{
int length = Convert.ToInt32(wresp.ContentLength);
byte[] buffer = new byte[length];
buffer = reader.ReadBytes(length);
Response.Clear();
Response.Buffer = false;
Response.ContentType = "video/mp4";
//Response.BinaryWrite(buffer);
Response.OutputStream.Write(buffer, 0, buffer.Length);
Response.End();
}
}
But the problem is that the whole file downloads before being played. How can I make it stream and play as it's still downloading? Or is this up to the client/receiver application to manage?

You're reading the entire file into a single buffer, then sending the entire byte array at once.
You should read into a smaller buffer in a while loop.
For example:
byte[] buffer = new byte[4096];
while(true) {
int bytesRead = myStream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0) break;
Response.OutputStream.Write(buffer, 0, bytesRead);
}

This is more efficient for you especially if you need to stream a video from a file on your server or even this file is hosted at another server
File On your server:
context.Response.BinaryWrite(File.ReadAllBytes(HTTPContext.Current.Server.MapPath(_video.Location)));
File on external server:
var wc = new WebClient();
context.Response.BinaryWrite(wc.DownloadData(new Uri("http://mysite/video.mp4")));

Have you looked at Smooth Streaming?
Look at sample code here

Related

pdf corrupted while downloading from URL VB.net/C#

Problem still there while i tried below three methods.
Using Window API "URLDownloadToFile"
WebClient Method
webclient.DownloadFile(url,dest) ''With/Without credientials
HTTP WebRequest Method:
public static void Download(String strURLFileandPath, String strFileSaveFileandPath)
{
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(strURLFileandPath);
HttpWebResponse ws = (HttpWebResponse)wr.GetResponse();
Stream str = ws.GetResponseStream();
byte[] inBuf = new byte[100000];
int bytesToRead = (int) inBuf.Length;
int bytesRead = 0;
while (bytesToRead > 0)
{
int n = str.Read(inBuf, bytesRead,bytesToRead);
if (n==0)
break;
bytesRead += n;
bytesToRead -= n;
}
FileStream fstr = new FileStream(strFileSaveFileandPath, FileMode.OpenOrCreate, FileAccess.Write);
fstr.Write(inBuf, 0, bytesRead);
str.Close();
fstr.Close();
}
Still i m facing the problem, file i am able to download at my local system, but when i open that it show Corrupt pdf.
!!!!I just want to download the pdf from URL and thats my query in VB.net/C# not using response method of ASP.net.
Please help if someone face this real problem.
Thanks in Advance!!!
Your code only writes 100000 bytes of the downloaded PDF and hence every PDF that is bigger than 100000 bytes gets corrupted.
To read more bytes you have to write the contents of every buffer to the FileStream.
The following should do it:
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create(strURLFileandPath);
using (HttpWebResponse ws = (HttpWebResponse)wr.GetResponse())
using (Stream str = ws.GetResponseStream())
using (FileStream fstr = new FileStream(strFileSaveFileandPath, FileMode.OpenOrCreate, FileAccess.Write))
{
byte[] inBuf = new byte[100000];
int bytesRead = 0;
while ((bytesRead = str.Read(inBuf, 0, inBuf.Length)) > 0)
fstr.Write(inBuf, 0, bytesRead);
}
(It's good coding practice to use a using on every IDisposable instead of manually closing the streams.)

Image upload to FTP issue

I am using the following code to upload a image to my FTP server but I have a problem. If I use the code to check the dimension (height and width) of the image before upload then there is .png file created in the FTP server but it's empty (or invalid format) and if I remove the code to check the dimension, then the image is uploaded correctly. Does any have any idea on this?
public ActionResult UploadFile(int type, HttpPostedFileBase imagefile)
{
//check image height and width
using (System.Drawing.Image image = System.Drawing.Image.FromStream(imagefile.InputStream, true, true))
{
if (image.Width > 160 || image.Height > 160)
{
//do something here
}
}//end check image height and width
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftpPath" + "/" + imagefile.FileName);
request.Credentials = new NetworkCredential("ftpUserName", "ftpPassword");
request.Method = WebRequestMethods.Ftp.UploadFile;
var sourceStream = imagefile.InputStream;
Stream requestStream = request.GetRequestStream();
request.ContentLength = sourceStream.Length;
int BUFFER_SIZE = imagefile.ContentLength;
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = sourceStream.Read(buffer, 0, BUFFER_SIZE);
do
{
requestStream.Write(buffer, 0, bytesRead);
bytesRead = sourceStream.Read(buffer, 0, BUFFER_SIZE);
} while (bytesRead > 0);
sourceStream.Close();
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
}
As mentioned, you are reading up all the stream when you load it into your Image. However, I don't think you can reset the position (i.e. "Seek") on a NetworkStream (your InputStream). Once you read it, it is gone.
One thing you can do though is to create a MemoryStream and use Stream.CopyTo to copy the contents into that. Then, you can do anything you like with it, including resetting the position to 0 to "read it a second time".
//example of resetting a stream named "s"
s.Position = 0;
Thanks guys for the reply they were very helpful but I fixed this issue by making slight changes on my code as below, I checked the image dimension after reading the input Stream. May be someone find this helpful.
public string ftpUpload(HttpPostedFileBase imagefile, string filename)
{
var sourceStream = imagefile.InputStream;
int BUFFER_SIZE = imagefile.ContentLength;
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = sourceStream.Read(buffer, 0, BUFFER_SIZE);
if (!CheckLogoDimension(sourceStream))
{
sourceStream.Close();
return "error";
}
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpRootPath + "/" + filename);
request.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
request.Method = WebRequestMethods.Ftp.UploadFile;
Stream requestStream = request.GetRequestStream();
request.ContentLength = sourceStream.Length;
do
{
requestStream.Write(buffer, 0, bytesRead);
bytesRead = sourceStream.Read(buffer, 0, BUFFER_SIZE);
} while (bytesRead > 0);
sourceStream.Close();
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
response.Close();
return "Success";
}

Return stream reader from FTP response is good practice or not

I have a method for FTP download file, but I do not save file locally rather I parse the file in memory through ftp response. My question is, is returning stream reader after getting ftp response stream a good practice? Because do not want to do parsing and other stuff in the same method.
var uri = new Uri(string.Format("ftp://{0}/{1}/{2}", "somevalue", remotefolderpath, remotefilename));
var request = (FtpWebRequest)FtpWebRequest.Create(uri);
request.Credentials = new NetworkCredential(userName, password);
request.Method = WebRequestMethods.Ftp.DownloadFile;
var ftpResponse = (FtpWebResponse)request.GetResponse();
/* Get the FTP Server's Response Stream */
ftpStream = ftpResponse.GetResponseStream();
return responseStream = new StreamReader(ftpStream);
For me there are 2 disadvantages of using the stream directly, if you can live with them, you shouldn't waste memory or disk space.
In this stream you can not seek to a specific position, you can only read the contents as it comes in;
Your internet connection could suddenly drop and you will get an exception while parsing and processing your file, either split the parsing and processing or make sure your processing routine can handle the case that a file is processed for a second time (after a failure halfway through the first attempt).
To work around these issues, you could copy the stream to a MemoryStream:
using (var ftpStream = ftpResponse.GetResponseStream())
{
var memoryStream = new MemoryStream()
while ((bytesRead = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
memoryStream.Flush();
memoryStream.Position = 0;
return memoryStream;
}
If you are working with larger files I prefer writing it to a file, this way you minimize the memory footprint of your application:
using (var ftpStream = ftpResponse.GetResponseStream())
{
var fileStream = new FileStream(Path.GetTempFileName(), FileMode.CreateNew)
while ((bytesRead = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, bytesRead);
}
fileStream.Flush();
fileStream.Position = 0;
return fileStream;
}
I see more practical returning a responseStream when you are performing an HttpWebRequest. If you are using FtpWebRequest it means you are working with files. I would read the responseStream to byte[] and return the byte file content of the downloaded file, so you can easily work with the System.IO.Fileclasses to handle the file.
Thanks Carlos it was really helpful . I just return the byte[]
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = ftpStream.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
memoryStream=ms;
}
return memoryStream.ToArray();
and used byte[] in the method like this
public async Task ParseReport(byte[] bytesRead)
{
Stream stream = new MemoryStream(bytesRead);
using (StreamReader reader = new StreamReader(stream))
{
string line = null;
while (null != (line = reader.ReadLine()))
{
string[] values = line.Split(';');
}
}
stream.Close();
}

File download For Current Request

I need to download the file as http response for the current http request.
Until now I used code as
System.Uri uri = System.Web.HttpContext.Current.Request.Url;
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(
Path.Combine(uri.ToString(), filename));
httpRequest.Method = "GET";
using (HttpWebResponse httpResponse = (HttpWebResponse)httpRequest.GetResponse())
{
using (Stream responseStream = httpResponse.GetResponseStream())
{
using (FileStream localFileStream = new FileStream(
Path.Combine(localFolder, filename), FileMode.Open))
{
int bytesRead;
while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
{
totalBytesRead += bytesRead;
localFileStream.Write(buffer, 0, bytesRead);
}
}
}
}
But this code the request is only sending but not getting any responses...
Is this possible?
You should get the file off disk then use the Response.OutputStream to write the file directly to the response. Make sure to set the correct content headers so the browser will know what is coming.
FileInfo file = new FileInfo(Path.Combine(localFolder, filename));
int len = (int)file.Length, bytes;
Response.ContentType = "text/plain"; //Set the file type here
Response.AddHeader "Content-Disposition", "attachment;filename=" + filename;
context.Response.AppendHeader("content-length", len.ToString());
byte[] buffer = new byte[1024];
using(Stream stream = File.OpenRead(path)) {
while (len > 0 && (bytes =
stream.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytes);
len -= bytes;
}
}
Not sure, but it looks like your making a web request, getting the response stream, then attempting to buffer it out to localFolder. If so, FileMode.Open looks suspect ("should open an existing file..."?). Maybe use FileMode.Create.
MSDN ref
Also, does your web app needs to have write permissions to localFolder.

Write PDF stream to response stream

If I have a pdf file as a Stream, how can I write it to the response output stream?
Since you are using MVC, the best way is to use FileStreamResult:
return new FileStreamResult(stream, "application/pdf")
{
FileDownloadName = "file.pdf"
};
Playing with Response.Write or Response.OutputStream from your controller is non-idiomatic and there's no reason to write your own ActionResult when one already exists.
One way to do it is as follows:
//assuming you have your FileStream handle already - named fs
byte[] buffer = new byte[4096];
long count = 0;
while ((count = fs.Read(buffer, 0, buffer.Length)) > 0)
{
response.OutputStream.Write(buffer, 0, count);
response.Flush();
}
You can also use GZIP compression to speed the transfer of the file to the client (less bytes streamed).
In asp.net this is the way to download a pdf file
Dim MyFileStream As FileStream
Dim FileSize As Long
MyFileStream = New FileStream(filePath, FileMode.Open)
FileSize = MyFileStream.Length
Dim Buffer(CInt(FileSize)) As Byte
MyFileStream.Read(Buffer, 0, CInt(FileSize))
MyFileStream.Close()
Response.ContentType = "application/pdf"
Response.OutputStream.Write(Buffer, 0, FileSize)
Response.Flush()
Response.Close()
The HTTP Response is a stream exposed to you through the HttpContext.Response.OutputStream property, so if you have the PDF file in a stream you can simply copy the data from one stream to the other:
CopyStream(pdfStream, response.OutputStream);
For an implementation of CopyStream see Best way to copy between two Stream instances - C#
Please try this one:
protected void Page_Load(object sender, EventArgs e) {
Context.Response.Buffer = false;
FileStream inStr = null;
byte[] buffer = new byte[1024];
long byteCount; inStr = File.OpenRead(#"C:\Users\Downloads\sample.pdf");
while ((byteCount = inStr.Read(buffer, 0, buffer.Length)) > 0) {
if (Context.Response.IsClientConnected) {
Context.Response.ContentType = "application/pdf";
Context.Response.OutputStream.Write(buffer, 0, buffer.Length);
Context.Response.Flush();
}
}
}

Categories