I was wondering how can I make a post from a json to an http server.
The code I'm using to do json is as follows:
pedro product = new pedro();
product.FirtsName = "Ola";
product.ID = 1;
product.idade= 10;
string json = JsonConvert.SerializeObject(product);
And this is the pedro class:
public class pedro
{
public int ID { get; set; }
public string FirtsName { get; set; }
public int idade { get; set; }
}
With WebApi, you can use something like this:
string url = "http://url.of.server/";
Pedro product = new Pedro();
product.FirtsName = "Ola";
product.ID = 1;
product.Idade = 10;
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = client.PostAsJsonAsync(url, product).Result;
if (response.IsSuccessStatusCode)
{
// do something
}
}
If you're not using WepApi there are many similar methods, for instance: https://stackoverflow.com/a/39414248/7489072
Don't Base64 encode the body of your post, as suggested in the comments, unless you absolutely must / want to post binary files AND have control over the receiving webserver. Webservers in 99% of the cases expect a plain text body.
If you need to post characters outside the ASCII range, use the correct HTTP headers to specify a Unicode body load.
Update 1 (headers):
The HttpClient class has property DefaultRequestHeaders that can be used to set common request headers, such as AcceptEncoding. If you need a more fine grained control of the content headers, use .PostAsync(string uri, HttpContent content) in stead of .PostAsJsonAsync (that just sets some default headers for Json content)
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string stringFromObject = JsonConvert.SerializeObject(product);
HttpContent content = new StringContent(stringFromObject, Encoding.UTF8, "application/json");
content.Headers.Add("YourCustomHeader", "YourParameter");
HttpResponseMessage response = client.PostAsync(url, content).Result;
if (response.IsSuccessStatusCode)
{
// do something
}
}
Update 2 (encoding):
To elaborate more on the encoding comments: of course you should escape quotes and the likes. But this is part of the Json standard and should be handled by common encoders / decoders. On top of that, you can use any further encoding for the properties of your serialized object. For instance HTML-encoding on strings and Base64 on binary properties. As long as you know the webserver receiving it will decode it properly.
{
"id": 3,
"title": "Decode this",
"description": "this is < HTML encoded >",
"profileImgBase64": "Nzg5MzQ4IHdleWhmQVMmKihFJiphc3R5WUdkdCphc14qVHlpZg0K"
}
So encode individual properties, but don't encode the whole Json payload, as you would have to decode it at the beginning of the receiving pipeline and it's just not something webservers will understand.
Related
I have a Rest API written in .Net core that accepts a File as input as Multipart/Form-data. The API works absolutely fine when I run it from Swagger/Postman.
Here is the API endpoint.
[HttpPost("CreateStudy")]
public ActionResult CreateStudy([FromForm] APIRequest request)
{
// rest of the code
Also here is the APIRequest object. it has only one property which is IFormFile Type.
public class APIRequest
{
public IFormFile XMLFile { get; set; }
}
So far it works well. The problem is that I am trying to write a client side code that will call this API and pass the File from C# code.
But I am always getting a 400-Bad request in the client code.
This is the client code I am trying with.
public string CallServiceWithFileAsync(string EndPointURL, string FilePath)
{
string ResultStatusCode;
Uri uri = new Uri(EndPointURL);
var Client = new HttpClient();
Client.DefaultRequestHeaders.Clear();
//Prepare Message
HttpRequestMessage Message = new HttpRequestMessage();
Message.Method = HttpMethod.Post;
Message.Headers.Add("Accept", "application/octet-stream");
Message.RequestUri = new Uri(EndPointURL);
using (Stream fileStream = File.OpenRead(FilePath))
{
var content = new StreamContent(fileStream);
var response = Client.PostAsync(uri, content);
ResultStatusCode = response.Result.StatusCode.ToString();
}
return ResultStatusCode;
}
What am I doing wrong here? What is the correct way of sending a file into REST endpoint ?
[FromForm] expects an accept header with application/x-www-url-formencoded. If this is not the case, check your output-logs to see why the request is not processed.
I am trying to send a POST request when using HttpClient. When I run the code I am getting an unauthorized response. But I am able to get it to work in PostMan. Below is my current code snippet and pictures of what I am trying to perform. I'd like to add I am trying to send a json string in my body.
using (HttpClient client = new HttpClient())
{
var connectionUrl = "https://api.accusoft.com/prizmdoc/ViewingSession";
var content = new Dictionary<string, string> { { "type", "upload" }, { "displayName", "testdoc" } };
// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(content);
// Wrap our JSON inside a StringContent which then can be used by the HttpClient class
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
//client.DefaultRequestHeaders.Add("Acs-Api-Key", "aPsmKCmvkZHf9VakCmfHB8COmzRxXY5FDhj8F1FU1IGmQlOkfjiKESKxfm38lhey");
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Acs-Api-Key", "aPsmKCmvkZHf9VakCmfHB8COmzRxXY5FDhj8F1FU1IGmQlOkfjiKESKxfm38lhey");
// Do the actual request and await the response
var httpResponse = httpClient.PostAsync(connectionUrl, httpContent).Result;
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
// Do something with response. Example get content:
var connectionContent = httpResponse.Content.ReadAsStringAsync().Result;
}
else
{
// Handle a bad response
return;
}
}
}
You're using two HttpClients when you only need to use one.
using (HttpClient client = new HttpClient())
and
using (var httpClient = new HttpClient())
The second one (httpClient) is doing the post but the authentication header has been added to client. Just remove the second one (httpClient) and make sure you use client.PostAsync(...) to send the request.
I'd also consider using await, rather than .Result (see why here) when sending the request:
var httpResponse = await client.PostAsync(connectionUrl, httpContent);
In addition to haldo's answer,
In your code, you are adding your Acs-Api-Key header as and Authorization header, meaning it ends up looking like Authorization: Acs-Api-Key (key) rather than Acs-Api-Key: (key) which is what you have in PostMan.
Instead of adding it as an Authorization header, just add it as a regular header.
client.DefaultRequestHeaders.Add("Acs-Api-Key","(key)");
Also something else that may cause issues is that you aren't wrapping your content in the "source" object like you are in PostMan. There are a couple ways of doing this
The first would be to simply wrap it in it's string format:
stringPayload = $"\"source\":{{{stringPayload}}}"
Or you can do it before you serialize by making your own object instead of having a Dictionary
var content = new PayloadObject(new Source("upload", "testdoc"));
var stringPayload = JsonConvert.SerializeObject(content);
// Send the request
class PayloadObject{
Source source {get; set;}
PayloadObject(Source source){
this.source = source;
}
}
class Source{
string type {get; set;}
string displayName {get; set;}
Source(string type, string displayName){
this.type = type;
this.displayName = displayName;
}
}
I have a rest endpoint that accepts a single custom object parameter containing two properties.
Let's call the param InfoParam
public class InfoParam
{
public long LongVar { get; set; }
public string StringVar { get; set; }
}
My code I have is as follows:
infoParam.LongVar = 12345678;
infoParam.StringVar = "abc"
var myRequest = (HttpWebRequest)WebRequest.Create(url);
myRequest.Method = "POST";
var content = string.Empty;
using (var theResponse = (HttpWebResponse)MyRequest.GetResponse())
{
using (var stream = theResponse.GetResponseStream())
{
using (var sr = new StreamReader(stream))
{
content = sr.ReadToEnd();
}
}
}
So I have the InfoParam variable, with the two values, but I can't figure out where to pass it in to the REST endpoint.
You need to turn the object into a stream of bytes that can be added to the Request stream - which will in turn be sent as the HTTP POST body. The format of these bytes needs to match what the server expects. REST endpoints usually expect these bytes to resemble JSON.
// assuming you have added Newtonsoft.JSON package and added the correct using statements
using (StreamWriter writer = new StreamWriter(myRequest.GetRequestStream()) {
string json = JsonConvert.SerializeObject(infoParam);
writer.WriteLine(json);
writer.Flush();
}
You'll probably want to set various other request parameters, like the Content-Type header.
You have to write it int the `Content (and set content-type). Check out How to: Send data by using the WebRequest class
The recommendation is to use System.Net.Http.HttpClient instead.
Please note that you should know what content the server expects ('application/x-www-form-urlencoded`, json, etc.)
The following snippet is from POST JSON data over HTTP
// Construct the HttpClient and Uri. This endpoint is for test purposes only.
HttpClient httpClient = new HttpClient();
Uri uri = new Uri("https://www.contoso.com/post");
// Construct the JSON to post.
HttpStringContent content = new HttpStringContent(
"{ \"firstName\": \"Eliot\" }",
UnicodeEncoding.Utf8,
"application/json");
// Post the JSON and wait for a response.
HttpResponseMessage httpResponseMessage = await httpClient.PostAsync(
uri,
content);
// Make sure the post succeeded, and write out the response.
httpResponseMessage.EnsureSuccessStatusCode();
var httpResponseBody = await httpResponseMessage.Content.ReadAsStringAsync();
Debug.WriteLine(httpResponseBody);
In your case the content would be something like this
HttpStringContent content = new HttpStringContent(
JsonConvert.SerializeObject(infoParam), // using Json.Net;
UnicodeEncoding.Utf8,
"application/json");
I'm trying to consume data in my front-end which calls a API Broker and this API Broker calls my API. In my front-end I'm getting JSON data returned JSON with alot of backslashes in it. How can i prevent this? see code and errors below:
Consuming my API in my front-end:
[HttpGet]
public async Task<ActionResult> getCall()
{
string url = "http://localhost:54857/";
string operation = "getClients";
using (var client = new HttpClient())
{
//get logged in userID
HttpContext context = System.Web.HttpContext.Current;
string sessionID = context.Session["userID"].ToString();
//Create request and add headers
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
//Custom header
client.DefaultRequestHeaders.Add("loggedInUser", sessionID);
//Response
HttpResponseMessage response = await client.GetAsync(operation);
if (response.IsSuccessStatusCode)
{
string jsondata = await response.Content.ReadAsStringAsync();
return Content(jsondata, "application/json");
}
return Json(1, JsonRequestBehavior.AllowGet);
}
}
My Api Broker gets the request and executes this:
As you can see the response content contains alot of backslashes.
This response is going back to my front-end where i receive the following content:
In this response there are even more backslashes added.
I hope someone recognizes this problem and knows a solution.
Thanks in advance!
I fixed it by serializing the string to a JSON object and than deserialize it .
There is StringContent class in System.Net.Http namespace. What purposes should I use class StringContent for?
StringContent class creates a formatted text appropriate for the http server/client communication. After a client request, a server will respond with a HttpResponseMessageand that response will need a content, that can be created with the StringContent class.
Example:
string csv = "content here";
var response = new HttpResponseMessage();
response.Content = new StringContent(csv, Encoding.UTF8, "text/csv");
response.Content.Headers.Add("Content-Disposition",
"attachment;
filename=yourname.csv");
return response;
In this example, the server will respond with the content present on the csv variable.
It provides HTTP content based on a string.
Example:
Adding the content on HTTPResponseMessage Object
response.Content = new StringContent("Place response text here");
Whenever I want to send an object to web api server I use StringContent to add format to HTTP content, for example to add Customer object as json to server:
public void AddCustomer(Customer customer)
{
String apiUrl = "Web api Address";
HttpClient _client= new HttpClient();
string JsonCustomer = JsonConvert.SerializeObject(customer);
StringContent content = new StringContent(JsonCustomer, Encoding.UTF8, "application/json");
var response = _client.PostAsync(apiUrl, content).Result;
}
Every response that is basically text encoded can be represented as StringContent.
Html reponse is text too (with proper content type set):
response.Content = new StringContent("<html><head>...</head><body>....</body></html>")
On the other side, if you download/upload file, that is binary content, so it cannot be represented by string.