Having trouble getting my from data out of Request in C#. What I have is angular $http posting to a proxy api. Problem is that Request.Form is empty; same goes for Request.InputStream.
Angular:
$http({
method: "POST",
url: '/apiproxy/projects/' + data.Project.Id + '/recruiting-groups',
data: angular.toJson(group, false)
});
C#:
public ActionResult Index(string pathInfo)
{
var url = Settings.GetValue<string>("QualService") + "/" + pathInfo + "?" + Request.QueryString;
//Get stuff from the back end
using (var client = new WebClient())
{
client.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
client.Headers[HttpRequestHeader.Cookie] = Request.Headers["Cookie"];
client.Headers[HttpRequestHeader.Authorization] = "Basic " +
Convert.ToBase64String(
Encoding.UTF8.GetBytes(
"x:{0}".Fmt(UserSession.ApiKey)));
try
{
var responseBytes = Request.HttpMethod == "POST" ? client.UploadValues(url, Request.Form) : client.DownloadData(url);
var result = new ContentResult();
result.Content = Encoding.UTF8.GetString(responseBytes);
result.ContentEncoding = Encoding.UTF8;
result.ContentType = "application/json";
return result;
}
catch(Exception e)
{
Logger.Error("Error while proxying to the API: ", e);
}
}
return Json(false);
}
When I look at network tab in chrome I can see the data being passed:
No matter what though Request.Form is null. And for that matter Request.InputStream is empty. What is going on?
You might want to try adding one of the following header types:
application/x-www-form-urlencoded
multipart/form-data
Related
I am trying to attach a binary file (Excel, MS-Word or Image or anything) to ServiceNow ticket using the POST method available in their REST API.
It works fine when I try to do that using Postman app, however, when I try to do that using C# code, the file gets added successfully however, in the beginning and end of file there is some data due to which files are not valid any more. If I open the attached files using Notepad++, I can see that the file has something like below:
--dc5fc6f1-c907-4a26-b410-1d54256954d6
Content-Disposition: form-data; name=Attachment; filename=Download_14Jul20151332195868.xlsx; filename*=utf-8''Download_14Jul20151332195868.xlsx
If I remove above lines from the file and save it again, then I am able to open the file in excel. Same thing happens with any other file type.
I am using below URL to POST the file to ServiceNow:
https://mycompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=SampleExcel3.xlsx
And below is my code:
private static string SendMultiPartRequest(string URL, ExecutionEnvironment executionEnvironment)
{
var response = "";
try
{
byte[] file_bytes = File.ReadAllBytes(AttachmentFilePath);
if (!string.IsNullOrWhiteSpace(AttachmentFilePath))
{
using (var client = CreateNewClient(URL, executionEnvironment))
{
using (var multipartContent = new MultipartFormDataContent())
{
multipartContent.Add(new StreamContent(new MemoryStream(file_bytes)), "Attachment", AttachmentFilePath.Substring(AttachmentFilePath.LastIndexOf("\\") + 1));
//multipartContent.Headers.Remove("Content-Type");
Task responseTask = client.PostAsync(WSIUrl, multipartContent).ContinueWith((Task<HttpResponseMessage> authRes) =>
{
response = HandleResponse(authRes);
});
responseTask.Wait();
}
}
}
else
{
response = "{ \"ErrorMessage\" : \"Attachment file not specified.\"}";
}
}
catch (Exception ex)
{
response = "{ \"ErrorMessage\" : \"Unspecified error: " + ex.Message + " \"}";
}
return response;
}
I also tried to Remove the header but it failed to attach file when I un-comment this line:
//multipartContent.Headers.Remove("Content-Type");
I don't have control over how ServiceNow API is using the file submitted. Please suggest how can I submit a binary file to attach to ServiceNow ticket.
UPDATE:
I am still trying with various options but still no luck. I tried to explore how Postman is able to attach the file successfully and found below code from Postman application. However, I can't see in this code how Postman is adding the Binary contents in the payload:
var client = new RestClient("https://mycompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=Sample.xlsx");
var request = new RestRequest(Method.POST);
request.AddHeader("Postman-Token", "34584fo4-f91a-414f-8fd0-ff44b0c6b345");
request.AddHeader("cache-control", "no-cache");
request.AddHeader("Authorization", "Basic c4Ajc2NvcmNoOmVOdBEzOSNSQGspqr==");
request.AddHeader("Accept", "application/json");
request.AddHeader("Content-Type", "application/json");
IRestResponse response = client.Execute(request);
However, when I send the POST request through Postman Application, it is working fine:
URL used in postman is: POST - https://MyCompany.service-now.com/api/now/attachment/file?table_name=incident&table_sys_id=1abc60ccdabc1c14215fc082ba9619b0&file_name=Sample.xlsx
I finally got this working using RestSharp. Below is the code if anyone else is looking for the solution:
private static string SendMultiPartRestClient(string URL, ExecutionEnvironment executionEnvironment)
{
string response;
try
{
if (!string.IsNullOrWhiteSpace(AttachmentFilePath))
{
string FileNameWithoutExtension = Path.GetFileNameWithoutExtension(AttachmentFilePath);
string FileExtension = Path.GetExtension(AttachmentFilePath);
string AttachmentFileName = $"{FileNameWithoutExtension}{FileExtension}";
string AskNowPasswordToBeUsed;
if (executionEnvironment == ExecutionEnvironment.NonProduction)
AskNowPasswordToBeUsed = AskNowPasswordEagle;
else
AskNowPasswordToBeUsed = AskNowPasswordProduction;
byte[] byteArray = Encoding.ASCII.GetBytes(AskNowUserName + ":" + AskNowPasswordToBeUsed);
var Auth = Convert.ToBase64String(byteArray);
ServicePointManager.Expect100Continue = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
X509Certificate2 c1 = new X509Certificate2(asknowCertPath, CertPass);
var client = new RestClient(WSIUrl);
client.Timeout = -1;
client.AddDefaultHeader(DP_EXTERNAL_URL, URL);
client.ClientCertificates = new X509CertificateCollection() { c1 };
var request = new RestRequest(Method.POST);
request.AddHeader("Authorization", $"Basic {Auth}");
request.AddHeader("Accept", "*/*");
request.AddHeader("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
request.AddParameter("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
File.ReadAllBytes(AttachmentFilePath),
ParameterType.RequestBody);
IRestResponse restResponse = client.Execute(request);
switch (restResponse.ResponseStatus)
{
case ResponseStatus.None:
response = "{ \"ErrorMessage\" : \"No response\"}";
break;
case ResponseStatus.Completed:
response = restResponse.Content;
break;
case ResponseStatus.Error:
response = "{ \"ErrorMessage\" : \"Unspecified error: " + restResponse.ErrorMessage + " \"}";
break;
case ResponseStatus.TimedOut:
response = "{ \"ErrorMessage\" : \"Request timed out\"}";
break;
case ResponseStatus.Aborted:
response = "{ \"ErrorMessage\" : \"Request aborted\"}";
break;
default:
response = "{ \"ErrorMessage\" : \"Unspecified response type.\"}";
break;
}
}
else
{
response = "{ \"ErrorMessage\" : \"Attachment file not specified.\"}";
}
}
catch (Exception ex)
{
response = "{ \"ErrorMessage\" : \"Unspecified error: " + ex.Message + " \"}";
}
return response;
}
This is less a question than an answer. I figured I would want to share this with you, since I was a bit confused finding so litte about the ebay OAuth 2.0 in combination with a C# web application.
I tried starting to use the RESTsharp library, but got stuck at the point, where the body content was created. RESTsharp prefers XML or JSON, ebay want's a string with params.
So to give you all a little help if you run into the same issue, I decided to post my solution (not using RESTsharp).
public class HomeController : Controller {
string clientId = "YOUR_CLIENT_ID";
string clientSecret = "YOUR_CLIENT_SECRET";
string ruName = "YOUR_RU_NAME";
// Redirect the request to get a request token
public ActionResult Index() {
var authorizationUrl =
"https://signin.sandbox.ebay.de/authorize?" +
"client_id=" + clientId + "&" +
"redirect_uri=" + ruName + "&" +
"response_type=code";
Response.Redirect(authorizationUrl);
return View();
}
// I used Test as a method to test the result in the controller, use your apropriate method here
public ActionResult Test(string code)
{
ViewBag.Code = code;
// Base 64 encode client Id and client secret
var clientString = clientId + ":" + clientSecret;
byte[] clientEncode = Encoding.UTF8.GetBytes(clientString);
var credentials = "Basic " + System.Convert.ToBase64String(clientEncode);
HttpWebRequest request = WebRequest.Create("https://api.sandbox.ebay.com/identity/v1/oauth2/token")
as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add(HttpRequestHeader.Authorization, credentials);
var codeEncoded = HttpUtility.UrlEncode(code);
var body = "grant_type=authorization_code&code=" + codeEncoded + "&redirect_uri=" + ruName;
// Encode the parameters as form data
byte[] formData = UTF8Encoding.UTF8.GetBytes(body);
request.ContentLength = formData.Length;
// Send the request
using (Stream post = request.GetRequestStream())
{
post.Write(formData, 0, formData.Length);
}
// Pick up the response
string result = null;
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
StreamReader reader = new StreamReader(response.GetResponseStream());
result = reader.ReadToEnd();
}
ViewBag.Response = result;
return View();
}
If you output ViewBag.Response you will see the authorization code. Have fun.
How is your redirect url looking in sandbox? Seems like the url should be https. In this stage in dev environment and don't have server with https. How did you deal with that?
Ta
I'm receiving a 400 Bad Request error message when posting a pin on Pinterest. It works using Postman, but doesn't work programmatically. Using C#, has anyone been able to successfully post a pin on Pinterest without using the pinsharp wrapper?
private void postPinterest(string messages, string id, string usertoken, string image, string boardname, string username)
{
string link = null;
boardname = boardname.Replace(" ", "-");
string board = username + "/" + boardname;
string url = "https://api.pinterest.com/v1/pins?access_token=" + usertoken;
StringBuilder sb = new StringBuilder();
if (!string.IsNullOrEmpty(board))
sb.Append("&board=" + HttpUtility.UrlEncode(board));
if (!string.IsNullOrEmpty(messages))
sb.Append("¬e=" + HttpUtility.UrlEncode(messages));
if (!string.IsNullOrEmpty(link))
sb.Append("&image_url=" + HttpUtility.UrlEncode(link));
string postdata = sb.ToString().Substring(1);
PostData(url, postdata);
}
private object PostData(string url, string postdata)
{
object json=null;
try
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
req.Method = "POST";
req.ContentType = "application/x-www-form-urlencoded";
// req.Accept = "application/json";
using (var stream = req.GetRequestStream())
{
byte[] bindata = Encoding.ASCII.GetBytes(postdata);
stream.Write(bindata, 0, bindata.Length);
}
HttpWebResponse resp = (HttpWebResponse)req.GetResponse();
string response = new StreamReader(resp.GetResponseStream()).ReadToEnd();
json = JsonConvert.DeserializeObject<dynamic>(response);
return json;
}
catch (WebException wex)
{
if (wex.Response != null)
{
using (var errorResponse = (HttpWebResponse)wex.Response)
{
using (var reader = new StreamReader(errorResponse.GetResponseStream()))
{
string error = reader.ReadToEnd();
return json;
}
}
}
}
return json;
}
EDIT:
It doesn't work using the JSON format or x-www-form-urlencoded format.
I changed the content type to application/x-www-form-urlencoded and now I'm receiving the error message below. I receive 400 Bad Request error using JSON format:
"{\n \"message\": \"405: Method Not Allowed\",\n \"type\": \"http\"\n}"
The problem is the the parameter that you are posting.
In the Api i could find board as a parameter but both note and image comes under field parameter which specifies the return type JSON.
As per documentation on this page you can post in this format
https://api.pinterest.com/v1/boards/anapinskywalker/wanderlust/pins/?
access_token=abcde&
limit=2&
fields=id,link,counts,note
So I tried the following and its getting response
https://api.pinterest.com/v1/boards/?access_token="YourTokenWithoutQuotes"&fields=id%2Ccreator
Would suggest you to first test the Api you are hitting putting a breakpoint inside the PostData function and check if the passed url is in the correct format and compare it with Pininterest API Explorer.
As you might have already received authorization code and access token so I am assuming your post function should be working fine.
public string postPinterest(string access_token,string boardname,string note,string image_url)
{
public string pinSharesEndPoint = "https://api.pinterest.com/v1/pins/?access_token={0}";
var requestUrl = String.Format(pinSharesEndPoint, accessToken);
var message = new
{
board = boardname,
note = note,
image_url = image_url
};
var requestJson = new JavaScriptSerializer().Serialize(message);
var client = new WebClient();
var requestHeaders = new NameValueCollection
{
{"Content-Type", "application/json" },
{"x-li-format", "json" }
};
client.Headers.Add(requestHeaders);
var responseJson = client.UploadString(requestUrl, "POST", requestJson);
var response = new JavaScriptSerializer().Deserialize<Dictionary<string, object>>(responseJson);
return response;
}
I am trying to call a web service by passing JSON data. The web service accepts the authentication, where we need to pass the username and password to authenticate.
I am sorry guys, I couldn't disclose the URL and the Username.
Below is my method to do the job.
private static void MakeRequest(string url, string user_name)
{
try
{
var webAddr = url;
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json;";
httpWebRequest.Method = "POST";
//password is blank
var credentialBuffer = new UTF8Encoding().GetBytes(user_name + ":" + "");
httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(credentialBuffer);
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = "{\"x\":\"true\"}";
streamWriter.Write(json);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
}
catch (Exception ex)
{
throw;
}
}
When I call the method by passing URL and the username, it is returning error as "The remote server returned an error: (422) Unprocessable Entity."
I guess I am not using the proper authentication method.
Please help.
Is "X" valid attribute parameter to update or create your object ? Because when trying to create or update an object with invalid or missing attribute parameters, you will get a 422 Unprocessable Entity response.
I would like to try upload a mp3 file to my soundcloud account. I have written this code for this job.
WebClient client = new WebClient();
string postData = "client_id=" + "xxxxx"
+ "&client_secret=" + "xxx"
+ "&grant_type=password&username=" + "xxx" //your username
+ "&password=" + "xxx";//your password :)
string soundCloudTokenRes = "https://api.soundcloud.com/oauth2/token";
string tokenInfo = client.UploadString(soundCloudTokenRes, postData);
tokenInfo = tokenInfo.Remove(0, tokenInfo.IndexOf("token\":\"") + 8);
string token = tokenInfo.Remove(tokenInfo.IndexOf("\""));
System.Net.ServicePointManager.Expect100Continue = false;
var request = WebRequest.Create("https://api.soundcloud.com/tracks") as HttpWebRequest;
request.CookieContainer = new CookieContainer();
//some default headers
request.Accept = "*/*";
request.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.3");
request.Headers.Add("Accept-Encoding", "gzip,deflate,sdch");
request.Headers.Add("Accept-Language", "en-US,en;q=0.8,ru;q=0.6");
//file array
var files = new UploadFile[] { new UploadFile(filePath, "#/" + filePath, "application/octet-stream") };
//other form data
var form = new NameValueCollection();
form.Add("track[title]", "biksad");
form.Add("track[sharing]", "public");
form.Add("oauth_token", token);
form.Add("format", "json");
form.Add("Filename", fileName);
form.Add("Upload", "Submit Query");
string lblInfo;
try
{
using (var response = HttpUploadHelper.Upload(request, files, form))
{
using (var reader = new StreamReader(response.GetResponseStream()))
{
lblInfo = reader.ReadToEnd();
}
}
}
catch (Exception ex)
{
lblInfo = ex.ToString();
}
}
When I debug this code part. I get (422) Unprocessable Entity error in catch block. Why I get this error? How can solve this problem?
Check the Soundcloud documentation:
http://developers.soundcloud.com/docs#errors
422 - "The request looks alright, but one or more of the parameters looks a little screwy. It's possible that you sent data in the wrong format (e.g. an array where we expected a string)."