I'm trying to insert a file in google drive using webRequest (since I'm implementing an resumable async upload), but I have no idea how to put data in request "body".
From now, I have:
public static HttpWebRequest CreateUploadRequest(Google.Apis.Drive.v2.DriveService driveService, string uri, Stream contentStream, string title, string mimeType, string description = null)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "PUT";
Dictionary<string, object> requestBody = new Dictionary<string, object>();
requestBody["title"] = title;
requestBody["mimeType"] = mimeType;
if (!string.IsNullOrWhiteSpace(description))
{
requestBody["description"] = description;
}
driveService.Authenticator.ApplyAuthenticationToRequest(request);
Stream requestStream = request.GetRequestStream();
//How to do that???
requestStream.Close();
return request;
}
I set the headers for the HttpWebRequest, how the data of the body should be disposed?
And whats is the property name for the byte[] data of the file to be inserted?
Any example whould be appreciated.
The SDK documentation on this page says:
The body of the request is formatted as a multipart/related content type RFC2387 and contains exactly two parts. The parts are identified by a boundary string, and the final boundary string is followed by two hyphens.
If you've never worked with it, RFC2387 is the MIME definition. Binary data in MIME is typically BASE64 encoded, like in this example from the RFC:
Content-Type: Application/octet-stream
Content-Description: The fixed length records
Content-Transfer-Encoding: base64
Content-ID: <950120.aaCB#XIson.com>
T2xkIE1hY0RvbmFsZCBoYWQgYSBmYXJtCkUgSS
BFIEkgTwpBbmQgb24gaGlzIGZhcm0gaGUgaGFk
IHNvbWUgZHVja3MKRSBJIEUgSSBPCldpdGggYS
BxdWFjayBxdWFjayBoZXJlLAphIHF1YWNrIHF1
YWNrIHRoZXJlLApldmVyeSB3aGVyZSBhIHF1YW
NrIHF1YWNrCkUgSSBFIEkgTwo=
Have a look at this question for an example of uploading binary data to a Web request: Upload files with HTTPWebrequest (multipart/form-data)
Related
I am attempting to send an attachment through a HttpWebRequest in a Console Application. After a few days of searching and scouring the internet for some understandable assistance on this, I came up with what I think is a decent solution from this site
While I think I've done everything correctly, I am receiving the following error:
Multipart stream ended before a terminating boundary was encountered.
Questions:
I'm hoping to get some assistance/guidance with the multipart error I'm receiving, as well as assistance in attaching the actual byte[] of the XML Document.
Requirements:
The data file that needs to be attached is is an XML file which
should be an MTOM Attachment. In order to make it Mtom, my
understanding is that I need to be sure that the messageEncoding
attribute of the <binding> element in the app.config should have
a value of "Mtom" and this will be encoded as such.
Based on the business requirements (of which is strict), I need to send the byte[] of the file, not simply the contents itself.
Web Request Method
private static HttpWebRequest CreateWebRequest(SoapAction action)
{
// Retrieve URL from Endpoint in the app.Config based on the action passed into the
// method.
string url = GetUrlAddress(action);
if (url != null)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip, deflate");
request.Headers.Add(HttpRequestHeader.ContentEncoding, "gzip");
request.Headers.Add("Content-Transfer-Encoding", "8bit");
request.Headers.Add("SOAPAction", action.ToString());
request.Method = "POST";
request.Headers.Add("MIME-Version", "1.0");
request.ContentType = "multipart/form-data; type=\"application/xop+xml;\" boundary=\"" + BoundaryMarker + "\"";
request.ClientCertificates.Add(SecurityCertificate.CertificateObject);
ServicePointManager.Expect100Continue = false;
return request;
}
else
{
throw new NullReferenceException("Address for Endpoint could not be resolved.");
}
}
Method to Submit Request
Based on this post of mine, I believe I am compressing the HttpWebRequest appropriately using GZip.
private static void SubmitRequest(HttpWebRequest request, XDocument soapXml, byte[] formXmlBytes, FileInfo fileToUpload)
{
using (Stream requestStream = request.GetRequestStream())
{
using (GZipStream gz = new GZipStream(requestStream, CompressionMode.Compress, false))
{
soapXml.Save(gz);
WriteToStream(gz, formXmlBytes, fileToUpload.Name);
}
}
}
Method used to Write the MIME information and attachment to the Stream
public static void WriteToStream(Stream stream, byte[] formData, string fileName)
{
// Write a new line to the stream.
byte[] newLineBytes = Encoding.UTF8.GetBytes("\r\n");
stream.Write(newLineBytes, 0, newLineBytes.Length);
// Write the header to the stream.
string header = String.Format(HeaderTemplate, BoundaryMarker, fileName, RequestContentID);
byte[] headerBytes = Encoding.UTF8.GetBytes(header);
stream.Write(headerBytes, 0, headerBytes.Length);
// Write a new line to the stream.
stream.Write(newLineBytes, 0, newLineBytes.Length);
// Write the formData to the stream.
stream.Write(formData, 0, formData.Length);
// Write a new line to the stream.
stream.Write(newLineBytes, 0, newLineBytes.Length);
// Write the footer to the stream.
byte[] boundaryFooterBytes = Encoding.UTF8.GetBytes("--" + BoundaryMarker + "--");
stream.Write(boundaryFooterBytes, 0, boundaryFooterBytes.Length);
}
Soap Body Snippet Element
By using Fiddler, I am able to see what the request actually looks like. To me, it appears that the attachment is actually being appended to the request as the XML that it is, instead of (what I thought would be) a byte[].
After this should be the byte[] of the attachment. Currently, the full XML document is displaying.
Accept-Encoding: gzip, deflate
Content-Transfer-Encoding: 8bit
MIME-Version: 1.0
Content-Type: multipart/form-data; type="application/xop+xml;" boundary="--b73acdd180274cab985e4d697bfde428"
Content-Length: 582081
Connection: Keep-Alive
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:soapenv="..." ...>
...
<soapenv:Body>
<urn:Request version="1.0">
<urn:FileAttachment>cid:b73acdd180274cab985e4d697bfde428</urn:FileAttachment>
</urn:Request>
</soapenv:Body>
</soapenv:Envelope>
----b73acdd180274cab985e4d697bfde428
Content-Disposition: attachment; filename="test.xml"
Content-Type: text/xml
Content-Id: b73acdd180274cab985e4d697bfde428
<XML OF ATTACHMENT>
----b73acdd180274cab985e4d697bfde428--
I've created a web api, which contains method:
POST Settings/SetPropertyValue?propertyName={propertyName}
public object SetPropertyValue(string propertyName, object propertyValue)
{
switch (propertyName)
{
//Do the property assignment
}
}
When I visit help page, it shows following
When I try to invoke the method from fiddler, using XML example, it works fine, object propertyValue equals to POST value.
XML POST example:
POST http://localhost:99/webapi/Settings/SetPropertyValue?propertyName=myProperty HTTP/1.1
Content-Type: text/xml; charset=UTF-8
Host: localhost:99
Expect: 100-continue
Connection: Keep-Alive
<anyType>
true
</anyType>
But how to POST JSON in this case? Does JSON handles "simple" data types, like object or string?
As far as I see there is no body you send. So both the XML and JSON bodies are empty.
You place all your properties in the query string.
I was reading this article about it and it seems you have to start your method with Post to make it a HTTP POST instead of GET.
Quote:
Note two things about this method:
The method name starts with "Post...". To create a new product, the
client sends an HTTP POST request.
This is my test code. Maybe it is useful to you:
WebRequest request = HttpWebRequest.Create("http://localhost:12345/api/Values");
byte[] byteArray = Encoding.UTF8.GetBytes("5");
request.ContentLength = byteArray.Length;
request.ContentType = "application/json";
request.Method = "POST";
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
WebResponse response = request.GetResponse();
Stream data = response.GetResponseStream();
StreamReader reader = new StreamReader(data);
// Read the content.
string responseFromServer = reader.ReadToEnd();
The controller action involved here:
// POST api/values
public void Post([FromBody]string value)
{
// check the value here
}
I'm working on a project where I have to send product information via HTTP POST in XML string to a web server. It turns out that certain product names may have a % sign in their name, such as ".05% Topical Cream". Whenever I attempt to send XML data that contained a % sign in the product name, I get an error apparently because when encoding the XML string data the percent sign caused the data to become malformed.
How can I encode and send the XML string data with % sign in product name safely?
XML Data:
<node>
<product>
<BrandName>amlodipine besylate (bulk) 100 % Powder</BrandName>
</product>
</node>
Web request code:
public string MakeWebServerRequest(string url, string data)
{
var parms = System.Web.HttpUtility.UrlEncode(data);
byte[] bytes = Encoding.UTF8.GetBytes("xml=" + parms);
string webResponse = String.Empty;
try
{
System.Web.HttpUtility.UrlEncode(data);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
req.ContentLength = bytes.Length;
using (Stream reqStream = req.GetRequestStream())
{
reqStream.WriteTimeout = 3000;
reqStream.Write(bytes, 0, bytes.Length);
reqStream.Close();
}
using (HttpWebResponse response = (HttpWebResponse)req.GetResponse())
{
using (StreamReader rdr = new StreamReader(response.GetResponseStream()))
{
webResponse = rdr.ReadToEnd();
rdr.Close();
}
response.Close();
}
}
Should I be creating the web request differently? What can I do to resolve, while maintaining the product name?
Corrected - and working now. Thanks
Thanks
You need to construct request propely. application/x-www-form-urlencoded means that each parameter is Url-encoded. In your case xml parameter must have value correctly encoded, not just blindly concatenated. Below is sample that should give you stared... hopefully you'll be able to avoid string concateneation to construct XML (and insane way of constructing string constant with queotes you have in original code):
var parameterValue = System.Web.HttpUtility.UrlEncode("<xml>" + data);
byte[] bytes = Encoding.UTF8.GetBytes("xml=" + parameterValue);
There are also plenty of samples how to correctly construct requests of this kind. I.e. C# web request with POST encoding question
On the MSDN site there is an example of some C# code that shows how to make a web request with POST'ed data. Here is an excerpt of that code:
WebRequest request = WebRequest.Create ("http://www.contoso.com/PostAccepter.aspx ");
request.Method = "POST";
string postData = "This is a test that posts this string to a Web server.";
byte[] byteArray = Encoding.UTF8.GetBytes (postData); // (*)
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream ();
dataStream.Write (byteArray, 0, byteArray.Length);
dataStream.Close ();
WebResponse response = request.GetResponse ();
...more...
The line marked (*) is the line that puzzles me. Shouldn't the data be encoded using the UrlEncode method rather than UTF8? Isn't that what application/x-www-form-urlencoded implies?
The sample code is misleading, because ContentType is set to application/x-www-form-urlencoded but the actual content is plain text. application/x-www-form-urlencoded is a string like this:
name1=value1&name2=value2
The UrlEncode function is used to escape especial characters like '&' and '=' so a parser doesn't consider them as syntax. It takes a string (media type text/plain) and returns a string (media type application/x-www-form-urlencoded).
Encoding.UTF8.GetBytes is used to convert the string (media type application/x-www-form-urlencoded in our case) into an array of bytes, which is what the WebRequest API expects.
As Max Toro indicated, the examples on the MSDN site are incorrect: a correct form POST requires the data to be URL encoded; since the data in the MSDN example does not contain any characters that would be changed by encoding, they are, in a sense, already encoded.
The correct code would have a System.Web.HttpUtility.UrlEncode call on the names and values of each name/value pair before combining them into the name1=value1&name2=value2 string.
This page was helpful: http://geekswithblogs.net/rakker/archive/2006/04/21/76044.aspx
I am trying to send an URL-encoded post to a REST API implemented in PHP. The POST data contains two user-provided strings:
WebRequest request = HttpWebRequest.Create(new Uri(serverUri, "rest"));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded; charset=UTF-8";
request.Headers.Add("Content-Transfer-Encoding", "binary");
// Form the url-encoded credentials we'll use to log in
StringBuilder builder = new StringBuilder();
builder.Append("user=");
builder.Append(user);
builder.Append("&password=");
builder.Append(password);
byte[] credentials = Encoding.UTF8.GetBytes(builder.ToString());
// Write the url-encoded post data into the request stream.
request.ContentLength = credentials.Length;
using (Stream requestStream = request.GetRequestStream()) {
requestStream.Write(credentials, 0, credentials.Length);
}
This sends a HTTP request to the server containing user=myusername&password=mypassword in UTF-8 as its POST data.
How can I escape the user-provided strings?
For example, if I had a user named big&mean, how should the ampersand be escaped so that it does not mess up the request line?
You can use the static HttpUtility class in System.Web for encoding and decoding HTML and Url related values.
Try HttpUtility.UrlEncode().
It would seem that System.Web is obsolete - the newer way to access it is System.Net.WebUtility.HtmlEncode