Sending Attachment to HttpRequest POST C# - c#

I'm trying to send an attachment using HttpRequest, but the server give me a 500 Internal Server Error.
If i make the same call from SOAP UI, it will success with this result.
HTTP/1.1 200 OK Date: Fri, 30 Apr 2021 13:47:00 GMT Server: Apache Strict-Transport-Security: max-age=63072000; includeSubDomains;
preload Keep-Alive: timeout=5, max=100 Connection: Keep-Alive
Transfer-Encoding: chunked Content-Type: multipart/related;
boundary="MIMEBoundary_ccc0c7786f280ccc7fb981fb343b4463e574457582881961";
type="application/xop+xml";
start="0.dcc0c7786f280ccc7fb981fb343b4463e574457582881961#apache.org";
start-info="text/xml"
--MIMEBoundary_ccc0c7786f280ccc7fb981fb343b4463e574457582881961 Content-Type: application/xop+xml; charset=UTF-8; type="text/xml"
Content-Transfer-Encoding: binary Content-ID:
0.dcc0c7786f280ccc7fb981fb343b4463e574457582881961#apache.org
xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
...</soapenv:Envelope>
--MIMEBoundary_ccc0c7786f280ccc7fb981fb343b4463e574457582881961--
So i'm mistaking the link between soap request and attachment.
What could be the error inside the code?
The code is called by a c# Web Api and is calling a SOAP POST resource.
public static string Start()
{
var _url = "...";
var _action = "...";
XmlDocument soapEnvelopeXml = SoapEnvelope();
HttpWebRequest webRequest = CreateWebRequest(_url, _action);
InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);
// begin async call to web request.
IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);
// suspend this thread until call is complete. You might want to
// do something usefull here like update your UI.
asyncResult.AsyncWaitHandle.WaitOne();
// get the response from the completed web request.
string soapResult;
using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
{
using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
{
soapResult = rd.ReadToEnd();
}
Console.Write(soapResult);
}
return "";
}
private static XmlDocument SoapEnvelope()
{
XmlDocument soapEnvelopeDocument = new XmlDocument();
soapEnvelopeDocument.LoadXml(
#"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/""
....
</soapenv:Envelope>");
return soapEnvelopeDocument;
}
public static HttpWebRequest CreateWebRequest(string url, string action)
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Headers.Add("SOAPAction", action);
webRequest.ContentType = "text/xml;charset=\"utf-8\"";
webRequest.Accept = "text/xml";
webRequest.Method = "POST";
return webRequest;
}
private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
{
using (Stream stream = webRequest.GetRequestStream())
{
var data = GetFromData("dummy.pdf", #"C:\dummy.pdf", webRequest);
stream.Write(data, 0, data.Length);
soapEnvelopeXml.Save(stream);
}
}
public static byte[] GetFromData(string fileName, string filePath, HttpWebRequest request)
{
var attachment = System.IO.File.ReadAllBytes(filePath);
string boundaryString = Guid.NewGuid().ToString();
MemoryStream postDataStream = new MemoryStream();
StreamWriter postDataWriter = new StreamWriter(postDataStream);
request.ContentType = "multipart/form-data; boundary=" + boundaryString;
postDataWriter.Write("\r\n--" + boundaryString + "\r\n");
postDataWriter.Flush();
postDataWriter.Write("Content-Disposition: form-data; name=\"{0}\"; filename=\"{1}\"\r\nContent-Type: {2}\r\n\r\n", "file", fileName, MimeMapping.GetMimeMapping(fileName));
postDataWriter.Flush();
postDataStream.Write(attachment, 0, attachment.Length);
postDataWriter.Write("\r\n--" + boundaryString + "--\r\n");
postDataWriter.Flush();
return postDataStream.ToArray();
}
Thank you

Related

Document Moved 201 Remove from WebResponse

I use .NET 4.61. Can I get the response from https://1106-7916.el-alt.com/wp-json/wc/v2/products/407 instead of https://1106-7916.el-alt.com/wp-json/wc/v2/products, which causes a redirect? Can I add code to BuildRequest, shown below, to get that response automatically?
I am using the WooCommerce REST API to create products. Here is my request:
POST-https://1106-7916.el-alt.com/wp-json/wc/v2/products?consumer_key=X
{"attributes":[{"name":"Color","visible":true,"variation":true,"options":["Red","Blue","Green","Orange"]},{"name":"Size","visible":true,"variation":true,"options":["S","M","L"]}],"title":"FooFoo","sku":"TestCreateProductWoo1026","description":"Test","categories":[],"tags":[],"type":"variable"}
Here is the response:
HTTP/1.1 201 Created
Cache-Control: no-cache, must-revalidate, max-age=0
Allow: GET, POST
Location: https://1106-7916.el-alt.com/wp-json/wc/v2/products/407
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found here</body>{"id":407,"name":"Product","slug":"product"}
Here is my code:
private string BuildRequest(string path, IDictionary<string, string> query, HttpMethodTypes httpMethod, object body)
{
string pathAndQuery = BuildParameters(path, query);
string resultData = string.Empty;
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(pathAndQuery);
myHttpWebRequest.Accept = "application/json";
myHttpWebRequest.ContentType = "application/json";
myHttpWebRequest.UserAgent = "JMA Web Technologies";
myHttpWebRequest.AllowAutoRedirect = true;
SetHeaders(myHttpWebRequest);
if (httpMethod != HttpMethodTypes.GET)
myHttpWebRequest.Method = httpMethod.ToString();
SetResponseBody(body, myHttpWebRequest);
WebResponse httpResponse = myHttpWebRequest.GetResponse();
Stream responseStream = httpResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
resultData = reader.ReadToEnd();
responseStream.Close();
httpResponse.Close();
return resultData;
}
Any help is greatly appreciated.

Send json data to remote server for authentication

I want to post authentication details to a remote server, sending username, database name and password. My server is running on Ubuntu. But i get error Invalid JSON data: ''
"POST / HTTP/1.1" 400 -
I am new to working on this platform, help me with where i am doing it wrong. Below is my code:
private void SendDataButton_Click(object sender, RoutedEventArgs e)
{
string url = "http://200.84.100.211:9875";
string call = url + "/web/session/authenticate";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(call) as HttpWebRequest;
request.ContentType = "application/json";
request.Method = "POST";
request.BeginGetResponse(new AsyncCallback(SendData), request);
}
void SendData(IAsyncResult callbackResult)
{
HttpWebRequest myRequest = (HttpWebRequest)callbackResult.AsyncState;
Stream postStream = myRequest.EndGetRequestStream(callbackResult);
string postData = "{'db':'demo_shruti','login':'admin','password':'admin'}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
myRequest.BeginGetResponse(new AsyncCallback(FinishWebRequest), myRequest);
}
void FinishWebRequest(IAsyncResult callbackResult)
{
HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
string responseString = "";
Stream streamResponse = response.GetResponseStream();
StreamReader reader = new StreamReader(streamResponse);
responseString = reader.ReadToEnd();
streamResponse.Close();
reader.Close();
response.Close();
string result = responseString;
}

Get data on error with HttpWebRequest

While interacting with an API there is a situation where they will return a 401 response that also contains data. I would like to return this data regardless of the error code of the response.
I have created a function to submit a either a GET or POST using HttpWebRequest that returns a string containing the response data. The only problem is that if the response is a 401, an error is thrown and the data is not read.
Here is an example of what is returned:
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Credentials: false
Content-Type: application/json; charset=UTF-8
Date: Tue, 19 May 2015 17:56:10 GMT
Vary: Accept-Encoding
Vary: Accept-Encoding
Content-Length: 254
Connection: keep-alive
{"status":"error","message":"access_token (...) was deleted (at Tue May 19 17:52:49 UTC 2015). Use your refresh token (if you have one) to generate a new access_token.","requestId":"..."}
Here is what I have for my function so far:
private string SendHttpRequest(string url, out int statusCode, string method = "GET", object postData = null, string contentType = "application/json")
{
bool isPost = method.Equals("POST", StringComparison.CurrentCultureIgnoreCase);
byte[] content = new ASCIIEncoding().GetBytes(isPost ? JsonConvert.SerializeObject(postData) : "");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = method;
request.ContentType = contentType;
request.ContentLength = postData == null ? 0 : content.Length;
if (isPost && postData != null)
{
Stream reqStream = request.GetRequestStream();
reqStream.Write(content, 0, content.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Throws error here
string result;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
statusCode = (int)response.StatusCode;
response.Close();
return result;
}
How can I still get the data for a 401 response? There is no requirement to use HttpWebRequest, that is just what I have been using so far.
The call to GetResponse is throwing a WebException. You can catch that exception and extract the response via the exception's Response property:
private string SendHttpRequest(string url, out int statusCode, string method = "GET", object postData = null, string contentType = "application/json")
{
bool isPost = method.Equals("POST", StringComparison.CurrentCultureIgnoreCase);
byte[] content = new ASCIIEncoding().GetBytes(isPost ? JsonConvert.SerializeObject(postData) : "");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = method;
request.ContentType = contentType;
request.ContentLength = postData == null ? 0 : content.Length;
if (isPost && postData != null)
{
Stream reqStream = request.GetRequestStream();
reqStream.Write(content, 0, content.Length);
}
HttpWebResponse response = null;
//Get the response via request.GetResponse, but if that fails,
//retrieve the response from the exception
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse)ex.Response;
}
string result;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
statusCode = (int)response.StatusCode;
response.Close();
return result;
}

C# Upload file error - Corrupt form data: no leading boundary

I am using this code below to authenticate and upload file to a website, but I am getting an error "Corrupt form data: no leading boundary".
In the Fiddler I see this, ( I see the exact same thing when I upload the file using browser), not sure why I am getting an error when I am doing using C# HttpWebRequest/WebClient
Fiddler Info:
------WebKitFormBoundary9ewWOMyBmk0YAhTL
Content-Disposition: form-data; name="FileSubmitted"; filename="SAMPLE_0001.xls"
Content-Type: application/vnd.ms-excel
------WebKitFormBoundary9ewWOMyBmk0YAhTL
Content-Disposition: form-data; name="FileSubmittedValue"
C:\path\SAMPLE_0001.xls
------WebKitFormBoundary9ewWOMyBmk0YAhTL--
Assumptions:
I hard coded the 'boundary' value, because I am not sure how to get the 'boundary' value after login.
Code: Copied from Stackoverflow
static void Main()
{
NameValueCollection nvCollection = new NameValueCollection();
CookieAwareWebClient webClient = new CookieAwareWebClient();
nvCollection.Clear();
nvCollection["Name"] = "ABC";
nvCollection["Password"] = "XYZ";
//Login to the Site
byte[] responseBytes = webClient.UploadValues("https://www.somesite.com/login.cfm", "POST", nvCollection);
string resultAuthTicket = Encoding.UTF8.GetString(responseBytes);
//Get Cookies
CookieCollection cookies = webClient.CookieContainer.GetCookies(new Uri("https://www.somesite.com/login.cfm"));
//
string URL = "https://www.somesite.com/app/request.cfm";
string boundary = "----WebKitFormBoundary9ewWOMyBmk0YAhTL";
string FilePath = "C:\\Users\\user.name\\Desktop\\SAMPLE_0001.xls";
byte[] fileData = GetMultipartFormData(new Dictionary<string, object>() { { "FileSubmitted", FilePath } }, boundary);
PostForm(URL, "", "", fileData, boundary, cookies);
}
private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
{
Encoding encoding = Encoding.UTF8;
Stream formDataStream = new System.IO.MemoryStream();
bool needsCLRF = false;
foreach (var param in postParameters)
{
// Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
// Skip it on the first parameter, add it to subsequent parameters.
if (needsCLRF)
formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));
needsCLRF = true;
{
string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
boundary,
param.Key,
param.Value,
"application/vnd.ms-excel");
formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
string postData2 = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\" \r\n\r\n{2}",
boundary,
"FileSubmittedValue",
"C:\\path\\SAMPLE_0001.xls");
formDataStream.Write(encoding.GetBytes(postData2), 0, encoding.GetByteCount(postData2));
}
}
// Add the end of the request. Start with a newline
string footer = "\r\n--" + boundary + "--\r\n";
formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));
// Dump the Stream into a byte[]
formDataStream.Position = 0;
byte[] formData = new byte[formDataStream.Length];
formDataStream.Read(formData, 0, formData.Length);
formDataStream.Close();
return formData;
}
private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData, string boundary, CookieCollection cookies)
{
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
if (request == null)
{
throw new NullReferenceException("request is not a http request");
}
// Set up the request properties.
request.UserAgent = userAgent;
request.ContentLength = formData.Length;
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.KeepAlive = true;
request.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";
request.CookieContainer = new CookieContainer();
request.CookieContainer.Add(cookies);
request.Host = "secure.somesite.com";
request.Referer = String.Format("https://secure.somesite.com/app/request.cfm?CFID={0}&CFTOKEN={1}", cookies[0].Value, cookies[1].Value);
request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36";
// Send the form data to the request.
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(formData, 0, formData.Length);
requestStream.Close();
}
try
{
return request.GetResponse() as HttpWebResponse;
}
catch (WebException wex)
{
var pageContent = new StreamReader(wex.Response.GetResponseStream())
.ReadToEnd();
return null;
}
return null;
}
Error:
<head><title>JRun Servlet Error</title></head><h1>500 </h1><body>
<pre>
Corrupt form data: no leading boundary: != ------WebKitFormBoundary9ewWOMyBmk0YAhTL</pre><br><pre>
java.io.IOException: Corrupt form data: no leading boundary: != ------WebKitFormBoundary9ewWOMyBmk0YAhTL
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:176)
at com.oreilly.servlet.multipart.MultipartParser.<init>(MultipartParser.java:95)
at coldfusion.filter.FormScope.fillMultipart(FormScope.java:170)
at coldfusion.filter.FusionContext.SymTab_initForRequest(FusionContext.java:435)
at coldfusion.filter.GlobalsFilter.invoke(GlobalsFilter.java:33)
at coldfusion.filter.DatasourceFilter.invoke(DatasourceFilter.java:22)
at coldfusion.filter.RequestThrottleFilter.invoke(RequestThrottleFilter.java:126)
at coldfusion.CfmServlet.service(CfmServlet.java:175)
at coldfusion.bootstrap.BootstrapServlet.service(BootstrapServlet.java:89)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:86)
at coldfusion.monitor.event.MonitoringServletFilter.doFilter(MonitoringServletFilter.java:42)
at coldfusion.bootstrap.BootstrapFilter.doFilter(BootstrapFilter.java:46)
at jrun.servlet.FilterChain.doFilter(FilterChain.java:94)
at jrun.servlet.FilterChain.service(FilterChain.java:101)
at jrun.servlet.ServletInvoker.invoke(ServletInvoker.java:106)
at jrun.servlet.JRunInvokerChain.invokeNext(JRunInvokerChain.java:42)
at jrun.servlet.JRunRequestDispatcher.invoke(JRunRequestDispatcher.java:286)
at jrun.servlet.ServletEngineService.dispatch(ServletEngineService.java:543)
at jrun.servlet.jrpp.JRunProxyService.invokeRunnable(JRunProxyService.java:203)
at jrunx.scheduler.ThreadPool$ThreadThrottle.invokeRunnable(ThreadPool.java:428)
at jrunx.scheduler.WorkerThread.run(WorkerThread.java:66)
</pre></body>
Don't Knows: Since I copied this source code from Stackoverflow, I don't know if the file really getting uploaded to C:\Path folder on server (look at the Fiddler data).
Update: When I try to upload file using browser I see Content-Length: 49504, but when I try using C# program Content-Length: 385 (Even when I use the same file in both browser and C# program)
Also, when I try now I am getting "No data was received in the uploaded file SAMPLE_0001.xls"
The code is missing this line of code, which is the actual file content.
formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
Thanks all for your help!

