Remote File Upload Through ASP .Net page
-
I have an interesting issue; I have been tasked with building a "one size fits all" file upload page. I am using C# and the 4.5 framework, so my options are wide open, but I have one problem in particular... Part of the requirement involves an old upload page; we already have a page that uses a regular file upload control with a button and it works exactly as expected. Here's what I need to do; the page I need to build needs to access the old page in the background and do the following: Upload the selected file Return the message displayed by the old page So I need to build a page that allows the user to select a file and "upload" it by accessing the older page in the background and pass the file and/or file information to it. I do not have access to the code of the old page, so I have to use the new page to handle all of the work. So far I have played with code I have found using HttpWebRequest,WebClient and even the .net libraries for cURL with no success. Has anyone tackled something similar in the past? Any suggestions?
______________________ Oh Hamburgers!
-
I have an interesting issue; I have been tasked with building a "one size fits all" file upload page. I am using C# and the 4.5 framework, so my options are wide open, but I have one problem in particular... Part of the requirement involves an old upload page; we already have a page that uses a regular file upload control with a button and it works exactly as expected. Here's what I need to do; the page I need to build needs to access the old page in the background and do the following: Upload the selected file Return the message displayed by the old page So I need to build a page that allows the user to select a file and "upload" it by accessing the older page in the background and pass the file and/or file information to it. I do not have access to the code of the old page, so I have to use the new page to handle all of the work. So far I have played with code I have found using HttpWebRequest,WebClient and even the .net libraries for cURL with no success. Has anyone tackled something similar in the past? Any suggestions?
______________________ Oh Hamburgers!
-
Vodstok wrote:
Return the message displayed by the old page
What is the message, why is it so important.
The new page is being built to integrate two old pages into a new interface, so for end users accustomed to the old functionality, they want to be able to present them with the message(s) that the old one did to minimize the changes in how they see things. Basically, it's out of my hands why, it's in the spec so I have to. There is a new solution in the works, but for the time being, I am tasked with making a new page that "operates" the old page in the background.
______________________ Oh Hamburgers!
-
I have an interesting issue; I have been tasked with building a "one size fits all" file upload page. I am using C# and the 4.5 framework, so my options are wide open, but I have one problem in particular... Part of the requirement involves an old upload page; we already have a page that uses a regular file upload control with a button and it works exactly as expected. Here's what I need to do; the page I need to build needs to access the old page in the background and do the following: Upload the selected file Return the message displayed by the old page So I need to build a page that allows the user to select a file and "upload" it by accessing the older page in the background and pass the file and/or file information to it. I do not have access to the code of the old page, so I have to use the new page to handle all of the work. So far I have played with code I have found using HttpWebRequest,WebClient and even the .net libraries for cURL with no success. Has anyone tackled something similar in the past? Any suggestions?
______________________ Oh Hamburgers!
Is the old page written in ASP.NET? If so, you'll probably have to issue a
GET
request first, find the hidden view-state and event validation fields, and include those fields in yourPOST
request. Once you've got the data you need to send, you'll need to build and send amultipart/form-data
request. Unfortunately, there's no built-in way to do that prior to .NET 4.5, but there are quite a few examples floating around for earlier versions. Eg: UploadFileEx: C#'s WebClient.UploadFile with more functionality[^] If you're using .NET 4.5, you can use the new HttpClient[^] class from the System.Net.Http[^] assembly, combined with the MultipartFormDataContent[^] class.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Is the old page written in ASP.NET? If so, you'll probably have to issue a
GET
request first, find the hidden view-state and event validation fields, and include those fields in yourPOST
request. Once you've got the data you need to send, you'll need to build and send amultipart/form-data
request. Unfortunately, there's no built-in way to do that prior to .NET 4.5, but there are quite a few examples floating around for earlier versions. Eg: UploadFileEx: C#'s WebClient.UploadFile with more functionality[^] If you're using .NET 4.5, you can use the new HttpClient[^] class from the System.Net.Http[^] assembly, combined with the MultipartFormDataContent[^] class.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
The new page is being built to integrate two old pages into a new interface, so for end users accustomed to the old functionality, they want to be able to present them with the message(s) that the old one did to minimize the changes in how they see things. Basically, it's out of my hands why, it's in the spec so I have to. There is a new solution in the works, but for the time being, I am tasked with making a new page that "operates" the old page in the background.
______________________ Oh Hamburgers!
-
Is the old page written in ASP.NET? If so, you'll probably have to issue a
GET
request first, find the hidden view-state and event validation fields, and include those fields in yourPOST
request. Once you've got the data you need to send, you'll need to build and send amultipart/form-data
request. Unfortunately, there's no built-in way to do that prior to .NET 4.5, but there are quite a few examples floating around for earlier versions. Eg: UploadFileEx: C#'s WebClient.UploadFile with more functionality[^] If you're using .NET 4.5, you can use the new HttpClient[^] class from the System.Net.Http[^] assembly, combined with the MultipartFormDataContent[^] class.
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Okay, so I have a question; I am doing a get, scraping out the event validation and viewstate to send back, but when I try to post back to the page, I am getting what appears to be a non-posted page on the other end. Since I can't seem to reuse the original request, the page I get has different viewstate information, so I'm not getting the post I hoped (I think that is what is happening anyway). I am definitely hitting the page; I am doing a Response.Write for the returned content and it is definitely loading the correct page in the background. I seem to be back at square one (albeit using the baked-in features of 4.5, which is nice :)). So I am definitely calling the right page, but it does not appear to actually post. Here is the code I am using:
//First call to get the hidden fields from the page HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(@"http://localhost:51749/Default.aspx"); request.Method = "GET"; request.ContentType = "application/x-www-form-urlencoded"; HttpWebResponse resp = (HttpWebResponse)request.GetResponse(); string respString = string.Empty; using (Stream strm = resp.GetResponseStream()) { using (StreamReader sr = new StreamReader(strm)) { respString = sr.ReadToEnd(); } } request = (HttpWebRequest)HttpWebRequest.Create(@"http://localhost:51749/Default.aspx"); List controls = respString.Split('\\n').Select(o => o.Replace("\\r", string.Empty).Trim()).Where(o => o.StartsWith("<input") && o.IndexOf("hidden") > -1).ToList(); request.Method = "POST"; request.ContentType = "multipart/form-data"; //copied from StackOverflow and updated to hit my URL using (HttpClient client = new HttpClient()) { using (MultipartFormDataContent content = new MultipartFormDataContent()) { var values = new\[\] { new KeyValuePair("txtFile", "BALHHHHH"), new KeyValuePair("fu1", fileName), }.ToList(); foreach (string cont in controls) { List attributes = cont.Split(' ').Whe
-
Okay, so I have a question; I am doing a get, scraping out the event validation and viewstate to send back, but when I try to post back to the page, I am getting what appears to be a non-posted page on the other end. Since I can't seem to reuse the original request, the page I get has different viewstate information, so I'm not getting the post I hoped (I think that is what is happening anyway). I am definitely hitting the page; I am doing a Response.Write for the returned content and it is definitely loading the correct page in the background. I seem to be back at square one (albeit using the baked-in features of 4.5, which is nice :)). So I am definitely calling the right page, but it does not appear to actually post. Here is the code I am using:
//First call to get the hidden fields from the page HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(@"http://localhost:51749/Default.aspx"); request.Method = "GET"; request.ContentType = "application/x-www-form-urlencoded"; HttpWebResponse resp = (HttpWebResponse)request.GetResponse(); string respString = string.Empty; using (Stream strm = resp.GetResponseStream()) { using (StreamReader sr = new StreamReader(strm)) { respString = sr.ReadToEnd(); } } request = (HttpWebRequest)HttpWebRequest.Create(@"http://localhost:51749/Default.aspx"); List controls = respString.Split('\\n').Select(o => o.Replace("\\r", string.Empty).Trim()).Where(o => o.StartsWith("<input") && o.IndexOf("hidden") > -1).ToList(); request.Method = "POST"; request.ContentType = "multipart/form-data"; //copied from StackOverflow and updated to hit my URL using (HttpClient client = new HttpClient()) { using (MultipartFormDataContent content = new MultipartFormDataContent()) { var values = new\[\] { new KeyValuePair("txtFile", "BALHHHHH"), new KeyValuePair("fu1", fileName), }.ToList(); foreach (string cont in controls) { List attributes = cont.Split(' ').Whe
Based on a quick test I did last night, I came to the conclusion that the
Name
of each part needs to be enclosed in quotes:foreach (KeyValuePair<string, string> keyValuePair in values)
{
content.Add(new StringContent(keyValuePair.Value), "\"" + keyValuePair.Key + "\"");
}Without this, ASP.NET doesn't think there's a form present. (I'm not sure if this is a bug in ASP.NET, a bug in the
HttpClient
implementation, or a misunderstanding on my part.) You'll need to specify thename
for the file content, which should be equal to the name of theFileUpload
control on the target page. I also found that if theFileName
isn't enclosed in quotes, ASP.NET request validation rejects the request:ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(fileName));
content.Add(fileContent, "\"nameOfTheFileUpload\"", "\"" + Path.GetFileName(fileName) + "\"");
// This overload of Add automatically creates the Content-Disposition header.You're missing an
await
on theclient.PostAsync
line, but I presume that's just a typo. You can also replace theReadAsStream
+Read
+Encoding.ASCII.GetString
block with a simpleawait response.Content.ReadAsStringAsync()
call. If all else fails, you can always trace the request with Fiddler[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
-
Based on a quick test I did last night, I came to the conclusion that the
Name
of each part needs to be enclosed in quotes:foreach (KeyValuePair<string, string> keyValuePair in values)
{
content.Add(new StringContent(keyValuePair.Value), "\"" + keyValuePair.Key + "\"");
}Without this, ASP.NET doesn't think there's a form present. (I'm not sure if this is a bug in ASP.NET, a bug in the
HttpClient
implementation, or a misunderstanding on my part.) You'll need to specify thename
for the file content, which should be equal to the name of theFileUpload
control on the target page. I also found that if theFileName
isn't enclosed in quotes, ASP.NET request validation rejects the request:ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(fileName));
content.Add(fileContent, "\"nameOfTheFileUpload\"", "\"" + Path.GetFileName(fileName) + "\"");
// This overload of Add automatically creates the Content-Disposition header.You're missing an
await
on theclient.PostAsync
line, but I presume that's just a typo. You can also replace theReadAsStream
+Read
+Encoding.ASCII.GetString
block with a simpleawait response.Content.ReadAsStringAsync()
call. If all else fails, you can always trace the request with Fiddler[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
Most excellent, I am not quite there yet, but considering all of the annoying viewstate errors I am now getting (I appear to need the same machine key for both test sites) I am definitely getting farther than I was. I will update as soon as I get it figured out. Thank you again! This has been a huge help.
______________________ Oh Hamburgers!
-
Based on a quick test I did last night, I came to the conclusion that the
Name
of each part needs to be enclosed in quotes:foreach (KeyValuePair<string, string> keyValuePair in values)
{
content.Add(new StringContent(keyValuePair.Value), "\"" + keyValuePair.Key + "\"");
}Without this, ASP.NET doesn't think there's a form present. (I'm not sure if this is a bug in ASP.NET, a bug in the
HttpClient
implementation, or a misunderstanding on my part.) You'll need to specify thename
for the file content, which should be equal to the name of theFileUpload
control on the target page. I also found that if theFileName
isn't enclosed in quotes, ASP.NET request validation rejects the request:ByteArrayContent fileContent = new ByteArrayContent(File.ReadAllBytes(fileName));
content.Add(fileContent, "\"nameOfTheFileUpload\"", "\"" + Path.GetFileName(fileName) + "\"");
// This overload of Add automatically creates the Content-Disposition header.You're missing an
await
on theclient.PostAsync
line, but I presume that's just a typo. You can also replace theReadAsStream
+Read
+Encoding.ASCII.GetString
block with a simpleawait response.Content.ReadAsStringAsync()
call. If all else fails, you can always trace the request with Fiddler[^].
"These people looked deep within my soul and assigned me a number based on the order in which I joined." - Homer
The plot thickens. The page I will eventually have to call is written in JSP, which is of no immediate concern since the basic idea behind this requirement doesn't change, but here's where it gets interesting; the page I am calling uses JavaScript to set the cookies, and the page login immediately fails unless it's executed. So I'm not only not back to square one, it's not even on the horizon right now. Gotta love legacy products...
______________________ Oh Hamburgers!