Streaming video files in asp.net core 2 - asp.net-core-2.0

I want to play video in browser using asp.net core
in html I have
<video width="320" height="240" controls>
<source src="http://localhost:55193/api/VideoPlayer/Download" type="video/mp4">
Your browser does not support the video tag.
</video>
and in asp.net core 2
[HttpGet]
[Route("Download")]
public async Task<IActionResult> Download()
{
var path = #"d:\test\somemovie.mp4";
var memory = new MemoryStream();
using (var stream = new FileStream(#"d:\test\somemovie.mp4", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 65536, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, "application/octet-stream", Path.GetFileName(path));
}
Does this code play file by streaming( I mean buffer file chunk by chunk and play)?
And if I want to play file from any position which user set the player's progress, How I can do it?

Just use the normal return PhysicalFile here:
public class HomeController : Controller
{
public IActionResult Download()
{
return PhysicalFile(#"d:\test\somemovie.mp4", "application/octet-stream");
}
Because it supports range headers which are necessary for streaming and resuming a file download:
Also return File, FileStreamResult and VirtualFileResult support partial range requests too. Even static files middleware supports that too.

Something is wrong. My sample doesn't support resume
[HttpGet]
[Route("Download2")]
public IActionResult Download2()
{
return PhysicalFile(#"d:\test\somemovie.mp4", "application/octet-stream");
}
and there is no accept-ranges in response headers
but when I use
[HttpGet]
[Route("Download")]
public async Task<IActionResult> Download()
{
var path = #"d:\test\somemovie.mp4";
var memory = new MemoryStream();
using (var stream = new FileStream(#"d:\test\somemovie.mp4", FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 65536, FileOptions.Asynchronous | FileOptions.SequentialScan))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
return File(memory, "application/octet-stream", Path.GetFileName(path),true); //enableRangeProcessing = true
}
with "enableRangeProcessing" parameter true
Can you provide more explanation why the case is this?
And which solution I should use? I got confused.

static MediaStream song = null;
static byte[] SongArray = null;
song = await client.GetMediaStreamAsync(streamFilter).ConfigureAwait(false);
MemoryStream ms = new MemoryStream();
song.CopyTo(ms);
SongArray = ms.ToArray();
long fSize = song.Length, startbyte = 0, endbyte = fSize - 1;
int statusCode = 200;
var rangeRequest = Request.Headers["Range"].ToString();
if (!string.IsNullOrEmpty(rangeRequest))
{
string[] range = Request.Headers["Range"].ToString().Split(new char[] { '=', '-' });
startbyte = Convert.ToInt64(range[1]);
if (range.Length > 2 && range[2] != "")
{
endbyte = Convert.ToInt64(range[2]);
}
if (startbyte != 0 || endbyte != fSize - 1 || range.Length > 2 && range[2] == "")
{
statusCode = 206;
}
}
long desSize = endbyte - startbyte + 1;
Response.StatusCode = statusCode;
// Response.Headers.Add(ETag = new EntityTagHeaderValue(String.Format("\"{0}\"", _eTag));
Response.ContentType = "video/" + streamFilter.Container.GetFileExtension();
Response.Headers.Add("Content-Accept", Response.ContentType);
Response.Headers.Add("Content-Length", desSize.ToString());
Response.Headers.Add("Content-Range", string.Format("bytes {0}-{1}/{2}", startbyte, endbyte, fSize));
return new FileStreamResult(new MemoryStream(SongArray, (int)startbyte, (int)desSize), Response.ContentType);

Related

Making HTTPS call in C# with the BouncyCastle library

Using C# 4.0, I need to make HTTPS call with the BouncyCastle library (Short story : Windows XP + TLS 1.2).
When using the following code, I get a "HTTP Error 400. The request verb is invalid."
Here is my code :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
sr.NextBytes(dataToSend);
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}
class MyTlsClient : DefaultTlsClient
{
public override TlsAuthentication GetAuthentication()
{
return new MyTlsAuthentication();
}
}
class MyTlsAuthentication : TlsAuthentication
{
public TlsCredentials GetClientCredentials(CertificateRequest certificateRequest) { return null; }
public void NotifyServerCertificate(Certificate serverCertificate) { }
}
What I've already done :
Using WireShark to decrypt the ssl stream and inspect the request send => I've never succeeded to decrypt ssl stream
Using fiddler to decrypt the https stream => No detection by fiddler so I suspect something might be badly encrypted
Any ideas ?
Thanks to PeterDettman who gave me the solution :
I must not use the sr.NextBytes(instructions), so the code becomes :
using (var client = new TcpClient("serverName", 443))
{
var sr = new SecureRandom();
var cl = new MyTlsClient();
var protocol = new TlsClientProtocol(client.GetStream(), sr);
protocol.Connect(new MyTlsClient());
using (var stream = protocol.Stream)
{
var hdr = new StringBuilder();
hdr.AppendLine("GET /Url/WebService.asmx?wsdl HTTP/1.1");
hdr.AppendLine("Host: serverName");
hdr.AppendLine("Content-Type: text/xml; charset=utf-8");
hdr.AppendLine("Connection: close");
hdr.AppendLine();
var dataToSend = Encoding.ASCII.GetBytes(hdr.ToString());
stream.Write(dataToSend, 0, dataToSend.Length);
int totalRead = 0;
string response = "";
byte[] buff = new byte[1000];
do
{
totalRead = stream.Read(buff, 0, buff.Length);
response += Encoding.ASCII.GetString(buff, 0, totalRead);
} while (totalRead == buff.Length);
}
}

NAudio Mp3 decoding click and pops

I followed this NAudio Demo modified to play ShoutCast.
In my full code I have to resample the incoming audio and stream it again over the network to a network player. Since I get many "clicks and pops", I came back to the demo code and I found that these artifacts are originated after the decoding block.
If I save the incoming stream in mp3 format, it is pretty clear.
When I save the raw decoded data (without other processing than the decoder) I get many audio artifacts.
I wonder whether I am doing some error, even if my code is almost equal to the NAudio demo.
Here the function from the example as modified by me to save the raw data. It is called as a new Thread.
private void StreamMP3(object state)
{
//Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
//SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");
this.fullyDownloaded = false;
string url = "http://icestreaming.rai.it/5.mp3";//(string)state;
webRequest = (HttpWebRequest)WebRequest.Create(url);
int metaInt = 0; // blocksize of mp3 data
int framesize = 0;
webRequest.Headers.Clear();
webRequest.Headers.Add("GET", "/ HTTP/1.0");
// needed to receive metadata informations
webRequest.Headers.Add("Icy-MetaData", "1");
webRequest.UserAgent = "WinampMPEG/5.09";
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)webRequest.GetResponse();
}
catch (WebException e)
{
if (e.Status != WebExceptionStatus.RequestCanceled)
{
ShowError(e.Message);
}
return;
}
byte[] buffer = new byte[16384 * 4]; // needs to be big enough to hold a decompressed frame
try
{
// read blocksize to find metadata block
metaInt = Convert.ToInt32(resp.GetResponseHeader("icy-metaint"));
}
catch
{
}
IMp3FrameDecompressor decompressor = null;
byteOut = createNewFile(destPath, "salva", "raw");
try
{
using (var responseStream = resp.GetResponseStream())
{
var readFullyStream = new ReadFullyStream(responseStream);
readFullyStream.metaInt = metaInt;
do
{
if (mybufferedWaveProvider != null && mybufferedWaveProvider.BufferLength - mybufferedWaveProvider.BufferedBytes < mybufferedWaveProvider.WaveFormat.AverageBytesPerSecond / 4)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
}
else
{
Mp3Frame frame = null;
try
{
frame = Mp3Frame.LoadFromStream(readFullyStream, true);
if (metaInt > 0)
UpdateSongName(readFullyStream.SongName);
else
UpdateSongName("No Song Info in Stream...");
}
catch (EndOfStreamException)
{
this.fullyDownloaded = true;
// reached the end of the MP3 file / stream
break;
}
catch (WebException)
{
// probably we have aborted download from the GUI thread
break;
}
if (decompressor == null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat waveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
decompressor = new AcmMp3FrameDecompressor(waveFormat);
this.mybufferedWaveProvider = new BufferedWaveProvider(decompressor.OutputFormat);
this.mybufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(200); // allow us to get well ahead of ourselves
framesize = (decompressor.OutputFormat.Channels * decompressor.OutputFormat.SampleRate * (decompressor.OutputFormat.BitsPerSample / 8) * 20) / 1000;
//this.bufferedWaveProvider.BufferedDuration = 250;
}
int decompressed = decompressor.DecompressFrame(frame, buffer, 0);
//Debug.WriteLine(String.Format("Decompressed a frame {0}", decompressed));
mybufferedWaveProvider.AddSamples(buffer, 0, decompressed);
while (mybufferedWaveProvider.BufferedDuration.Milliseconds >= 20)
{
byte[] read = new byte[framesize];
mybufferedWaveProvider.Read(read, 0, framesize);
byteOut.Write(read, 0, framesize);
}
}
} while (playbackState != StreamingPlaybackState.Stopped);
Debug.WriteLine("Exiting");
// was doing this in a finally block, but for some reason
// we are hanging on response stream .Dispose so never get there
decompressor.Dispose();
}
}
finally
{
if (decompressor != null)
{
decompressor.Dispose();
}
}
}
OK i found the problem. I included the shoutcast metadata to the MP3Frame.
See the comment "HERE I COLLECT THE BYTES OF THE MP3 FRAME" to locate the correct point to get the MP3 frame with no streaming metadata.
The following code runs without audio artifacts:
private void SHOUTcastReceiverThread()
{
//-*- String server = "http://216.235.80.18:8285/stream";
//String serverPath = "/";
//String destPath = "C:\\temp\\"; // destination path for saved songs
HttpWebRequest request = null; // web request
HttpWebResponse response = null; // web response
int metaInt = 0; // blocksize of mp3 data
int count = 0; // byte counter
int metadataLength = 0; // length of metadata header
string metadataHeader = ""; // metadata header that contains the actual songtitle
string oldMetadataHeader = null; // previous metadata header, to compare with new header and find next song
//CircularQueueStream framestream = new CircularQueueStream(2048);
QueueStream framestream = new QueueStream();
framestream.Position = 0;
bool bNewSong = false;
byte[] buffer = new byte[512]; // receive buffer
byte[] dec_buffer = new byte[decSIZE];
Mp3Frame frame;
IMp3FrameDecompressor decompressor = null;
Stream socketStream = null; // input stream on the web request
// create web request
request = (HttpWebRequest)WebRequest.Create(server);
// clear old request header and build own header to receive ICY-metadata
request.Headers.Clear();
request.Headers.Add("GET", serverPath + " HTTP/1.0");
request.Headers.Add("Icy-MetaData", "1"); // needed to receive metadata informations
request.UserAgent = "WinampMPEG/5.09";
// execute request
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
return;
}
// read blocksize to find metadata header
metaInt = Convert.ToInt32(response.GetResponseHeader("icy-metaint"));
try
{
// open stream on response
socketStream = response.GetResponseStream();
var readFullyStream = new ReadFullyStream(socketStream);
frame = null;
// rip stream in an endless loop
do
{
if (IsBufferNearlyFull)
{
Debug.WriteLine("Buffer getting full, taking a break");
Thread.Sleep(500);
frame = null;
}
else
{
int bufLen = readFullyStream.Read(buffer, 0, buffer.Length);
try
{
if (framestream.CanRead && framestream.Length > 512)
frame = Mp3Frame.LoadFromStream(framestream);
else
frame = null;
}
catch (Exception ex)
{
frame = null;
}
if (bufLen < 0)
{
Debug.WriteLine("Buffer error 1: exit.");
return;
}
// processing RAW data
for (int i = 0; i < bufLen; i++)
{
// if there is a header, the 'headerLength' would be set to a value != 0. Then we save the header to a string
if (metadataLength != 0)
{
metadataHeader += Convert.ToChar(buffer[i]);
metadataLength--;
if (metadataLength == 0) // all metadata informations were written to the 'metadataHeader' string
{
string fileName = "";
string fileNameRaw = "";
// if songtitle changes, create a new file
if (!metadataHeader.Equals(oldMetadataHeader))
{
// flush and close old byteOut stream
if (byteOut != null)
{
byteOut.Flush();
byteOut.Close();
byteOut = null;
}
if (byteOutRaw != null)
{
byteOutRaw.Flush();
byteOutRaw.Close();
byteOutRaw = null;
}
timeStart = timeEnd;
// extract songtitle from metadata header. Trim was needed, because some stations don't trim the songtitle
//fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';StreamUrl)").Groups[2].Value.Trim();
fileName = Regex.Match(metadataHeader, "(StreamTitle=')(.*)(';)").Groups[2].Value.Trim();
// write new songtitle to console for information
if (fileName.Length == 0)
fileName = "shoutcast_test";
fileNameRaw = fileName + "_raw";
framestream.reSetPosition();
SongChanged(this, metadataHeader);
bNewSong = true;
// create new file with the songtitle from header and set a stream on this file
timeEnd = DateTime.Now;
if (bWrite_to_file)
{
byteOut = createNewFile(destPath, fileName, "mp3");
byteOutRaw = createNewFile(destPath, fileNameRaw, "raw");
}
timediff = timeEnd - timeStart;
// save new header to 'oldMetadataHeader' string, to compare if there's a new song starting
oldMetadataHeader = metadataHeader;
}
metadataHeader = "";
}
}
else // write mp3 data to file or extract metadata headerlength
{
if (count++ < metaInt) // write bytes to filestream
{
//HERE I COLLECT THE BYTES OF THE MP3 FRAME
framestream.Write(buffer, i, 1);
}
else // get headerlength from lengthbyte and multiply by 16 to get correct headerlength
{
metadataLength = Convert.ToInt32(buffer[i]) * 16;
count = 0;
}
}
}//for
if (bNewSong)
{
decompressor = createDecompressor(frame);
bNewSong = false;
}
if (frame != null && decompressor != null)
{
framedec(decompressor, frame);
}
// fine Processing dati RAW
}//Buffer is not full
SHOUTcastStatusProcess();
} while (playbackState != StreamingPlaybackState.Stopped);
} //try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
if (byteOut != null)
byteOut.Close();
if (socketStream != null)
socketStream.Close();
if (decompressor != null)
{
decompressor.Dispose();
decompressor = null;
}
if (null != request)
request.Abort();
if (null != framestream)
framestream.Dispose();
if (null != bufferedWaveProvider)
bufferedWaveProvider.ClearBuffer();
//if (null != bufferedWaveProviderOut)
// bufferedWaveProviderOut.ClearBuffer();
if (null != mono16bitFsinStream)
{
mono16bitFsinStream.Close();
mono16bitFsinStream.Dispose();
}
if (null != middleStream2)
{
middleStream2.Close();
middleStream2.Dispose();
}
if (null != resampler)
resampler.Dispose();
}
}
public class QueueStream : MemoryStream
{
long ReadPosition = 0;
long WritePosition = 0;
public QueueStream() : base() { }
public override int Read(byte[] buffer, int offset, int count)
{
Position = ReadPosition;
var temp = base.Read(buffer, offset, count);
ReadPosition = Position;
return temp;
}
public override void Write(byte[] buffer, int offset, int count)
{
Position = WritePosition;
base.Write(buffer, offset, count);
WritePosition = Position;
}
public void reSetPosition()
{
WritePosition = 0;
ReadPosition = 0;
Position = 0;
}
}
private void framedec(IMp3FrameDecompressor decompressor, Mp3Frame frame)
{
int Ndecoded_samples = 0;
byte[] dec_buffer = new byte[decSIZE];
Ndecoded_samples = decompressor.DecompressFrame(frame, dec_buffer, 0);
bufferedWaveProvider.AddSamples(dec_buffer, 0, Ndecoded_samples);
NBufferedSamples += Ndecoded_samples;
brcnt_in.incSamples(Ndecoded_samples);
if (Ndecoded_samples > decSIZE)
{
Debug.WriteLine(String.Format("Too many samples {0}", Ndecoded_samples));
}
if (byteOut != null)
byteOut.Write(frame.RawData, 0, frame.RawData.Length);
if (byteOutRaw != null) // as long as we don't have a songtitle, we don't open a new file and don't write any bytes
byteOutRaw.Write(dec_buffer, 0, Ndecoded_samples);
frame = null;
}
private IMp3FrameDecompressor createDecompressor(Mp3Frame frame)
{
IMp3FrameDecompressor dec = null;
if (frame != null)
{
// don't think these details matter too much - just help ACM select the right codec
// however, the buffered provider doesn't know what sample rate it is working at
// until we have a frame
WaveFormat srcwaveFormat = new Mp3WaveFormat(frame.SampleRate, frame.ChannelMode == ChannelMode.Mono ? 1 : 2, frame.FrameLength, frame.BitRate);
dec = new AcmMp3FrameDecompressor(srcwaveFormat);
bufferedWaveProvider = new BufferedWaveProvider(dec.OutputFormat);// decompressor.OutputFormat
bufferedWaveProvider.BufferDuration = TimeSpan.FromSeconds(400); // allow us to get well ahead of ourselves
// ------------------------------------------------
//Create an intermediate format with same sampling rate, 16 bit, mono
middlewavformat = new WaveFormat(dec.OutputFormat.SampleRate, 16, 1);
outwavFormat = new WaveFormat(Fs_out, 16, 1);
// wave16ToFloat = new Wave16ToFloatProvider(provider); // I have tried with and without this converter.
wpws = new WaveProviderToWaveStream(bufferedWaveProvider);
//Check middlewavformat.Encoding == WaveFormatEncoding.Pcm;
mono16bitFsinStream = new WaveFormatConversionStream(middlewavformat, wpws);
middleStream2 = new BlockAlignReductionStream(mono16bitFsinStream);
resampler = new MediaFoundationResampler(middleStream2, outwavFormat);
}
return dec;
}

ASP.NET MVC Core Azure Blob Image Resizer

I've got an ASP.NET core application that uploads images to Azure. I am attempting to resize an image using Magick.NET before uploading said image to Azure Blob container. So far, I've managed to save the image to a folder in a local hard drive. Is this the correct way of writing this?
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Product products)
{
var files = products.UploudThumbnail;
List<string> image = new List<string>();
List<string> names = new List<string>();
if (files != null)
{
foreach (var file in files)
{
if (ModelState.IsValid)
{
if (file.ContentType == "image/jpeg" || file.ContentType == "image/jpg")
{
if (file.Length < 1 * 1000 * 1000)
{
var parsedContentDisposition = ContentDispositionHeaderValue.Parse(file.ContentDisposition);
var fileName = parsedContentDisposition.FileName.Trim('"');
names.Add(fileName);
fileName = Guid.NewGuid().ToString() + "-" + fileName;
CloudBlockBlob cloudBlockBlob = cloudBlobContainer.GetBlockBlobReference(fileName);
cloudBlockBlob.Properties.ContentType = file.ContentType;
await cloudBlockBlob.UploadFromStreamAsync(file.OpenReadStream());
image.Add(cloudBlockBlob.Uri.AbsoluteUri);
const int size = 20;
const int quality = 75;
using (var image = new MagickImage(file.OpenReadStream()))
{
image.Resize(size, size);
image.Strip();
image.Quality = quality;
//how to save it into azure?
image.Write(fileName);
}
}
else
{
ModelState.AddModelError("UploudThumbnail", "Max size not accepted");
}
}
else
{
ModelState.AddModelError("UploudThumbnail", "jpeg & jpg are accepted");
}
}
}
}
_context.Add(products);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
Just write the image to a memory stream and upload it using the UploadFromStreamAsync method.
Example (pseudo):
using (var memStream = new MemoryStream())
{
image.Write(memStream);
memStream.Seek(0, SeekOrigin.Begin);
await cloudBlockBlob.UploadFromStreamAsync(memStream);
}

How to save Rotativa PDF on server

I am using Rotativa to generate PDF in my "MVC" application. How can I save Rotativa PDF? I need to save the document on a server after all the process is completed.
Code below:
public ActionResult PRVRequestPdf(string refnum,string emid)
{
var prv = functions.getprvrequest(refnum, emid);
return View(prv);
}
public ActionResult PDFPRVRequest()
{
var prv = Session["PRV"] as PRVRequestModel;
byte[] pdfByteArray = Rotativa.WkhtmltopdfDriver.ConvertHtml("Rotativa", "Approver", "PRVRequestPdf");
return new Rotativa.ViewAsPdf("PRVRequestPdf", new { refnum = prv.rheader.request.Referenceno });
}
You can give this a try
var actionResult = new ActionAsPdf("PRVRequestPdf", new { refnum = prv.rheader.request.Referenceno, emid = "Whatever this is" });
var byteArray = actionResult.BuildPdf(ControllerContext);
var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write);
fileStream.Write(byteArray, 0, byteArray.Length);
fileStream.Close();
If that doesn't do the trick then, you can follow the answers here
Just make sure if you do it this way not to have PRVRequestPdf return as a PDF View, rather a normal View like you have above (only mention as managed to fall foul of that myself causing lots of fun).
Another useful answer:
I found the solution here
var actionPDF = new Rotativa.ActionAsPdf("YOUR_ACTION_Method", new { id = ID, lang = strLang } //some route values)
{
//FileName = "TestView.pdf",
PageSize = Size.A4,
PageOrientation = Rotativa.Options.Orientation.Landscape,
PageMargins = { Left = 1, Right = 1 }
};
byte[] applicationPDFData = actionPDF.BuildPdf(ControllerContext);
This is the original thread
You can achieve this with ViewAsPdf.
[HttpGet]
public ActionResult SaveAsPdf(string refnum, string emid)
{
try
{
var prv = functions.getprvrequest(refnum, emid);
ViewAsPdf pdf = new Rotativa.ViewAsPdf("PRVRequestPdf", prv)
{
FileName = "Test.pdf",
CustomSwitches = "--page-offset 0 --footer-center [page] --footer-font-size 8"
};
byte[] pdfData = pdf.BuildFile(ControllerContext);
string fullPath = #"\\server\network\path\pdfs\" + pdf.FileName;
using (var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write))
{
fileStream.Write(pdfData, 0, pdfData.Length);
}
return Json(new { isSuccessful = true }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
//TODO: ADD LOGGING
return Json(new { isSuccessful = false, error = "Uh oh!" }, JsonRequestBehavior.AllowGet);
//throw;
}
}
You can simply try this:
var fileName = string.Format("my_file_{0}.pdf", id);
var path = Server.MapPath("~/App_Data/" + fileName);
System.IO.File.WriteAllBytes(path, pdfByteArray );

How to allow a file to be read by multiple users/process at a time on web server

I am using below code in asp.net webapi for audio streaming to allow android application to call api and play songs.
public class AudioController : ApiController
{
ITrackRepository _TrackRepo = new TrackRepository();
public AudioController()
{
}
public HttpResponseMessage Get(int id)
{
var trackd = _TrackRepo.GetPlayfilepath(id);
string filename = System.Web.HttpContext.Current.Server.MapPath(trackd.Select(x => x.FilePath).FirstOrDefault());
var audio = new AudioStream(filename);
string fileExtension = System.IO.Path.GetExtension(filename);
var response = Request.CreateResponse();
response.Content = new PushStreamContent(audio.WriteToStream, new MediaTypeHeaderValue("audio/" + fileExtension));
return response;
}
}
public class AudioStream
{
private readonly string _filename;
public AudioStream(string filename)
{
_filename = filename;
}
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[65536];
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
{
var length = (int)video.Length;
var bytesRead = 1;
while (length > 0 && bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, Math.Min(length, buffer.Length));
await outputStream.WriteAsync(buffer, 0, bytesRead);
length -= bytesRead;
}
}
}
catch (HttpException ex)
{
return;
}
finally
{
outputStream.Close();
}
}
}
I am able to play song, i tested it with vlc (stream) and its working fine, Issue is when i try to play same song in parallel in another player its giving me below error
The process cannot access the file because it is being used by another
process.
I completely understand error, but i am not able to find any satisfactory solution.
one solution is to create a copy of song before play/stream and delete it on completion but i don't think that is a good solution.
please suggest.
I'm not at a computer with visual studio on it at the moment, but look at this overload for File.Open
Try changing this line:
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read))
to
using (var video = File.Open(_filename, FileMode.Open, FileAccess.Read, FileShare.Read))
See if that helps.

Resources