I have this more complicated web request in C# which involves a File upload. I keep receiving 422 Unprocessable Entity error.
Basically this is the JSON structure that is required in the body of the request.
{
"title":"abc",
"publisher":
{
"city":"J Town",
"year":2021
}
"File":"???",
"Shed":[
{
"country":"NZ",
"postcode":12345
}
]
}
What I have written is the following (I converted the file path to byte).
var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://api-abc.com/upload");
httpWebRequest.ContentType = "multipart/form-data";
httpWebRequest.Headers.Add("Token", "3SHFHBVRH87BHDBGV");
httpWebRequest.Method = "POST";
var bytes = Encoding.UTF8.GetBytes(#"D:/abc.pdf");
var root = new RootObject()
{
upload = new UploadDoc()
{
title = "Test 321",
Publisher = new List<publishers>
{
new recipients()
{
city = "J Town",
year = 2021
}
},
file = $"Basic { Convert.ToBase64String(bytes) }",
Shed = new []
{
new
{
country = "NZ",
postcode = 12345
}
}
}
};
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
var book = JsonConvert.SerializeObject(new
{
root
});
streamWriter.Write(book);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Which part did I do wrong?
Appreciate the help in advance :)
Related
I have this problem. i have to submit a file (or not) to an endpoint on an API of bmc.
the KEY:entry with the VALUE:data_entry.txt is the json to send with the values, as the same of the body.
The attach-z2AF_WIAttachment1 is the file i want to submit. I'm it's always throuwing some error, or headers invalid, or filetype not valid, but in postman is working.
I cant convert to C#.
this is my code so far, or now.
try
{
//authentication
var dict = new Dictionary<string, string>();
dict.Add("username", "applicationUsernameJonDoe");
dict.Add("password", "applicationPassowrdXPTO");
var clientLogin = new HttpClient();
var req = new HttpRequestMessage(HttpMethod.Post, Endpoint_loginITSM) { Content = new FormUrlEncodedContent(dict) };
var res = clientLogin.SendAsync(req); //.Result.ToString();
var body = res.GetAwaiter().GetResult().Content.ReadAsStringAsync();
//pedido de criação de registo
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post
};
request.Headers.Add("Authorization", body.Result.ToString());
if (!string.IsNullOrEmpty(registos.Objeto.fileName))
{
registos.Objeto.Registo.z2AF_WIAttachment1 = registos.Objeto.fileName;
}
string json = JsonConvert.SerializeObject(new { values = registos.Objeto });
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
MemoryStream memoryStream = new MemoryStream();
using (BsonDataWriter writer = new BsonDataWriter(memoryStream))
{
JsonSerializer serializer = new JsonSerializer();
serializer.Serialize(writer, registos.Objeto.Registo);
}
var data_entry_bytes = memoryStream.ToArray();
// we need to send a request with multipart/form-data
var multiForm = new MultipartFormDataContent();
ByteArrayContent data_entry_json_content = new ByteArrayContent(data_entry_bytes);
data_entry_json_content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
data_entry_json_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("entry")
{
FileName = "data_entry.txt",
Name = "entry",
};
multiForm.Add(data_entry_json_content);
ByteArrayContent z2AF_WIAttachment1_content = new ByteArrayContent(file_bytes);
z2AF_WIAttachment1_content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
z2AF_WIAttachment1_content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attach-z2AF_WIAttachment1")
{
FileName = registos.Objeto.fileName,
Name = "attach-z2AF_WIAttachment1",
};
multiForm.Add(z2AF_WIAttachment1_content);
request.Content = multiForm;
var result = await client.SendAsync(request);
var resBody = result.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _resBody = JsonConvert.DeserializeObject<dynamic>(resBody);
string registoID = _resBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", registoID);
}
}
catch (Exception e)
{
string classname = this.GetType().Name;
CentralLibrary.Services.ErrorLoggingService.ErrorLogsForCore(classname, e, _env.WebRootPath);
return ResponseHandler<string>.Resposta(true, "EXCEPTION : resposta api bit criar registos", e.Message);
}
Here is a better solution.
I had a problem with the last, but for someone who doesnt wnat to use de library RestClient that's the way. But this is working 100% and i have JsonProperty Names for NewtonSoft.Json so this workin with names like
[JsonProperty("z1D Action")]
public string z1D_Action { get; } = "CREATE";
so, my code is, and using an object AbrirRegistosITSM with nested object AbrirRegistosITSM_com_anexo my final solution is
AbrirRegistosITSM _registo = new AbrirRegistosITSM
{
Values = new AbrirRegistosITSM_com_anexo
{
Details = registos.Objeto.Comentario,
Customer_Login = registos.username,
Login_ID = registos.username,
SR_Type_Field_3 = registos.Objeto.Tipologia,
SR_Type_Field_28 = registos.Objeto.Categoria,
z2AF_WIAttachment1 = registos.Objeto.FicheiroNome
}
};
var client = new RestClient(Endpoint_CreateITSM);
string baseFolder = _env.WebRootPath;
string pathDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathDir);
string pathDirFile = Path.Combine(pathDir, registos.Objeto.FicheiroNome);
File.WriteAllBytes(pathDirFile, Convert.FromBase64String(registos.Objeto.FicheiroBase64));
string pathEntryDir = Path.Combine(baseFolder, DateTime.Now.ToString().Replace('/', '_').Replace(' ', '_').Replace(':', '_'));
Directory.CreateDirectory(pathEntryDir);
string patnEntrydirFile = Path.Combine(pathEntryDir, "data_entry.txt");
File.WriteAllText(patnEntrydirFile, JsonConvert.SerializeObject(new { values = _registo.Values }));
var request = new RestRequest();
request.Method = Method.Post;
request.AddHeader("Authorization", token);
request.AddFile("entry", patnEntrydirFile, "application/json");
request.AddFile("attach-z2AF_WIAttachment1", pathDirFile, "application/octet-stream");
var reqbody = JsonConvert.SerializeObject(_registo);
request.AddParameter("application/json", reqbody, ParameterType.RequestBody);
RestResponse response = client.Execute(request);
var respostaBody = response.Content.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"]["Request Number"];
then i return the request number that what i need, but you have a lot of values there. I use NewtonSoft remember that. I dont use JsonSerializer because i wasn't able to save the json property names with spaces with JsonSerializer.
I'm not entirely sure what's going wrong here. It can be a lot of things, but I might be able to get you going. The last couple of weeks I build a HttpClient that sends a file with metadata to a GraphQL endpoint.
Please ensure the following:
I think you are requesting the file through an call. Please store it in a variable as a Byte[] using the ReadAsByteArrayAsync(). Do note decode it or cast it to a string or anything. You'll just corrupt the file.
var response = client.GetAsync(fileUrl);
var downloadedFile = await response.Result.Content.ReadAsByteArrayAsync();
The following code might not work entirely in your case, but should help you get going building the right request, since I'm also sending metadata in my request containing the file extension and some other information. This will most likely send the file to your API without a file extension.
using (var client = new HttpClient())
{
var file = new byte[] { 1, 2, 3 };
var fileToUpload = new ByteArrayContent(file);
var formData = new MultipartFormDataContent
{
{ fileToUpload, "entry", "passInFileExtensionForExample"},
{ fileToUpload, "attach-z2AF_WIAttachment1", "passInFileExtensionForExample" }
};
var response = await client.PostAsync("endpoint", formData);
}
Add the Bearer token using the following code:
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
So i've discover the solution for my problem. I'm gonna to submit only one file. I have to submit also the Json body as a file "entry" "data_entry.txt" and for HttpRequestMessage you have to have a content MultipartFormDataContent and here you can add as many files as you have. i have to convert the Json body to a file ( in this case i converted to binary Array) with the name entry, and the name of the file data_entry.txt, but it's what the endpoint needs, so...whatever.
using (var client = new HttpClient())
{
client.Timeout = TimeSpan.FromMinutes(10);
MultipartFormDataContent content = new MultipartFormDataContent();
//adicionar ficheiro
byte[] file_bytes = System.Convert.FromBase64String(registos.Objeto.fileEncoded);
StreamContent fileContent = new StreamContent(new MemoryStream(file_bytes));
fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[attach-z2AF_WIAttachment1]",
FileName = registos.Objeto.fileName
};
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/octet-stream");
content.Add(fileContent);
//adicionar ficheiro entry
StreamContent entryStreamContent = new StreamContent(new MemoryStream(ObjectToByteArray(registos.Objeto.Registo)));
entryStreamContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
{
Name = "files[entry]",
FileName = "data_entry.txt"
};
entryStreamContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
content.Add(entryStreamContent);
var request = new HttpRequestMessage
{
RequestUri = new Uri(Endpoint_CreateITSM),
Method = HttpMethod.Post,
Content= content
};
request.Headers.Add("Authorization", body.Result.ToString());
string json = JsonConvert.SerializeObject(new { values = registos.Objeto.Registo});
request.Content = new ByteArrayContent(Encoding.UTF8.GetBytes(json));
request.Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var resposta = await client.SendAsync(request);
var respostaBody = resposta.Content.ReadAsStringAsync().Result.ToString();//.ConfigureAwait(false);
dynamic _respostaBody = JsonConvert.DeserializeObject<dynamic>(respostaBody);
string _registoID = _respostaBody["values"].SysRequestID;
return ResponseHandler<string>.Resposta(false, "resposta api bit criar registos", _registoID);
So this is my solution. and it's working :)
I am trying to build a console app that reads the data from SharePoint list.
But i dont want to pass the user credentials in order to authenticate, instead use the token. Is this possible?
I tried using the following code but i get forbidden error while trying to GetFormDigest
static void Main(string[] args)
{
string sConnStr = "https://sab/sites/DevT";
Uri oUri = null;
oUri = new Uri(sConnStr + "/_api/web/lists/getbytitle('sd')/GetItems");
string sResult = string.Empty;
string stringData = "{'query' : {'__metadata': { 'type': 'SP.CamlQuery' }, 'ViewXml':'<View><Query><Where><Eq><FieldRef Name =\"Title\"/><Value Type=\"Text\">HR</Value></Eq></Where></Query></View>'}}";
HttpWebRequest oWebRequest = (HttpWebRequest)WebRequest.Create(oUri);
oWebRequest.Credentials = CredentialCache.DefaultNetworkCredentials;
oWebRequest.Method = "POST";
oWebRequest.Accept = "application/json;odata=verbose";
oWebRequest.ContentType = "application/json;odata=verbose";
oWebRequest.Headers.Add("X-RequestDigest", GetFormDigest());
oWebRequest.ContentLength = stringData.Length;
StreamWriter writer = new StreamWriter(oWebRequest.GetRequestStream());
writer.Write(stringData);
writer.Flush();
WebResponse wresp = oWebRequest.GetResponse();
using (StreamReader sr = new StreamReader(wresp.GetResponseStream()))
{
sResult = sr.ReadToEnd();
}
}
public static string GetFormDigest()
{
string sFormDigest = null;
string sConnStr = "https://sab/sites/DevT";
Uri oUri = null;
oUri = new Uri(sConnStr + "/_api/contextinfo");
HttpWebRequest oWebRequest = HttpWebRequest.Create(oUri) as HttpWebRequest;
oWebRequest.UseDefaultCredentials = true;
oWebRequest.Method = "POST";
oWebRequest.Accept = "application/json;odata=verbose";
oWebRequest.ContentLength = 0;
oWebRequest.ContentType = "application/json";
string sResult;
WebResponse sWebReponse = oWebRequest.GetResponse();
using (StreamReader sr = new StreamReader(sWebReponse.GetResponseStream()))
{
sResult = sr.ReadToEnd();
}
var jss = new JavaScriptSerializer();
var val = jss.Deserialize<Dictionary<string, object>>(sResult);
var d = val["d"] as Dictionary<string, object>;
var wi = d["GetContextWebInformation"] as Dictionary<string, object>;
sFormDigest = wi["FormDigestValue"].ToString();
return sFormDigest;
}
You could use Add-in authentication to access SharePoint data.
You could check my test demo below.
https://social.msdn.microsoft.com/Forums/office/en-US/d33f5818-f112-42fb-becf-3cf14ac5f940/app-only-token-issue-unauthorized-access?forum=appsforsharepoint
I am looking at some documentation that only shows examples of how to send web requests in cURL, however I'm using .NET and am trying to understand how I would send the same requests but using c#
Some examples of the requests I'm trying to send:
curl -X POST -H "Content-Type: application/json" -u "{username}":"{password}" -d #parameters.json "https://gateway.watsonplatform.net/natural-language-understanding/api/v1/analyze?version=2017-02-27"
with example parameters:
{
"text": "IBM is an American multinational technology company headquartered in Armonk, New York, United States, with operations in over 170 countries.",
"features": {
"entities": {
"emotion": true,
"sentiment": true,
"limit": 2
},
"keywords": {
"emotion": true,
"sentiment": true,
"limit": 2
}
}
}
I have made several different attempts to hit the API in C# with no success, always getting a Bad Request response so I must be doing something wrong. Here are some of the attempts I've made:
Attempt 1:
string url = $"{Properties.Settings.Default.WatsonLanguageUnderstandingUrl}/v1/analyze?version=2017-02-27";
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
string auth = $"{Properties.Settings.Default.WatsonLanguageUnderstandingUsername}:{Properties.Settings.Default.WatsonLanguageUnderstandingPassword}";
string auth64 = Convert.ToBase64String(Encoding.ASCII.GetBytes(auth));
string credentials = $"Basic {auth64}";
httpWebRequest.Headers[HttpRequestHeader.Authorization] = credentials;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (StreamWriter streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = JsonConvert.SerializeObject(new
{
features = new
{
entities = new
{
emotion = true,
sentiment = true,
limit = 2
},
keywords = new
{
emotion = true,
sentiment = true,
limit = 2
}
}
});
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var result = streamReader.ReadToEnd();
}
Attempt 2:
var authValue = new AuthenticationHeaderValue(
"Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{Properties.Settings.Default.WatsonLanguageUnderstandingUsername}:{Properties.Settings.Default.WatsonLanguageUnderstandingPassword}")));
var client = new HttpClient() { DefaultRequestHeaders = {Authorization = authValue} };
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var anonString = new
{
text = "IBM is an American multinational technology company headquartered in Armonk, New York, United States, with operations in over 170 countries.",
features = new
{
entities = new
{
emotion = true,
sentiment = true,
limit = 2
},
keywords = new
{
emotion = true,
sentiment = true,
limit = 2
}
}
};
string json = JsonConvert.SerializeObject(anonString);
HttpResponseMessage blah = await client.PutAsync($"{ Properties.Settings.Default.WatsonLanguageUnderstandingUrl}/v1/analyze?version=2017-02-27", new StringContent(json)).ConfigureAwait(false);
Attempt 3:
Dictionary<string, string> parameters = new Dictionary<string, string>
{
{ "version", "2017-02-27" },
{ "features", "sentiment" }
};
string queryParameters = DictToString(parameters);
var thing = new {text = angry };
string json = JsonConvert.SerializeObject(thing);
string url = $"{Properties.Settings.Default.WatsonLanguageUnderstandingUrl}/v1/analyze?{queryParameters}";
string result;
using (WebClient client = new WebClient())
{
client.UseDefaultCredentials = true;
client.Credentials = new NetworkCredential(Properties.Settings.Default.WatsonLanguageUnderstandingUsername, Properties.Settings.Default.WatsonLanguageUnderstandingPassword);
client.Headers[HttpRequestHeader.ContentType] = "application/json";
result = client.UploadString(url, "POST", json);
}
Where my DictToString() method looks like:
private static string DictToString(Dictionary<string, string> dict)
{
StringBuilder builder = new StringBuilder();
foreach (KeyValuePair<string, string> kvp in dict)
{
builder.Append(kvp.Key + "=" + kvp.Value + "&");
}
return builder.ToString();
}
Note that attempt 3 works and returns an ok request, but I can't get attempt 3 to work with all those example parameters and more.
Any help into why my requests aren't working would be great! Thanks
I am receiving multiple records when I expect one record which is the second to last record of json data.
Does anyone have any suggestions on what I might be doing incorrectly?
Sample data:
{
"timestamp":"2017-03-17T17:33:09.156Z",
"dataFrame":"VGVtcDoyOC43MA==",
"fcnt":318,
"port":2,
"rssi":-107,
"snr":0.8,
"sf_used":7,
"id":1489771989156,
"decrypted":true
},
{
"timestamp":"2017-03-17T17:33:16.614Z",
"dataFrame":"SHVtOjQzLjA0",
"fcnt":319,
"port":2,
"rssi":-108,
"snr":2.8,
"sf_used":7,
"id":1489771996614,
"decrypted":true
}
Code:
public ActionResult pir()
{
List<PIRDetailsViewModel> model = new List<PIRDetailsViewModel>();
model.AddRange(getPirDetails("0000acfffe588041"));
model = model.OrderByDescending(x => x.UpdatedTime).ToList();
return View(model);
}
private List<PIRDetailsViewModel> getPirDetails(string deviceID)
{
List<PIRDetailsViewModel> model = new List<PIRDetailsViewModel>();
try
{
WebRequest req = WebRequest.Create(#"https:example.com");
req.Method = "GET";
req.Headers["Authorization"] = "Basic " + "password==";
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
var encoding = resp.CharacterSet == "" ? Encoding.UTF8 : Encoding.GetEncoding(resp.CharacterSet);
using (var stream = resp.GetResponseStream())
{
var reader = new StreamReader(stream, encoding);
var responseString = reader.ReadToEnd();
List<PIRDetail> Pirs = Newtonsoft.Json.JsonConvert.DeserializeObject <List<PIRDetail>>(responseString);
foreach (var item in Pirs)
{
byte[] data = Convert.FromBase64String(item.dataFrame.ToString());
PIRDetailsViewModel binModel = new PIRDetailsViewModel();
binModel.deviceid = deviceID;
binModel.status = Convert.ToString(Encoding.UTF8.GetString(data).Substring(4));
binModel.UpdatedTime = TimeZoneInfo.ConvertTimeFromUtc(item.timestamp, TimeZoneInfo.FindSystemTimeZoneById("India Standard Time")).ToString();
model.Add(binModel);
}
}
}
catch (Exception Ex)
{
}
return model;
}
The above code only returns multiple records, but I am trying to get the second to last record that is being returned each time this code is ran.
I'm rewriting. Based on comments, I think you want something more like below (loop not necessary):
List<PIRDetail> Pirs = Newtonsoft.Json.JsonConvert.DeserializeObject <List<PIRDetail>>(responseString);
var item = Pirs[Pirs.Count -2];
byte[] data = Convert.FromBase64String(item.dataFrame.ToString());
PIRDetailsViewModel binModel = new PIRDetailsViewModel();
binModel.deviceid = deviceID;
binModel.status = Convert.ToString(Encoding.UTF8.GetString(data).Substring(4));
binModel.UpdatedTime = TimeZoneInfo.ConvertTimeFromUtc(item.timestamp, TimeZoneInfo.FindSystemTimeZoneById("India Standard Time")).ToString();
model.Add(binModel);
HttpResponse response;
request.AllowAutoRedirect = false;
request.UserAgent = HttpHelper.IEUserAgent();
response = request.Post("https://www.site.com", "value=1");
But after request, program trys to open file value=1. Why?
Try this option, code:
using (var request = new HttpRequest())
{
request.UserAgent = HttpHelper.RandomUserAgent();
request.Proxy = Socks5ProxyClient.Parse("127.0.0.1:1080");
var reqParams = new StringDictionary();
reqParams["login"] = "neo";
reqParams["password"] = "knockknock";
string content = request.Post(
"www.whitehouse.gov", reqParams).ToText();
string secretsGovernment = content.Substring("secrets_government=\"", "\"");
}
And read documentation here
Post(string address, string path) - send file. You can set the parameters as:
1:
using (var request = new HttpRequest())
{
var reqParams = new RequestParams();
reqParams["login"] = "neo";
reqParams["password"] = "knockknock";
string content = request.Post(
"www.whitehouse.gov", reqParams).ToString();
}
2:
using (var request = new HttpRequest("www.whitehouse.gov"))
{
request
.AddParam("login", "neo")
.AddParam("password", "knockknock");
string content = request.Post("/").ToString();
}
3:
using (var request = new HttpRequest())
{
var reqParams = new Dictionary<string, string>()
{
{"login", "neo"},
{"password", "knockknock"},
};
var httpContent = new FormUrlEncodedContent(reqParams);
string content = request.Post(
"www.whitehouse.gov", httpContent).ToString();
}
4:
using (var request = new HttpRequest())
{
string reqStr = "param1=value1¶m2=value2";
string content = request.Post(
"www.whitehouse.gov", reqStr,
"application/x-www-form-urlencoded").ToString();
}