I'm looking for your expertise/help figuring out why my http handler works perfectly over http and doesn't over https (only IE problem, other browsers work fine either way). I'm using the handler to display images and when https is used on IE, it shows some images and fails to show others images.
again, the problem is only happening on https and IE, all other mutations with other browsers work just fine. below is my code:
public void ProcessRequest(HttpContext context)
{
Stream iStream = null;
try
{
if (!context.Response.IsClientConnected || HttpContext.Current == null || HttpContext.Current.Session["GoodUser"] == null)
return;
var url = context.Request.QueryString[#"ID"];
if (string.IsNullOrWhiteSpace(url))
return;
var fileUrl = EncryptionManager.DecryptUrl(url);
if (!File.Exists(fileUrl))
return;
var buffer = new byte[4096];
// Open the file.
iStream = new FileStream(fileUrl, FileMode.Open, FileAccess.Read, FileShare.Read);
// Total bytes to read:
var dataToRead = iStream.Length;
context.Response.AddHeader(#"Accept-Ranges", #"bytes");
context.Response.AddHeader(#"Content-Length", dataToRead.ToString());
context.Response.StatusCode= (int)HttpStatusCode.OK;
var file = new FileInfo(fileUrl);
context.Response.ContentType = MimeTypeMap.GetMimeType(file.Extension);
context.Response.Cache.SetCacheability(HttpCacheability.NoCache);
context.Response.Cache.SetNoStore();
context.Response.Cache.SetExpires(DateTime.MinValue);
if (!string.IsNullOrEmpty(context.Request.Headers[#"Range"]))
{
var range = context.Request.Headers[#"Range"].Split('=', '-');
var startbyte = int.Parse(range[1]);
iStream.Seek(startbyte, SeekOrigin.Begin);
context.Response.StatusCode = 206;
context.Response.AddHeader(#"Content-Range", $#" bytes {startbyte}-{dataToRead - 1}/{dataToRead}");
}
while (dataToRead > 0)
{
iStream.Read(buffer, 0, buffer.Length);
if (context.Response.IsClientConnected)
{
context.Response.OutputStream.Write(buffer, 0, buffer.Length);
context.Response.Flush();
buffer = new byte[buffer.Length];
dataToRead = dataToRead - buffer.Length;
}
else
{
dataToRead = -1;
}
}
}
catch (Exception exception)
{
}
finally
{
iStream?.Close();
context.ApplicationInstance.CompleteRequest();
}
}
Related
I use IHttpHandler to Download a file from Server.Everything works fine.
But it shows the data on browser instead of download it. I need to download the file from the server like we do download from other servers.
Could anyone suggest me, what should I do to download the file,
Or what is the convenient way to download a file(pdf,mp4 etc).
public void ProcessRequest(HttpContext context)
{
string strPathName = "";
if (context.Request.QueryString["fileName"] != null)
{
strPathName = context.Request.QueryString["fileName"].ToString();
}
string filename = context.Server.MapPath("~/MyPath/" + strPathName);
System.IO.Stream oStream = null;
oStream =
new System.IO.FileStream
(path: filename,
mode: System.IO.FileMode.Open,
share: System.IO.FileShare.Read,
access: System.IO.FileAccess.Read);
try
{
context.Response.ClearHeaders();
context.Response.Buffer = false;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment");
long lngFileLength = oStream.Length;
context.Response.AddHeader("Content-Length", lngFileLength.ToString());
long lngDataToRead = lngFileLength;
while (lngDataToRead > 0)
{
if (context.Response.IsClientConnected)
{
int intBufferSize = 8 * 1024;
byte[] bytBuffers =
new System.Byte[intBufferSize];
int intTheBytesThatReallyHasBeenReadFromTheStream =
oStream.Read(buffer: bytBuffers, offset: 0, count: intBufferSize);
context.Response.OutputStream.Write
(buffer: bytBuffers, offset: 0,
count: intTheBytesThatReallyHasBeenReadFromTheStream);
context.Response.Flush();
lngDataToRead =
lngDataToRead - intTheBytesThatReallyHasBeenReadFromTheStream;
}
else
{
lngDataToRead = -1;
}
}
}
catch { }
finally
{
if (oStream != null)
{
oStream.Close();
oStream.Dispose();
oStream = null;
}
context.Response.Close();
}
}
You can't directly download a file via ajax, it only returns the data into a JS variable in the page's code, instead of triggering a traditional request and download.
Your button needs to make a standard HTTP request, not an ajax call.
I am trying to ping a link using the code below and the it fails. It works fine in our development environment, but not in production. However, this a valid URL because I can copy and paste it in the browser and go to the site. Since this is in production, I cannot debug it locally on my machine. Can anyone think of what might be causing this? The issue is only with this link; other links work fine. The link I am trying is https://owl.english.purdue.edu/
System.Net.WebResponse objWebResponse = default(System.Net.WebResponse);
System.Net.WebRequest objWebRequest = System.Net.WebRequest.Create(URL);
objWebRequest.Timeout = TimeoutInMiliseconds;
try
{
PerformanceTimer.Start();
objWebResponse = objWebRequest.GetResponse();
PerformanceTimer.Finish();
try
{
this._ResponseTime = PerformanceTimer.ElapsedTime.Miliseconds;
}
catch (Exception ex)
{
string s = ex.ToString();
this._ResponseTime = -1;
}
{
this._ContentLength = objWebResponse.ContentLength;
this._ContentType = objWebResponse.ContentType;
int BytesRead = 0;
byte[] buffer = new byte[10001];
if (GetFileContent)
{
System.IO.Stream ReceiveStream = objWebResponse.GetResponseStream();
System.IO.MemoryStream MS = new System.IO.MemoryStream();
//memory stream is used so we can grab binary data
do
{
BytesRead = ReceiveStream.Read(buffer, 0, buffer.Length);
if (BytesRead <= 0) break;
MS.Write(buffer, 0, BytesRead);
}
while (true);
this._MemoryStream = MS;
ReceiveStream = null;
}
else
{
//This else is to validate the existence of the file, but not get their contents in case the file is big.
BytesRead = objWebResponse.GetResponseStream().Read(buffer, 0, buffer.Length);
if (BytesRead > 0)
{
this._MemoryStream = new System.IO.MemoryStream();
this._MemoryStream.Write(buffer, 0, BytesRead);
}
}
objWebResponse.Close();
}
functionReturnValue = true;
}
catch (System.Net.WebException ex)
{
this._Message = ex.Message;
}
catch (Exception ex2)
{
this._Message = ex2.Message;
}
objWebResponse = null;
objWebRequest = null;
PerformanceTimer = null;
return functionReturnValue;
UPDATE: Got it! Answer posted below... I will clean up the question so it may be more useful to someone else.
I have a service that uses a library to generate thumbnails from html pages using a WebBrowser control. That works fine but I need to create a WCF service that allows you to pass in a uri, then the service converts that to a thumbnail and returns it. I've tried it as a Stream and a byte[]. It creates the image in the service, I save it as a file just to prove it, but when I consume it I get data (more than I send) and I am unable to save it as a viewable image. Any suggestions would be appreciated. I am not a WCF expert so I'm hoping I've just missed something that will be easy to spot.
Here is the service, it's hosted in a console app and the Main() procedure is included.
namespace RawImageService
{
[ServiceContract]
public interface IImageServer
{
[OperationContract]
[WebInvoke(Method = "GET", UriTemplate = "/image/?uri={uri}")]
Stream HtmlToImage(string uri);
}
public class Service : IImageServer
{
public Stream HtmlToImage(string uri)
{
string path = #"D:\Templates\HtmlServiceImage.bmp";
if( File.Exists(path) )
File.Delete(path);
if (string.IsNullOrEmpty(uri))
{
return null;
}
else
{
if ((uri.IndexOf("file:", System.StringComparison.Ordinal) < 0) &&
(uri.IndexOf("http", System.StringComparison.Ordinal) < 0))
uri = "http://" + uri;
Thumbnail.Uri = uri;
try
{
Bitmap bitmap =
HtmlToThumbnail.WebsiteThumbnail.GetThumbnail(Thumbnail.Uri, Thumbnail.Width,
Thumbnail.Hight, Thumbnail.ThumbWidth,
Thumbnail.ThumbHight);
using (MemoryStream ms = new MemoryStream())
{
bitmap.Save(ms, ImageFormat.Jpeg);
bitmap.Save(path, ImageFormat.Jpeg);
ms.Position = 0;
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
return ms;
}
}
catch (Exception)
{
throw;
}
return null;
}
}
static void Main(string[] args)
{
string baseAddress = "http://" + Environment.MachineName + ":8000/";
ServiceHost host = new ServiceHost(typeof(Service), new Uri(baseAddress));
host.AddServiceEndpoint(typeof(IImageServer), new WebHttpBinding(), "").Behaviors.Add(new WebHttpBehavior());
host.Open();
Console.WriteLine("Service is running");
Console.Write("Press ENTER to close the host");
Console.ReadLine();
host.Close();
}
}
}
Here is my attempt to consume the service:
private static void Main(string[] args)
{
string uri = string.Concat("http://localhost:8000",
string.Format("/image/?uri={0}", "file:///D:/Templates/Test4.htm"));
tryThis(uri);
}
public static void tryThis(string uri)
{
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
request.Method = "GET";
// Get response
using (WebResponse response = request.GetResponse() as WebResponse)
{
using (Stream stream = response.GetResponseStream())
{
byte[] buffer = new byte[response.ContentLength];
MemoryStream ms = new MemoryStream();
int bytesRead, totalBytesRead = 0;
do
{
bytesRead = stream.Read(buffer, 0, buffer.Length);
totalBytesRead += bytesRead;
ms.Write(buffer, 0, bytesRead);
} while (bytesRead > 0);
string path = #"D:/templates/fs.jpg";
if (File.Exists(path))
File.Delete(path);
var fs = new FileStream(path, FileMode.Create);
fs.Write(ms.ToArray(), 0, totalBytesRead);
fs.Flush();
fs.Close();
}
}
}
static byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
There is nothing additional in the .config files. I'm going to start looking into that but my understanding is I can configure everything in the app itself.
I don't care which way I get it working, I just need to get it working. I appreciate any suggestions. Thanks.
I got the Stream method working. Here is the code. I can access it like this:
http://localhost:8000/image/?uri=file:///D:/Templates/Test4.htm
Here is the new method. If you replace the code above with this it works.
public Stream HtmlToImage(string uri)
{
string path = #"D:\Templates\HtmlServiceImage.bmp";
if( File.Exists(path) )
File.Delete(path);
if (string.IsNullOrEmpty(uri))
{
return null;
}
else
{
if ((uri.IndexOf("file:", System.StringComparison.Ordinal) < 0) &&
(uri.IndexOf("http", System.StringComparison.Ordinal) < 0))
uri = "http://" + uri;
Thumbnail.Uri = uri;
try
{
Bitmap bitmap =
HtmlToThumbnail.WebsiteThumbnail.GetThumbnail(Thumbnail.Uri, Thumbnail.Width,
Thumbnail.Hight, Thumbnail.ThumbWidth,
Thumbnail.ThumbHight);
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
ms.Position = 0;
WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";
return ms;
}
catch (Exception)
{
throw;
}
return null;
}
}
I have a bit of code that uses a Task to transfer a file over a web service. However if the network drops or a timeout occurs it results in an incomplete file. I'm really trying to make this service as reliable as possible, but I'm not really sure where to even really start to add code that will trap when a chunk was not sent, and then attempt to resend it multiple times but also not send the next chunk until that is done. And maybe if it cannot resend that chunk over X times, fail completely and log an event.
Can anyone suggest anything?
Action<Guid, string> action = (smGuid, pubAttFullPath) =>
{
try
{
//Set filename from object
string FileName;
FileName = System.IO.Path.GetFileName(pubAttFullPath.ToString());
//Declare Web Service
TransferFile.TransferFileSoapClient ws_TransferFile = new TransferFile.TransferFileSoapClient();
//
bool transfercompleted = false;
using (FileStream fs = new FileStream(
pubAttFullPath.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
//Declare Buffers and Counts
byte[] buffer = new byte[49152];
long fileSize = fs.Length;
long totalReadCount = 0;
int readCount;
float percentageComplete = 0;
//Loop and copy file until it changes to not exactly the same byte count as the buffer
//which means the file is about to complete.
while ((readCount = fs.Read(buffer, 0, buffer.Length)) > 0)
{
if (!transfercompleted)
{
totalReadCount += readCount;
byte[] bytesToTransfer;
if (readCount == buffer.Length)
{
//Copy bytes until buffer is different
bytesToTransfer = buffer;
ws_TransferFile.WriteBinaryFile("ABCD", bytesToTransfer, FileName);
percentageComplete = (totalReadCount / (float)fileSize * 100);
percentageComplete = (float)Math.Round(percentageComplete, 2, MidpointRounding.ToEven);
//Update progress to DB
InsertProgress.InsertProgressSoapClient ws_InsertProgress = new InsertProgress.InsertProgressSoapClient();
if (percentageComplete == 10.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 10.0);
}
if (percentageComplete == 20.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 20.0);
}
if (percentageComplete == 30.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 30.0);
}
if (percentageComplete == 40.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 40.0);
}
if (percentageComplete == 50.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 50.0);
}
if (percentageComplete == 60.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 60.0);
}
if (percentageComplete == 70.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 70.0);
}
if (percentageComplete == 80.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 80.0);
}
if (percentageComplete == 90.00)
{
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 90.0);
}
}
else
{
// Only a part is requred to upload,
// copy that part.
List<byte> b = new List<byte>(buffer);
bytesToTransfer = b.GetRange(0, readCount).ToArray();
ws_TransferFile.WriteBinaryFile("ABCD", bytesToTransfer, FileName);
percentageComplete = 100;
//Insert Progress as complete
InsertProgress.InsertProgressSoapClient ws_InsertProgress = new InsertProgress.InsertProgressSoapClient();
ws_InsertProgress.InsertProgressService(smGuid.ToString(), 100);
transfercompleted = true;
fs.Close();
break;
}
}
}
}
}
catch (Exception ex)
{
EventLog.WriteEntry("Application", ex.Message.ToString(), EventLogEntryType.Error);
}
Web service is bad idea for file transfer. I used it few times, but amount of additional data transfered is making size of transfered data 1,5-2 times bigger then sending file using simple handler. Handler will allow you to the same without issues. It causes al lot of problem with proper progress handling and resume. You realy should reconsider using httphandler. If you like to use webservice, here is good example:
http://msdn.microsoft.com/en-us/library/ms172362%28v=vs.85%29.aspx
If you decide to use IHttpHandler see:
http://msdn.microsoft.com/en-us/library/ms228090%28v=vs.100%29.aspx
And then you can use following piece of code to proper handle retry/resume:
using (Stream stream = new FileStream(
pubAttFullPath.ToString(),
FileMode.Open,
FileAccess.Read,
FileShare.Read))
{
context.Response.AddHeader("Accept-Ranges", "bytes");
context.Response.Buffer = false;
if (context.Request.Headers["Range"] != null)
{
context.Response.StatusCode = 206;
string[] range = context.Request.Headers["Range"].Split(new[] { '=', '-' });
startBytes = Convert.ToInt32(range[1]);
}
int dataToRead = size - startBytes;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Length", dataToRead.ToString());
context.Response.AddHeader("Connection", "Keep-Alive");
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8));
if (startBytes > 0)
{
context.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, size - 1, size));
stream.Seek(startBytes, SeekOrigin.Begin);
}
while (dataToRead > 0)
{
// Verify that the client is connected.
if (context.Response.IsClientConnected)
{
// Read the data in buffer.
int length = stream.Read(buffer, 0, buffer.Length);
// Write the data to the current output stream.
context.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
context.Response.Flush();
dataToRead = dataToRead - length;
}
else
{
// prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
I'm saving an image from a web request and something really weird is happening. On roughly half of the 8,000 images I'm downloading I get IOEXCEPTION errors:
ERROR_ACCESS_DENIED (5)
INVALID_PARAMETER (87)
Before I save the file using file.open, I check to make sure the file does not exist. The exception is thrown at this line of code:
fileStream = File.Open(destination, FileMode.Create, FileAccess.Write, FileShare.None);
Below is the code:
public static bool DownloadFile(string url, string destination)
{
bool success = false;
System.Net.HttpWebRequest request = null;
System.Net.WebResponse response = null;
Stream responseStream = null;
FileStream fileStream = null;
try
{
request = (System.Net.HttpWebRequest)System.Net.WebRequest.Create(url);
request.Method = "GET";
request.Timeout = 100000; // 100 seconds
request.Proxy = System.Net.GlobalProxySelection.GetEmptyWebProxy();
response = request.GetResponse();
responseStream = response.GetResponseStream();
fileStream = File.Open(destination, FileMode.Create, FileAccess.Write, FileShare.None);
//fileStream = File.Create(destination);
// read up to ten kilobytes at a time
int maxRead = 10240;
byte[] buffer = new byte[maxRead];
int bytesRead = 0;
int totalBytesRead = 0;
// loop until no data is returned
while ((bytesRead = responseStream.Read(buffer, 0, maxRead)) > 0)
{
totalBytesRead += bytesRead;
fileStream.Write(buffer, 0, bytesRead);
}
// we got to this point with no exception. Ok.
success = true;
}
catch (System.Net.WebException we)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(exp.ToString());
writeErrFile(we.ToString(), url);
//Debug.WriteLine(exp);
}
catch (System.IO.IOException ie)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(ie.InnerException.ToString());
writeErrFile(ie.ToString(), destination + " -- " + url);
//Debug.WriteLine(exp);
}
catch (Exception exp)
{
// something went terribly wrong.
success = false;
//MessageBox.Show(exp.ToString());
writeErrFile(exp.ToString(), destination + " -- " + url);
//Debug.WriteLine(exp);
}
finally
{
// cleanup all potentially open streams.
if (null != responseStream)
responseStream.Close();
if (null != response)
response.Close();
if (null != fileStream)
fileStream.Close();
}
// if part of the file was written and the transfer failed, delete the partial file
if (!success && File.Exists(destination))
File.Delete(destination);
return success;
}
I've been stuck on this for a couple of days. Any help would be appreciated in unimaginable orders of magnitude.
Use file.exists() to check if the file exists and file.create or file.openwrite to write the file.
From your code I can't see how you are checking the file exists.