How to issue PUT HttpWebRequest - asp.net-mvc-3

I'm trying to integrate with an API that requires a PUT to update data:
Here's an example from them using curl:
curl --request PUT \
--user-agent "Your Client Name/1.0" \
--header "Content-Type: application/xml" \
--data-binary '<order><status_id>10</status_id></order>' \
https://www.example.com/api/v2/orders/101
However, I'd need to use JSON (they support that as well) using .NET MVC 3. Any idea on how I can do that?
I use the code below for GET successfully:
Order obj = Call<Order>(url, "GET");
private T Call<T>(string url, string methodType) where T : class {
T result;
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = methodType;
request.Accept = "application/json";
request.ContentType = "application/json";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
string jsonData = reader.ReadToEnd();
result = (T)jsSerializer.Deserialize<T>(jsonData);
}
return result;
}
However, can I issue a PUT using a similar method?
Order obj = Call<Order>(url, "PUT");
If so, where do I put the data that's required in "data-binary"?

Well, here's a possible point of origin - untested; written straight into the browser; not production code; assumes that the PUT call both sends and receives the same object type (which is probably not the case)...
The main addition is that you need to supply the request's ContentLength, and you need to write the serialized JSON object to the request stream, which you'll get by calling HttpWebRequest::GetRequestStream(). It's the same approach as when POSTing.
private T Call<T>(string url, string methodType, T data) where T: class
{
T result;
HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
request.Method = methodType;
request.ContentType = "application/json";
request.Accept = "application/json";
if (methodType == "PUT" || methodType == "POST")
{
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
string jsonData = jsSerializer.Serialize(data);
byte[] arrData = Encoding.UTF8.GetBytes(jsonData);
request.ContentLength = arrData.Length;
using (Stream dataStream = request.GetRequestStream())
{
dataStream.Write(arrData, 0, arrData.Length);
}
}
// Note: You may not need to parse any response content,
// or it may be a different class
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
using (StreamReader reader
= new StreamReader(response.GetResponseStream()))
{
JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
string jsonData = reader.ReadToEnd();
result = (T)jsSerializer.Deserialize<T>(jsonData);
}
}
return result;
}

Related

FiddlerScript: proxy QUERY STRING and POST data in autoresponder