Send POST request to apache server with htaccess using WebClient

I've got a problem with sending POST request to the apache server with htaccess using WebClient (I've tryed to using HttpRequest as well as WebRequest but it had the same result).
I've got the following example from vendor on PHP:
$soap = curl_init(url);
curl_setopt($soap, CURLOPT_POST, 1);
curl_setopt($soap, CURLOPT_RETURNTRANSFER, 1);
$XML = file_get_contents("test.xml");
$request = <<<XML
$XML
XML;
curl_setopt($soap, CURLOPT_HTTPHEADER, array('Content-Type: text/xml; charset=utf-8', 'Content-Length: '.strlen($request)));
curl_setopt($soap, CURLOPT_POSTFIELDS, $request);
$response = curl_exec($soap);
curl_close($soap);
My version on C# is:
public static string Post(string login, string password, string url, string content) {
var result = String.Empty;
var uri = new Uri(url);
using (var client = new WebClient()) {
client.Credentials = new NetworkCredential(login, password);
client.Encoding = Encoding.UTF8;
client.Headers[HttpRequestHeader.ContentType] = "text/xml; charset=UTF-8";
client.Headers[HttpRequestHeader.Accept] = "application/xml";
result = client.UploadString(uri, content);
}
return result;
}
When I run the program I've got an exception with 400 error (bad request). I've sniff the request using Fiddler2 and found the following error message: "Request header field is missing ':' separator"
Can anyone help me found what is wrong in the request and why a server reject the request?
P.S: Request header
POST http://production.is.topdelivery.ru/tests/xmlGate/index.php HTTP/1.1
Content-Type: text/xml; charset=utf-8
Authorization: Basic YmFiYWR1OmJhYmFkdXBhc3M=
Host: production.is.topdelivery.ru
Content-Length: 1617
Expect: 100-continue
In my case following code works properly
private string post(string content)
{
var result = String.Empty;
var uri = new Uri(_url);
WebRequest req = HttpWebRequest.Create(uri);
req.Method = "POST";
req.ContentType = "text/xml";
String encoded = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("user:pass"));
req.Headers.Add("Authorization", "Basic " + encoded);
using (var s = req.GetRequestStream())
using (var sw = new StreamWriter(s, Encoding.UTF8))
{
sw.Write(content);
}
using (var s = req.GetResponse().GetResponseStream())
using (var sr = new StreamReader(s, Encoding.UTF8))
{
result = sr.ReadToEnd();
};
return result;
}
This helped me. I was having an issue with a newer release of Apache not seeing the credentials even though there was no issue with an older version. I changed
client.Credentials = new NetworkCredential(login, password);
to
String encoded = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes("user:pass"));
req.Headers.Add("Authorization", "Basic " + encoded);
and it worked!
Thank you.

Categories

Resources