I have webforms asp and web api. In web forms I try send to web api object of class this way:
HttpClient client = HttpClientHeader("", login, ClassMd5Calc.CalculateMd5Hash(password));
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
UserTariff userTariff = new UserTariff();
userTariff.Login = "some value";
userTariff.Password = "some value";
userTariff.TariffName = "some value";
var json = new JavaScriptSerializer().Serialize(userTariff);
StringContent content = new StringContent(json);
content.Headers.ContentType = new MediaTypeHeaderValue("text/json");
HttpResponseMessage response = client.PostAsync("api/ChangeTariff/", content).Result;
This is my class (exist in data contract solution, so both project are use this class).
[Serializable]
public class UserTariff
{
public String Login { get; set; }
public String Password { get; set; }
public String TariffName { get; set; }
public decimal Balance { get; set; }
}
My web api receive package, but all field are null. What's wrong? How it's fix?
public class ChangeTariffController : ApiController
{
public void Post([FromBody] UserTariff mes)
{
//mes exist, but his property are null: mes.Login=null; mes.Password=null and e.t.c. but need value: "some value"
UPDATE 1.
I also tryed this code, but it show same error:
var content = new ObjectContent<UserTariff>(new UserTariff(), new JsonMediaTypeFormatter());
content.Headers.ContentType = new MediaTypeHeaderValue("text/json");
HttpResponseMessage response = client.PostAsync("api/ChangeTariff/", content).Result;
You can set the object content instead of the string content and should be using json media type formatter. This should fix the null bound variable in web api.
Also, use the newton soft json lib to convert the object to json.
Related
I am trying to make a post request from WPF to Web API using the following code but the request parameter is always null.
Request Model
public class Document
{
public string FileName { get; set; }
public byte[] Buffer { get; set; }
}
public class Request
{
public string Uploader { get; set; }
public List<Document> Documents { get; set; }
}
WPF Client
var obj = new Request()
{
Uploader = "John Doe",
Documents = new List<Document>
{
new Document()
{
FileName ="I Love Coding.pdf",
Buffer = System.IO.File.ReadAllBytes(#"C:\Users\john.doe\Downloads\I Love Coding.pdf.pdf")
}
}
};
using (var http = new HttpClient())
{
var encodedJson = JsonConvert.SerializeObject(obj);
var conent = new StringContent(encodedJson, Encoding.UTF8, "application/json");
HttpResponseMessage response = await http.PostAsync("https://my-app.com/api/upload", conent);
response.EnsureSuccessStatusCode();
}
Web API
[Route("")]
public class AppController : ControllerBase
{
[HttpPost]
[Route("api/upload")]
public async Task<IActionResult> UploadDocumentsAsync([FromBody] Request request)
{
// request is always null when app is running in production
// https://my-app.com/api/upload
//request is not null when running on https://localhost:8080/api/upload
}
}
Please what am I missing in the above implementation?
The request parameter is not null on localhost but always null in production.
Please what am I missing in the above implementation? The request
parameter is not null on localhost but always null in production.
Well, not sure how are getting data on local server becuse, you are sending MultipartFormData means your POCO object and file buffer. As you may know we can send json object in FromBody but not the files as json. Thus, I am not sure how it working in local and getting null data is logical in IIS Or Azure.
what am I missing in the above implementation?
As explained above, for sending both POCO object and Files as byte or steam we need to use FromForm and beside that, we need to bind our request object as MultipartFormDataContent to resolve your null data on your UploadDocumentsAsync API action.
Required Change For Solution:
WPF:
In your WPF http request please update your request code snippet as following:
var obj = new Request()
{
Uploader = "John Doe",
Documents = new List<Document>
{
new Document()
{
FileName ="I Love Coding.pdf",
Buffer = System.IO.File.ReadAllBytes(#"YourFilePath")
}
}
};
var httpClient = new HttpClient
{
BaseAddress = new("https://YourServerURL")
};
var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(obj.Uploader), "Uploader");
formContent.Add(new StringContent(obj.Documents[0].FileName), "Documents[0].FileName");
formContent.Add(new StreamContent(new MemoryStream(obj.Documents[0].Buffer)), "Documents[0].Buffer", obj.Documents[0].FileName);
var response = await httpClient.PostAsync("/api/upload", formContent);
if (response.IsSuccessStatusCode)
{
var responseFromAzureIIS = await response.Content.ReadAsStringAsync();
}
Note: Class in WPF side would remain same as before. No changes required.
Asp.net Core Web API:
In asp.net core web API side you should use [FromForm] instead of [FromBody]
So your controller Action would as following:
[Route("")]
public class AppController : ControllerBase
{
[HttpPost]
[Route("api/upload")]
public async Task<IActionResult> UploadDocumentsAsync([FromForm] Request file)
{
if (file.Documents[0].Buffer == null)
{
return Ok("Null File");
}
return Ok("File Received");
}
}
Note: For remote debugging I have checked the logs and for double check I have used a simple conditionals whether file.Documents[0].Buffer == null. I have tested both in local, IIS and Azure and working accordingly.
Update POCO Class in API Project:
For buffer you have used byte for your WPF project but for Web API project update that to IFormFile instead of byte. It should be as following:
public class Document
{
public string FileName { get; set; }
public IFormFile Buffer { get; set; }
}
public class Request
{
public string Uploader { get; set; }
public List<Document> Documents { get; set; }
}
Output:
If you would like to know more details on it you could check our official document here
Here is my question,
I got a Web API and client(winform), client will send out data with a Serialize Object. My Web API do have received and return a response to client. But I can't view the data on Web API, I do have try using Deserialize Object and convert it into string but not working neither.
Please help me,Thanks!
Here is my code:
Client
private string WebApiPost(string sParam, string sJson)
{
var client = new HttpClient();
var content = new StringContent(sJson, Encoding.UTF8, "application/json");
var response = client.PostAsync(sWebAPI_URL + sParam, content).Result;
var body = response.Content.ReadAsStringAsync().Result;
return body;
}
This is my Web API
public object Post([FromBody]object hL7)
{
//what should I do???
//I've tried set hL7 into string but it wont get any data;
//I've also tried deserialize it but will get 500 internal server error.
return hL7;
}
This is my WebAPI model
public class HL7MID
{
public string LOC { get; set; }
public string COMPANY { get; set; }
}
public class HL7MID_List
{
public string sMSG { get; set; }
public List<HL7MID> data = new List<HL7MID>();
}
Because sJson matches HL7MID, you can use that type in as a paramter of your Post function, and just use that type.
public HL7MID Post([FromBody]HL7MID hL7)
{
//use hL7 here
return hL7;//also since you know the return type, changing that to HL7MID is suggested
}
I am doing an MVC 5 Application, and I am calling a API controller method that is in another Solution.
I am using HttpClient(). and I am calling PostAsJsonAsync with some parameters, an instance of a class.
It looks like this.
string apiUrl = "localhost:8080/api/";
ContactWF contactWF = new contactWF();
contactWF.contact_id=0;
contactWF.UserOrigin_id=20006
contactWF.ProcessState_id=2;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.PostAsJsonAsync(apiUrl + "Contact/Method", contactWF);
if (response.IsSuccessStatusCode)
{
return response.Content.ReadAsAsync<int>().Result;
}
}
My API controller method is like this.
[ActionName("Method")]
[HttpGet]
public int Method([FromBody] ContactWF userwf)
{
return 10;
}
It Works fine...
My problem is when I try Serialized the parameter class instance
I replace line
HttpResponseMessage response = await client.PostAsJsonAsync(apiUrl + "Contact/Method", contactWF);
with this one
string jsonData = JsonConvert.SerializeObject(contactWF);
HttpResponseMessage response = client.PostAsJsonAsync("api/Contact/Method", jsonData).Result;
I've got an Error:405...
It looks like the Json string it is not recognize as a Parameter.
My Json string looks like this.
"{\"Contact_id\":0,\"Description\":null,\"ProcessState_id\":2,\"Type_id\":0,\"Object_id\":0,\"Parent_id\":null}"
that is ContactWD class converter to json.
What´s wrong?
Method PostAsJsonAsync serialize parameter object himself, so it serialized your json string again.
If you need serialize object himself for some reason, then use method HttpClient.PostAsync
string jsonData = JsonConvert.SerializeObject(contactWF);
var stringContent = new StringContent(jsonData, Encoding.UTF8, "application/json");
HttpResponseMessage response = await client.PostAsync("api/Filler/CountMensajeByUser", stringContent);
Change verb to HttpPost in your api controller
[ActionName("Method")]
[HttpPost]
public int Method([FromBody] ContactWF userwf)
{
return 10;
}
Update
You don't need to serialize object in PostAsJsonAsync
HttpResponseMessage response = client.PostAsJsonAsync("api/Contact/Method", contactWF).Result;
Take a look at sample code from microsoft
https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/testing
internal class NewIdeaDto
{
public NewIdeaDto(string name, string description, int sessionId)
{
Name = name;
Description = description;
SessionId = sessionId;
}
public string Name { get; set; }
public string Description { get; set; }
public int SessionId { get; set; }
}
//Arrange
var newIdea = new NewIdeaDto("Name", "", 1);
// Act
var response = await _client.PostAsJsonAsync("/api/ideas/create", newIdea);
// Assert
Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
I am posting an object to a WebApi method. I'm using PostAsJsonAsync to do this.
public async Task<HttpResponseMessage> PostAsync(string token, ServiceCall call)
{
var client = new HttpClient();
client.SetBearerToken(token);
var response = await client.PostAsJsonAsync(Uri + "id/nestedcall", call);
return response;
}
The object call that I'm passing is not null when I post it.
[HttpPost]
[Route("id/nestedcall")]
public async Task<IHttpActionResult> NestedCall([FromBody]ServiceCall call)
{
// call is null here
}
However it is null in my API method. I can't seem to work out why as all of the examples I've followed use this format.
Why isn't the call object being picked up by the web api?
Edit
Here is the ServiceCall object. It is in a separate class library and a reference is included in both the web application and the API.
public class ServiceCall
{
public ServiceCall(Service service, string grantType)
{
ClientId = service.Id;
ClientSecret = service.Secret;
Uri = service.Uri;
Scope = service.Scope;
GrantType = grantType;
}
public ServiceCall(string clientid, string clientsecret, string uri, string scope, string grantType)
{
ClientId = clientid;
ClientSecret = clientsecret;
Uri = uri;
Scope = scope;
GrantType = grantType;
}
public string ClientId { get; set; }
public string ClientSecret { get; set; }
public string Uri { get; set; }
public string Scope { get; set; }
public string GrantType { get; set; }
}
I have seen Object null in WebApi method after PostAsJsonAsync due to serialization.
Better to use PostAsync like below :
var obj = new MyClass()
{
MyProperty = 11
};
using (var client = new HttpClient())
{
string inputJson = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
HttpContent inputContent = new StringContent(inputJson, Encoding.UTF8, "application/json");
HttpResponseMessage response1 = client.PostAsync("http://localhost:60909/api/home/Test", inputContent).Result;
if (response1.IsSuccessStatusCode)
{
}
}
Using Prefix Stackify I was able to diagnose that the serialiser was throwing an exception:
Newtonsoft.Json.JsonSerializationException: Unable to find a constructor to use for type Core.Models.ServiceCall. A class should either have a default constructor, one constructor with arguments or a constructor marked with the JsonConstructor attribute. Path 'ClientId', line 1, position 12.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize
However, very helpfully, rather than tell me that an exception occurred the controller simply gave me a null object.
As hinted by the exception the solution is to add a default constructor (or at least one the serialiser can understand).
public ServiceCall()
{
}
looks like the JSON serialization may be failing. BTW, remove that [FromBody] and try without it like below. PostAsJsonAsync method serializes the ServiceCall object to JSON and then sends the JSON payload in a POST request.
public async Task<IHttpActionResult> NestedCall(ServiceCall call)
{
// your code
}
I run into exactly the same problem and had to do this to solve it:
using (var client = new HttpClient())
{
client.SetBearerToken(token);
var content = new StringContent(JsonConvert.SerializeObject(call), Encoding.UTF8, "application/json");
var response = await client.PostAsJsonAsync(Uri + "id/nestedcall", content);
return response;
}
I am trying to create a JSON object in a .Net 5 application. The default options I am presented with are Microsoft.AspNet.Mvc.Formatters.Json, Microsoft.Extensions.Configuration.Json, and Newtonsoft.Json when I use the Visual Studio 2015 Qucik Actions on Json. My understanding is that Configuration.Json is for reading form the appsettings.json so it probably is not what I would use to create a JSON object. I can't find any real information on Formatters.Json, how to use it, or what it's intended use it. Newtonsoft.Json is will documented but is it better over the Formatters.Json? Which of the two should I be using?
Taken directly from ASP.NET Core 1 tests
var expected = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(new { foo = "abcd" }));
Also taken from the tests and slightly modified, call it with HttpClient to see how to send your json string to the server.
var response = await Client.PostAsync(
"http://localhost/api/ActionUsingSpecificFormatters",
new StringContent(yourJsonContent, Encoding.UTF8, "application/json"));
As per Newtonsoft you can simply encode, then do whatever you want after that.
Product product = new Product();
product.Name = "Apple";
product.ExpiryDate = new DateTime(2008, 12, 28);
product.Price = 3.99M;
product.Sizes = new string[] { "Small", "Medium", "Large" };
string output = JsonConvert.SerializeObject(product);
//{
// "Name": "Apple",
// "ExpiryDate": "2008-12-28T00:00:00",
// "Price": 3.99,
// "Sizes": [
// "Small",
// "Medium",
// "Large"
// ]
//}
Product deserializedProduct = JsonConvert.DeserializeObject(output);
Putting it all together - I just tested this. Keep in mind this is a real generic pass through test from MVC 6 (ASP.NET 5 ie ASP.NET Core 1) :)
[HttpGet]
public async Task<string> Get()
{
var client = new HttpClient();
var customer = new Customer() { Name = "Schmo", Address = "1999 Purple Rain St" };
var customerJson = JsonConvert.SerializeObject(customer);
var response = await client.PostAsync(
"http://localhost:4815/api/Customer",
new StringContent(customerJson, Encoding.UTF8, "application/json"));
//just some template output to test which I'm getting back.
string resultJson = "{ 'Name':'adam'}";
if (response.StatusCode == HttpStatusCode.OK)
{
resultJson = await response.Content.ReadAsStringAsync();
var updatedCustomer = JsonConvert.DeserializeObject(resultJson);
}
return resultJson;
}
public class Customer
{
public string Name { get; set; }
public string Address { get; set; }
}
I would use Json.Net to create the JSON payloads for sure (Afterall, Microsoft does for Web Api).
Nuget Package Source:
Install-Package Newtonsoft.Json
Here is an example. If you want to call a REST api that returns a product when you make a GET call then you might do something like this.
public static class Main
{
string url = "https://TheDomainYouWantToContact.com/products/1";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/json";
request.Accept = "application/json";
var httpResponse = (HttpWebResponse)request.GetResponse();
var dataStream = httpResponse.GetResponseStream();
var reader = new StreamReader(dataStream);
var responseFromServer = reader.ReadToEnd();
reader.Close();
dataStream.Close();
// This is the code that turns the JSON string into the Product object.
Product productFromServer = JsonConvert.Deserialize<Product>(responseFromServer);
Console.Writeline(productFromServer.Id);
}
// This is the class that represents the JSON that you want to post to the service.
public class Product
{
public string Id { get; set; }
public decimal Cost { get; set; }
public string Name { get; set; }
public string Description { get; set; }
}
The exact same method can be used for POST and PUT as well.
You can use 3rd party assemblies to make this super easy too. We are the authors of DynamicApis.Api
Install-Package DynamicApis.Api
The code to make the same request using this client would be:
public static class Main
{
RestClient client = new RestClient();
string url = "https://YourDomain.com/products/1";
var productFromServer = client.Get<Product>(url);
Console.Writeline(productFromServer.Id);
}
you should use NewtonSoft.Json if you need to serialize objects as json
You shouldn't have to do anything special to send back Json data. The default output formatter is already Json, and if your Startup.cs file is somewhat normal, you should have a line similar to this:
services.AddMvc();
By default, this already contains the Json formatter, and your controller should autonegotiate the return type based on what the browser asked. So a controller like the following should work (taken from this Github issue, which contains some information on why/how this work):
public class ValuesController : ApiController
{
public SomeClass Get()
{
return new SomeClass();
}
public SomeClass Post([FromBody] SomeClass x)
{
return x;
}
}