On the Autoresponder I map a certain endpoint to respond to a certain URL request received.
I would like the endpoint receives the QUERY STRING and POST DATA, too.
I thought it was possible through the "REGEX:" wrapper in the rule, but it cannot capture any subexpression to pass to the mapped endpoint.
Can it be done through FiddlerScript? How to reference request and mapped endpoint?
This solution in C# allows to incercept the request to www.example-1.com and forward it to www.example-2.com, chaining possible query string and filling POSTDATA if given:
// match regex
string regex = "example-1.com/somepath/.*";
Regex rgx = new Regex(regex);
Match match = rgx.Match(oSession.fullUrl);
if (match.Success) {
// GET request -> replace the original URL with "https://www.example-2.com"
if (oSession.HTTPMethodIs("GET")) {
string qs = oSession.fullUrl.Split('?')[1];
oSession.fullUrl = oSession.fullUrl.Replace(oSession.fullUrl, "https://www.example-2.com/path?" + qs);
} else if (oSession.HTTPMethodIs("POST")) {
// Create an HTTP request to www.example-2.com and forward the request body saved above:
oSession.utilCreateResponseAndBypassServer();
var reqBody = oSession.GetRequestBodyAsString();
var data = Encoding.ASCII.GetBytes(reqBody);
var request = (HttpWebRequest)WebRequest.Create("https://plugvue.com/test/request-parser/api-write.php");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
}
It has to be put inside the OnBeforeRequest(Session oSession) handler.

Getting Error 400 while Exchanging Code for Access Token in Google oAuth C#

WebRequest request = WebRequest.Create("https://accounts.google.com/o/oauth2/token");
request.Method = "POST";
string postData = "code=" + code + "&client_id=" + _clientId + "&client_secret=" + _clientSecret + "&redirect_uri=" + _callback_url + "&grant_type=authorization_code";
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();
I have placed a google sign in button in HTML page, on its callback got auth code to call ajax web servcice containing above code. But I am getting Error 400 on GetResponse(), I don't know why. Can any body please help me?
I have found following link workable in my case:
Code on page Page load :
protected void Page_Load(object sender, EventArgs e)
{
if (Request["code"] != null)
{
vCode = Request["code"].ToString();
getRefreshToken();
}
else
{
Response.Redirect(vAuthURL + "?scope=" + vScope + "&state=%2Fprofile&client_id=" + vClientId + "&redirect_uri=" + vRedURL + "&response_type=code&access_type=offline&approval_prompt=force", false);
}
}
Following function is being called in page load when code is available:
private void getRefreshToken()
{
string vClientId = "974762xxxxxx-xxxxxxxxx.apps.googleusercontent.com";
string vSecCode = "xxxxxxxxxxxxxxx";
string vScope = "https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile+https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fplus.login";
string vRedURL = "http://localhost:50488/wwwroot/member/social/googlesignin.aspx";
string vAuthURL = "https://accounts.google.com/o/oauth2/auth";
StringBuilder authLink = new StringBuilder();
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create("https://accounts.google.com/o/oauth2/token");
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
authLink.AppendFormat("code={0}", vCode);
authLink.AppendFormat("&client_id={0}", vClientId);
authLink.AppendFormat("&client_secret={0}", vSecCode);
authLink.AppendFormat("&redirect_uri={0}", vRedURL);
authLink.Append("&grant_type=authorization_code");
UTF8Encoding utfenc = new UTF8Encoding();
byte[] bytes = utfenc.GetBytes(authLink.ToString());
Stream os = null;
webRequest.ContentLength = bytes.Length; // Count bytes to send
os = webRequest.GetRequestStream();
os.Write(bytes, 0, bytes.Length); // Send it
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
if (webResponse == null) { Response.Write("null"); }
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
string jsonStr = sr.ReadToEnd().Trim();
}
Probably the important thing was to get code with server side code instead of mixing the client code and server side access_token getting script. Hope this works for you too.

valence desire 2 learn profile image upload

I'm trying to upload an image to my profile using the api but I'm getting a Unknown: NOT_FOUND 404 error. the call I am using is /d2l/api/lp/1.0/profile/myProfile/image, I am passing the content type, length and filename (profileImage). I'm passing the image as a dataStream. I've reduced the size of the image as well. Any ideas?
also here is part of my CallAction code orginally gotten from the Getting Started example
public void CallAction(ID2LUserContext userContext, int retryAttempts, string url, byte[] data, string method = "")
{
Uri uri = userContext.CreateAuthenticatedUri(url, method);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.AllowAutoRedirect = false;
request.Method = method;
if (method.Equals("PUT") || method.Equals("POST"))
{
request.ContentType = "image/jpeg";
//request.Headers.Add("Content-Disposition", "form-data; name=\"profileImage\"; filename=\"profileImage.jpg\"");
request.Headers.Add("Accept-Encoding", "gzip, deflate, compress");
//request.Headers.Add("X-Upload-Content-Type", "image/jpg");
//request.Headers.Add("X-Upload-Content-Length", data.Length.ToString());
//request.Headers.Add("X-Upload-File-Name", "profileImage");
request.ContentLength = data.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(data, 0, data.Length);
dataStream.Flush();
dataStream.Close();
}
}
Also when I run a get to retrieve my photo it also returns a 404 error.
We have tested this call against our test instances here, and it does work. Here's what the HTTP packet headers look like for a valid test call (from a call formed with the python requests module):
{ 'User-Agent': 'python-requests/1.2.3 CPython/3.3.2 Darwin/12.4.0',
'Accept': '*/*',
'Content-Type': 'multipart/form-data; boundary=716acd781e224902854e6845bc62f653',
'Content-Length': '117886',
'Accept-Encoding': 'gzip, deflate, compress' }
to this URL:
https://somelms.edu/d2l/api/lp/1.0/profile/myProfile/image?
x_a={appId}
&x_c=Lz3PDTaUgG46cMF3CajAsiiGzz0C6u5QTLieAmbONZ0
&x_b={userId}
&x_d=7sSqbce1_ictuNAs80n01h0jSI0YxxKbPM01W7f49a0
&x_t={timestamp}
with a body that looks like this (note the part headers in this body, that characterize the content of the single part in the body that contains the image data):
--716acd781e224902854e6845bc62f653
Content-Disposition: form-data; name="profileImage"; filename="profileImage-student.png"
Content-Type: image/png
{image bytes here}
--716acd781e224902854e6845bc62f653--
This code should fix your problem:
public static void UploadFilesToRemoteUrl(byte[] profileImage, ID2LUserContext userContext, string accion)
{
//Reference:
//action = "/d2l/api/lp/1.3/profile/" + profileIdentifier + "/image";
//profileImage = the profileImage of user read from disk:
/*
FileStream fileStream = new FileStream(pictureLocalPath, FileMode.Open, FileAccess.Read);
Byte[] img = new Byte[fileStream.Length];
fileStream.Read(img, 0, Convert.ToInt32(img.Length));
fileStream.Close();
*/
var uri = userContext.CreateAuthenticatedUri(accion, "POST");
string boundary = "bde472ff1f1a46539e54e655857c27c1";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = "multipart/form-data; boundary=" +
boundary;
request.Headers.Add("Accept-Encoding", "gzip, deflate, compress");
request.Method = "POST";
request.KeepAlive = true;
request.Proxy.Credentials = new NetworkCredential(Constantes.UsuarioProxy, Constantes.PasswordProxy, Constantes.DominioProxy);
Stream memStream = new System.IO.MemoryStream();
byte[] boundarybytes = System.Text.Encoding.ASCII.GetBytes("\r\n--" +
boundary + "\r\n");
string formdataTemplate = "\r\n--" + boundary +
"\r\nContent-Disposition: form-data; name=\"profileImage\"; filename=\"profileImage.jpg\"\r\nContent-Type: image/jpeg;\r\n\r\n";
byte[] formitembytes = System.Text.Encoding.UTF8.GetBytes(formdataTemplate);
memStream.Write(formitembytes, 0, formitembytes.Length);
//escribo el array de byte de la imagen
memStream.Write(profileImage, 0, profileImage.Length);
byte[] boundaryClose = System.Text.Encoding.ASCII.GetBytes("\r\n--" + boundary + "--");
memStream.Write(boundaryClose, 0, boundarybytes.Length);
StreamReader readerReq = new StreamReader(memStream);
string stringReq = readerReq.ReadToEnd();
request.ContentLength = memStream.Length;
Stream requestStream = request.GetRequestStream();
memStream.Position = 0;
byte[] tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
memStream.Close();
requestStream.Write(tempBuffer, 0, tempBuffer.Length);
requestStream.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
string responseValence = reader.ReadToEnd();
response.Close();
}
}

