Can't get stable 304 response when caching in .NET - c#

I need to control cache on the file-level.
Sometimes I can get a 304 response when the file is reloaded - but mostly not.
What am I doing wrong here with my caching settings?
public static void GetAndOutputFile(string url, int maxAgeInHours, string key)
{
Stream stream = null;
const int bytesToRead = 100000;
byte[] buffer = new Byte[bytesToRead];
try
{
HttpWebRequest fileReq = (HttpWebRequest) HttpWebRequest.Create(url);
HttpWebResponse fileResp = (HttpWebResponse) fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
stream = fileResp.GetResponseStream();
var resp = HttpContext.Current.Response;
resp.ContentType = fileResp.ContentType;
//Set cache
resp.Cache.SetCacheability(HttpCacheability.Public);
resp.Cache.SetSlidingExpiration(false);
resp.Cache.SetLastModified(DateTime.Parse("1/1/2001 00:00:01AM"));
resp.Cache.SetMaxAge(TimeSpan.FromHours(maxAgeInHours));
resp.Cache.SetExpires(DateTime.UtcNow.AddHours(maxAgeInHours));
MemoryStream ms = new MemoryStream();
int length;
do
{
if (resp.IsClientConnected)
{
length = stream.Read(buffer, 0, bytesToRead);
resp.OutputStream.Write(buffer, 0, length);
ms.Write(buffer, 0, length);
resp.Flush();
buffer = new Byte[bytesToRead];
}
else
{
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
stream.Dispose();
}
}
}
}

