I'm trying to post a long string (containing XML) to my Web API controller, but I'm failing miserablely.
The following works if TextAsXml is short, but when TextAsXml is long it fails "Invalid URI: The Uri string is too long.", which is understandable.
// Client code
using (var client = new HttpClient())
{
var requestUri = "http://localhost:49528/api/some";
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("Author", "John Doe"),
new KeyValuePair<string, string>("TextAsXml", "<?xml version=\"1.0\" encoding=\"UTF-8\"?><note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>")
});
var response = client.PostAsync(requestUri, content).Result;
response.EnsureSuccessStatusCode();
}
// Controller code
public HttpResponseMessage Post(SomeModel someModel)
{
// ...
return Request.CreateResponse(HttpStatusCode.OK);
}
public class SomeModel
{
public string Author { get; set; }
public string TextAsXml { get; set; }
}
How do I get the above code to work when TextAsXml is long? I tried playing around with StringContent and MultipartContent, but couldn't get it to work.
// This results in 500 Internal server error.
using (var client = new HttpClient())
{
var requestUri = "http://localhost:49528/api/some";
var textAsXml = File.ReadAllText("Note.xml");
var content = new MultipartFormDataContent();
content.Add(new StringContent("John Doe"), "Author");
content.Add(new StringContent(textAsXml), "TextAsXml");
var response = client.PostAsync(requestUri, content).Result;
response.EnsureSuccessStatusCode();
}
Send the XML as content without Uri encoding.
Related
I'm working on an application to make api get, post, delete, update requests on c # windowsforms.
My problem is: I want to send a parameter in "Body" when requesting a get. How can I do that ?
using System.Net.Http;
using System;
using System.Threading.Tasks;
using HastaTakip.Models;
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Text;
namespace HastaTakip.Api
{
public class CustomersRepository
{
public HttpClient _client;
public HttpResponseMessage _response;
public HttpRequestMessage _requestMessage;
public CustomersRepository()
{
_client = new HttpClient();
_client.BaseAddress = new Uri("http://localhost:3000/");
_client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6ImZ0aG1seW16QGhvdG1haWwuY29tIiwidXNlcklkIjoxLCJpYXQiOjE2MTM5MDY5NDMsImV4cCI6MTYxNDA3OTc0M30.NER1RMTYx41OsF26pjiMXY-pLZTE-pIg4Q73ehwGIhA");
_client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<CustomersModel> GetList()
{
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("business_code", "dental")
});
_response = await _client.GetAsync(content);
var json = await _response.Content.ReadAsStringAsync();
var listCS = CustomersModel.FromJson(json);
return listCS;
}
}
}
to send a GET request with a JSON body:
HttpClient client = ...
...
var request = new HttpRequestMessage
{
Method = HttpMethod.Get,
RequestUri = new Uri("some url"),
Content = new StringContent("some json", Encoding.UTF8, ContentType.Json),
};
var response = await client.SendAsync(request).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
But HTTP GET with a body is a somewhat unconventional construct that falls in a gray area of the HTTP specification!
You better create a class for your content data:
public class RequestData
{
pubic string BusinessCode {get; set;}
{
After this you can create your content object
public async Task<CustomersModel> GetList()
{
var data=new RequestData{BusinessCode="dental"}
var stringData = JsonConvert.SerializeObject(data);
contentData = new StringContent(stringData, Encoding.UTF8, "application/json");
var response = await _client.GetAsync(contentData);
// but I am not sure that Get will work correctly so I recommend to use
var response = await _client.PostAsync(contentData);
if (response.IsSuccessStatusCode)
{
var stringData = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<CustomersModel>(stringData);
}
else
{
....error code
}
}
I am using the HttpClient in C# to try and integrate SSO (Single Sign On) into some of our custom Applications.
I have done this successfully in our JavaScript Apps, but I'm having some difficulty integrating it into some of our Umbraco sites.
My code so far:
using System;
using System.Threading.Tasks;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Web;
using System.Web.Http;
using Newtonsoft.Json;
using System.Collections.Generic;
using Umbraco.Web;
using Umbraco.Web.WebApi;
namespace Umbraco.WebApi
{
public class TestController : UmbracoApiController
{
public HttpClient client = new HttpClient();
[HttpPost]
public async Task<Object> GetRefreshToken(Token t)
{
try {
string refToken = t.refresh_token;
var values = new Dictionary<string, string>
{
{ "grant_type", "refresh_token" },
{ "client_id", "CLIENTID" },
{ "client_secret", "CLIENTSECRET" },
{ "refresh_token", refToken }
};
var content = new FormUrlEncodedContent(values);
var response = await client.PostAsync("https://URL.org/Token", content);
string responseString = await response.Content.ReadAsStringAsync();
return responseString;
} catch(HttpRequestException e) {
return e;
}
}
public class Token
{
public string refresh_token { get; set; }
}
public class AuthData
{
public string access_token { get; set; }
public string token_type { get; set; }
public int expires_int { get; set; }
public string refresh_token { get; set; }
public string userName { get; set; }
public string client_id { get; set; }
public DateTime issued { get; set; }
public DateTime expires { get; set; }
}
}
}
Which does successfully return the data I'm after but there are issues with the returned data (Removed sensitive data):
<z:anyType xmlns:d1p1="http://www.w3.org/2001/XMLSchema" xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" i:type="d1p1:string">
{"access_token":"XXXXXXXX","token_type":"bearer","expires_in":1199,"refresh_token":"XXXXXX","userName":"XXXXXX","as:client_id":"XXXXX",".issued":"Fri, 20 Sep 2019 13:23:48 GMT",".expires":"Fri, 20 Sep 2019 13:43:48 GMT"}
</z:anyType>
It also seems to be getting returned as XML instead of JSON?
C# is not my strongest of languages, so I may be completely wrong.
Any help appreciated.
In your code, after you get the JSON string responseString, instead of returning it, try the following code.
...
string responseString = await response.Content.ReadAsStringAsync();
response = Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(responseString, Encoding.UTF8, "application/json");
return response;
You need to change your method return value from Task<Object> to Task<HttpResponseMessage>
Edit:
To access the properties, install the Newtonsoft.Json package and try below code.
var jsonString = ...
JObject jo = JObject.Parse(jsonString);
Console.WriteLine(jo["access_token"]);
One of the things you can do to resolve this is to specifically request a json format on your response by adding the corrent request headers
Accept: application/json
try it like so
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
Now if the server pays attentions to the request headers it will return a json back to you.
It might be defaulting to xml because there is no such header in your request OR the server only supports returning xml responses.
EDIT: If you can not get the server to return json, you can convert your xml string response to json string. Take a look at this example. After the convertsion you can return your json string normally from your controller.
Edit:
Ok, try out this sample below:
var content = new FormUrlEncodedContent(new[]
{
new KeyValuePair<string, string>("client_id", ""),
new KeyValuePair<string, string>("scope", ""),
new KeyValuePair<string, string>("grant_type", "authorization_code"),
new KeyValuePair<string, string>("redirect_uri", ""),
new KeyValuePair<string, string>("code", ""),
new KeyValuePair<string, string>("client_secret","")
});
AADTokenResponse TokenResponse = null;
string _baseAddress = string.Format("https://yourTargetDomain.com/");
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(_baseAddress);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
var responseMessage = await client.PostAsync("targetApiSegment", content);
if (responseMessage.IsSuccessStatusCode)
{
var responseString = await responseMessage.Content.ReadAsStringAsync();
TokenResponse = JsonConvert.DeserializeObject<AADTokenResponse>(responseString);
}
}
I think in this case, FormUrlEncodedContent is the wrong choice, and you'd want to use StringContent instead, similar to this:
var content = new StringContent(HttpUtility.UrlEncode(values), Encoding.UTF8, "application/json");
var response = await client.PostAsync("https://URL.com/Token", content);
The reason being, I dont think FormUrlEncodeContent has an overload to accept adding content type.
Another alternative would be to switch to using SendAsync rather than PostAsync, as SendAsync has some additional flexibility.
this is my client code
var client = new HttpClient();
client.BaseAddress = new Uri(BASE_URL);
var multipart = new MultipartFormDataContent();
var jsonToSend = JsonConvert.SerializeObject(template, Formatting.None);
var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
multipart.Add(body, "JsonDetails");
return client.PostAsync("jsons", multipart);
server code is
[HttpPost("jsons")]
public async Task<IActionResult> RequestJson([FromBody]Person person)
{
if (person != null)
{
return Ok("true");
}
return Ok("false");
person code
public class Person
{
public string Name { get; set; }
public string Position { get; set; }
}
when look in debug my post from client dont knock to server, in postman my post sending and i can see my object property
Just post the StringContent directly without the Multipart-Form:
var client = new HttpClient
{
BaseAddress = new Uri(BASE_URL)
};
var jsonToSend = JsonConvert.SerializeObject(template, Newtonsoft.Json.Formatting.None);
var body = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
return client.PostAsync("jsons", body)
when i run the client code it gives me a 500 error.Since am still new to web api subject , I really appreciate the help, to identify where was my mistake.
using (HttpClient client = new HttpClient())
{
ObjHeader.listRtnTalleySheetHeader = lstRtnTalleySheetHeader;
ObjHeader.listRtnTalleySheetDetail = lstRtnTalleySheetDetail;
client.BaseAddress = new Uri("http://---service---");
var url = "api/config/InsertTalleydetail/";
var alldetails = Newtonsoft.Json.JsonConvert.SerializeObject(ObjHeader);
HttpContent content = new StringContent(alldetails, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
val = "Ok";
else
val = "No";
}
return val;
which the ObjHeader is clsAllTalleyHeaderDetail ObjHeader = new clsAllTalleyHeaderDetail();
clsAllTalleyHeaderDetail is
public class clsAllTalleyHeaderDetail
{
public ObservableCollection<clsTalleySheetHeader> listRtnTalleySheetHeader { get; set; }
public ObservableCollection<clsTalleySheetDetail> listRtnTalleySheetDetail { get; set; }
}
then my WEb API
[HttpPost]
public HttpResponseMessage InsertTalleydetail([FromBody] clsAllTalleyHeaderDetail obj)
{
return todoService.InsertTalleydetail(obj.listRtnTalleySheetHeader , obj.listRtnTalleySheetDetail );
}
1) For your main api you have to set Content-Type header to application/json in HttpClient like
client.DefaultRequestHeaders.Add("Content-Type","application/json");
2) For your sample api you have to set Content-Type header to application/json in postman with your raw format.
I'd like to be able to read a post variable from my controller method.
I currently have the below code:
[HttpPost]
public IHttpActionResult BuildPartitions([FromBody]string PartitionBuildDate)
{
}
I'm using the below code to test:
using (HttpClient httpClient = new HttpClient())
{
var values = new Dictionary<string, string>
{
{ "PartitionBuildDate", "24-May-2017" }
};
var content = new FormUrlEncodedContent(values);
var response = httpClient.PostAsync("http://localhost:55974/api/Controller/BuildPartitions", content);
var responseString = response.Result.Content;
}
Looking online, this looks correct for both sending and receiving a post variable in C#, however the PartitionBuildDate variable is always null.
Try adding the content-type header. I have used Newtonsoft JSON.NET for JSON conversion:
string postBody = JsonConvert.SerializeObject(yourDictionary);
var response = client.PostAsync(url, new StringContent(postBody, Encoding.UTF8, "application/json"));
var responseString = response.Result.Content;
Also, on your web API side, try wrapping your POST parameters inside a class:
public class PostParameters
{
public string PartitionBuildDate {get;set;}
}
[HttpPost]
public IHttpActionResult BuildPartitions([FromBody]PostParameters parameters)
{
//you can access parameters.PartitionBuildDate
}