WP7 - Lost object's reference when making an asynchronous request/response

I am making a request to a service and getting a response. Service works fine and I am deserializing an object without a problem.
Below is an example of my code. The problem is the result object is null at the end. I do not know why am I losing a reference. What is the proper solution?
HttpWebRequest hwrq = (HttpWebRequest)WebRequest.Create("http://service.svc/Login");
hwrq.ContentType = "application/x-www-form-urlencoded; encoding='utf-8'";
hwrq.Accept = "text/xml";
hwrq.Method = "POST";
Users result = null; // object initializaiton
hwrq.BeginGetRequestStream(ar =>
{
var requestStream = hwrq.EndGetRequestStream(ar);
using (var sw = new StreamWriter(requestStream, System.Text.Encoding.UTF8))
{
sw.Write("Username Password");
sw.Close();
}
hwrq.BeginGetResponse(a =>
{
var response = hwrq.EndGetResponse(a);
var responseStream = response.GetResponseStream();
using (var sr = new StreamReader(responseStream))
{
returnedXML = sr.ReadToEnd();
XmlSerializer xds = new XmlSerializer(typeof(Users));
byte[] byteArray = Encoding.UTF8.GetBytes(returnedXML);
MemoryStream stream = new MemoryStream(byteArray);
result = (Users)xds.Deserialize(stream); // object is correct
}
responseStream.Close();
response.Close();
}, null);
}, null);
return result; // object is null!
Just like MarcinJuraszek suggested, the proper way is to make a callback and handle the results there.

first HttpWebResponse.GetResponseStream() fails, second one works?

I am creating a program that auto login into a website using forms authentication. When ever I call my method to connect to the website, it returns me a empty document text. However, if I call the same method a second time, it works perfectly.
Here is my code :
//perform authentication and stores the session in the cookiecontainer
private void loginToSite()
{
// prepare the web page we will be asking for
request = (HttpWebRequest)
WebRequest.Create(#"http://diary.com/notes/my_journal");
request.KeepAlive = true;
//========================================
//start of forms authentication parameters
//========================================
string authInfo = username + ":" + password;
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
request.Headers["Authorization"] = "Basic " + authInfo;
//========================================
//end of forms authentication parameters
//========================================
request.ContentType = "text/html";
request.Method = "GET";
request.AllowAutoRedirect = true;
request.Referer = #"http://diary.com/";
request.CookieContainer = new CookieContainer();
// execute the request
HttpWebResponse response = (HttpWebResponse)
request.GetResponse();
// we will read data via the response stream
Stream resStream = response.GetResponseStream();
container = request.CookieContainer;
//assign the http content to myWB for manipulation
//myWB is a WebBrowser object that have been declared
myWB.DocumentStream = resStream;
//prevent script errors from popping up
myWB.ScriptErrorsSuppressed = true;
MessageBox.Show(myWB.DocumentText);
}

Resources