Found the solution. Key issue is that must set the 304 yourself in .NET.
public static void GetAndOutputFile(string url, int maxAgeInHours, string key)
{
if (!String.IsNullOrEmpty(HttpContext.Current.Request.Headers["If-Modified-Since"]))
{
CultureInfo provider = CultureInfo.InvariantCulture;
var lastMod = DateTime.ParseExact(HttpContext.Current.Request.Headers["If-Modified-Since"], "r", provider).ToLocalTime();
if (lastMod < DateTime.UtcNow.ToLocalTime())
{
HttpContext.Current.Response.StatusCode = 304;
HttpContext.Current.Response.StatusDescription = "Not Modified";
return;
}
}
Stream stream = null;
const int bytesToRead = 100000;
byte[] buffer = new Byte[bytesToRead];
try
{
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(url);
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
stream = fileResp.GetResponseStream();
var resp = HttpContext.Current.Response;
resp.ContentType = fileResp.ContentType;
resp.Cache.SetCacheability(HttpCacheability.Public);
resp.Cache.SetExpires(DateTime.UtcNow.AddHours(maxAgeInHours));
resp.Cache.SetLastModified(DateTime.UtcNow.AddMinutes(-1));
MemoryStream ms = new MemoryStream();
int length;
do
{
if (resp.IsClientConnected)
{
length = stream.Read(buffer, 0, bytesToRead);
resp.OutputStream.Write(buffer, 0, length);
ms.Write(buffer, 0, length);
resp.Flush();
buffer = new Byte[bytesToRead];
}
else
{
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
stream.Dispose();
}
}

Related

is there any way to get data from service to web api

I am trying sending the data of file in chunks to web api through worker service. But chunks can not be received by web api, here is my code
Here is some code of worker service
int chunkSize = 100;
using (Stream streamx = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[chunkSize];
int bytesRead = 0;
long bytesToRead = streamx.Length;
while (bytesToRead > 0)
{
int n = streamx.Read(buffer, 0, chunkSize);
if (n == 0) break;
// Let's resize the last incomplete buffer
if (n != buffer.Length)
Array.Resize(ref buffer, n);
MultipartFormDataContent form = new MultipartFormDataContent();
HttpContent byteContent = new ByteArrayContent(buffer);
form.Add(byteContent, "fileByte");
HttpResponseMessage response1 = null;
try
{
response1 = client.PostAsync("http://localhost:15594/weatherforecast/PostData", form).Result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
var k = response1.Content.ReadAsStringAsync().Result;
response = null;
bytesRead += n;
bytesToRead -= n;
}
Here is some code of web api
[HttpPost]
[Route("PostData")]
public IActionResult PostData()
{
var request = HttpContext.Request;
var vals = request.Form.TryGetValue("fileByte", out StringValues sv).ToString();
NameValueCollection vals2 = new NameValueCollection();
int count = vals2.Count;
string cv = null;
foreach(var i in vals2)
{
cv += i;
}
}
Here I have solved the issue, basically I want to upload a file in chunks ,
Here the code of file uploading to webapi ,
int chunkSize = 1024
using (Stream streamx = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
byte[] buffer = new byte[chunkSize];
int bytesRead = 0;
long bytesToRead = streamx.Length;
while (bytesToRead > 0)
{
int n = streamx.Read(buffer, 0, chunkSize);
if (n == 0) break;
if (n != buffer.Length)
Array.Resize(ref buffer, n);
MultipartFormDataContent multiContent = new MultipartFormDataContent();
ByteArrayContent bytes = new ByteArrayContent(buffer);
multiContent.Add(bytes, "file", fi.Name);
HttpResponseMessage response1 = null;
try
{
response1 = client.PostAsync("http://localhost:15594/weatherforecast/PostData", multiContent).Result;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
var k = response1.Content.ReadAsStringAsync().Result;
response = null;
bytesRead += n;
bytesToRead -= n;
}
}
'''
here is code snippet of webapi
'''
[HttpPost]
[Route("PostData")]
public IActionResult PostData()
{​​​​​​​
var form = Request.Form;
foreach (var formFile in form.Files)
{​​​​​​​
var fileName = formFile.FileName;
var savePath = Path.Combine(#"E:\Program\_210302_1WebApplication_API\_210302_1WebApplication_API\wwwroot", fileName);
using (var fileStream = new FileStream(savePath, FileMode.Append))
{​​​​​​​
formFile.CopyTo(fileStream);
}​​​​​​​
}​​​​​​​
}​​​​​​​
'''

The stream does not support concurrent IO read or write operations

I have tried to search for this issue else where in Stack Overflow but couldn't find a proper answer, hence posting my question here. Below is my code, basically i am trying to read content from a file and post it to a web api, and then repeat the same step with another file. The first call passes but the second call fails with the error:
The stream does not support concurrent IO read or write operations at this line requestStream.Write(buffer, 0, bytesRead);.
Could please tell me what am i doing wrong here?
using(FileStream fs = new FileStream(# "C:\Test1.txt", FileMode.Open, FileAccess.Read)) {
byte[] buffer = null;
int bytesRead = 0;
using(Stream requestStream = request.GetRequestStream()) {
buffer = new Byte[checked((uint) Math.Min(1024, (int) fs.Length))];
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0) {
requestStream.Write(buffer, 0, bytesRead);
}
requestStream.Flush();
}
}
using(FileStream fs = new FileStream(# "C:\Test2.txt", FileMode.Open, FileAccess.Read)) {
byte[] buffer = null;
int bytesRead = 0;
using(Stream requestStream = request.GetRequestStream()) {
buffer = new Byte[checked((uint) Math.Min(1024, (int) fs.Length))];
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0) {
requestStream.Write(buffer, 0, bytesRead);
}
requestStream.Flush();
}
}
I believe the problem is happening because you are trying to get a request stream that is no more avaliable:
Try this code:
List<string> files = new List<String>();
files.Add(#"C:\Test1.txt");
files.Add(#"C:\Test2.txt");
using (Stream requestStream = request.GetRequestStream())
{
files.ForEach(fileName =>
{
byte[] buffer = null;
int bytesRead = 0;
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
buffer = new Byte[checked((uint)Math.Min(1024, (int)fs.Length))];
while ((bytesRead = fs.Read(buffer, 0, buffer.Length)) != 0)
{
requestStream.Write(buffer, 0, bytesRead);
}
requestStream.Flush();
}
});
}
Update: To have control over endpoints and files, try this:
static void Main(string[] args)
{
string result = SendPost(#"C:\Test1.txt", "https://httpbin.org/post");
if(result.Contains("SUCCESS"))
SendPost(#"C:\Test2.txt", "https://httpbin.org/anotherpost");
}
static string SendPost(string filename, string URL)
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create(URL);
httpWebRequest.ContentType = "text/plain";
httpWebRequest.Method = "POST";
/*proxy config*/
WebProxy proxy = new WebProxy();
Uri newUri = new Uri("http://xxxxxx");
proxy.Address = newUri;
httpWebRequest.Proxy = proxy;
using (var sw = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string[] lines = File.ReadAllLines(filename);
for(int i=0; i<lines.Length; i++)
sw.WriteLine(lines[i]);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
return result;
}
}

Transfer really large files using WebClient

My requirement is to transfer a zip file of size 400MB or more; The following code works for at least 40MB; But for more I would have to change byte[] bytes = new byte[50000000]; to byte[] bytes = new byte[400000000]; and maxRequestLength to maxRequestLength="409600";
The problem is byte[] bytes = new byte[100000000]; returns an error regarding insufficient space. So how can I transfer large files using WebClient??
WebClient client = new WebClient();
client.AllowWriteStreamBuffering = true;
UriBuilder ub = new UriBuilder("http://localhost:57596/UploadImages.ashx");
ub.Query = "ImageName=" + "DataSet" + DataSetId + ".zip";
client.OpenWriteCompleted += (InputStream, eArguments) =>
{
try
{
using (Stream output = eArguments.Result)
{
output.Write(ImagesAux, 0, (int)ImagesAux.Length);
//numeroimagem++;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
//throw;
}
};
client.OpenWriteAsync(ub.Uri);
in UploadImages.ashx
public void ProcessRequest(HttpContext context)
{
//context.Response.ContentType = "text/plain";
//context.Response.Write("Hello World");
string ImageName = context.Request.QueryString["ImageName"];
string UploadPath = context.Server.MapPath("~/ServerImages/");
using (FileStream stream = File.Create(UploadPath + ImageName))
{
byte[] bytes = new byte[50000000]; //
int bytesToRead = 0;
while ((bytesToRead =
context.Request.InputStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, bytesToRead);
stream.Close();
}
}
}
in Web.config
<httpRuntime targetFramework="4.5" maxRequestLength="40960"/>
You should never load everything in memory then write all back to disk, but instead you should load pieces and write them to disk while you are reading them.
When you've done reading you close the stream you are writing to.
Otherwise as soon as you reach sizes as GB you can get an OutOfMemory really quick.
So I would change the writing bytes to disk from this:
using (FileStream stream = File.Create(UploadPath + ImageName))
{
byte[] bytes = new byte[50000000]; //
int bytesToRead = 0;
while ((bytesToRead = context.Request.InputStream.Read(bytes, 0, bytes.Length)) != 0)
{
stream.Write(bytes, 0, bytesToRead);
stream.Close();
}
}
to this:
using (FileStream stream = File.Create(UploadPath + ImageName))
{
byte[] bytes = new byte[1024];
long totalBytes = context.Request.InputStream.Length;
long bytesRead = 0;
int bytesToRead = bytes.Length;
if (totalBytes - bytesRead < bytes.Length)
bytesToRead = (int)(totalBytes - bytesRead);
bytes = new byte[bytesToRead];
while ((bytesToRead = context.Request.InputStream.Read(bytes, bytesRead, bytes.Length)) != 0)
{
stream.Write(bytes, bytesRead, bytes.Length);
bytesRead += bytes.Length;
if (totalBytes - bytesRead < bytes.Length)
bytesToRead = (int)(totalBytes - bytesRead);
bytes = new byte[bytesToRead];
}
stream.Close();
}
1024 would be the buffer size.

Download a file and read from it in the same time

I download a file with this method:
WebClient WC = new WebClient();
WC.DownloadFile(url, filePath);
And i want that in the same time to read the file in the same time with:
var fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.None);
but i get allways :
The process cannot access the file 'filePath' because it is being used by another process.
It's possible to download and read in the same time?
Edit
I now download the file with:
var req = (HttpWebRequest)HttpWebRequest.Create(url);
var fileStream = new FileStream(filePath,
FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite);
using (var resp = req.GetResponse())
{
using (var stream = resp.GetResponseStream())
{
byte[] buffer = new byte[0x10000];
int len;
while ((len = stream.Read(buffer, 0, buffer.Length)) > 0)
{
fileStream.Write(buffer, 0, len);
}
}
}
And still get the error....
var req = (HttpWebRequest)HttpWebRequest.Create(url);
using (var resp = req.GetResponse())
{
using (var stream = resp.GetResponseStream())
{
byte[] buffer = new byte[0x10000];
int len;
while ((len = stream.Read(buffer, 0, buffer.Length))>0)
{
//Do with the content whatever you want
// ***YOUR CODE***
fileStream.Write(buffer, 0, len);
}
}
}
Try this way :
HttpWebRequest request = (HttpWebRequest) WebRequest.Create("http://www.domain.com/file.txt");
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
var stream = response.GetResponseStream();
byte[] buffer = new byte[8192];
int bytesRead = 0;
while ((bytesRead = stream.Read(buffer, 0, 8192)) > 0)
{
// handle your raw data
// you needed raw data = buffer[0 to bytesRead - 1]
}
stream.Close();
response.Close();

sending httpresponses in library file c#

i used the following code to download the file folder in asp.net website are
string path = #"E:\sample.zip";
FileInfo file = new FileInfo(path);
int len = (int)file.Length, bytes;
Response.ContentType = "text/html";
// Response.AddHeader "Content-Disposition", "attachment;filename=" + filename;
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;
}
}
it works fine/...
but my problem is when i used the same code to the library file as
FileInfo file = new FileInfo(ZipPath);
int len = (int)file.Length, bytes;
HttpResponse Response = new HttpResponse(TextWriter.Null);
Response.ContentType = "text/html";
Response.AppendHeader("content-length", len.ToString());
byte[] buffer = new byte[1024];
using (Stream stream = File.OpenRead(ZipPath))
{
while (len > 0 && (bytes =
stream.Read(buffer, 0, buffer.Length)) > 0)
{
Response.OutputStream.Write(buffer, 0, bytes);
len -= bytes;
}
}
}
it throws me a error as
OutputStream is not available when a custom TextWriter is used.
i guess the problem is in that line
HttpResponse Response = new HttpResponse(TextWriter.Null);
can you provide me a solution
waiting for your responses....
You can try with this code
TextWriter sw = new StringWriter();
HttpResponse Response = new HttpResponse(sw);
i replaced the structures as
HttpResponse response = HttpContext.Current.Response;
it works fine.....
Thanks all for your support

Categories

Resources