Hello I would like to call Web Api method from C# client by my body variable in web api controller is null all the time.
How to set it correct ?
client side:
IFileService imgService = new ImageServiceBll();
var image = System.Drawing.Image.FromFile(serverFile);
var dataImage = imgService.ImageToBase64(image, System.Drawing.Imaging.ImageFormat.Png);
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://site.local/");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
// HTTP POST
var data = new
{
imageData = dataImage,
version = version
};
HttpResponseMessage response = await client.PostAsJsonAsync("api/contenttool/SaveImage", data);
if (response.IsSuccessStatusCode)
{
Uri gizmoUrl = response.Headers.Location;
}
}
Server Side:
public class ContentToolController : ApiController
{
public IFileService FileService { get; set; }
// POST api/contenttool
public string SaveImage([FromBody]string data)
{
JObject jObject = JObject.Parse(data);
JObject version = (JObject)jObject["version"];
return "-OK-" + version;
}
}
I think it has more to do with the fact that you technically aren't passing in a string. You are passing in a JSON serialized string representation of an anonymous type, so the deserialization process in the Web Api is working against you. By the time your request gets to the controller and that method, it isn't a string anymore. Try changing your type on the SavImage method to be dynamic. Like this:
public string SavImage([FromBody]dynamic data)
{
JObject jObject = JObject.Parse(data);
JObject version = (JObject)jObject["version"];
return "-OK-" + version;
}
Unfortunately at that point you won't be able to use intellisense to get your properties out. You will have to get the data out of the dynamic type via a dictionary.
Dictionary<string, object> obj = JsonConvert.DeserializeObject<Dictionary<string, object>>(Convert.ToString(data));
Of course your other option would be to use an actual type that is shared between the client and the server. That would make this a bit easier.
The string value passed in the body probably needs to be prefixed with the = sign.
Related
I am trying to create a basic test web api, and use a standard controller to test call it.
When I run it, by putting
http://localhost:55144/home/testapi
it'll run the catcher function and completely ignore the parameter.
Then, the catcher will happily return a value, which can be seen in the calling code.
I have tried various combinations of putting [FromBody], changing the type of the parameter in TestApiMethod, and seeing if making a list or array makes any difference.
I've noticed a couple of weird things:
- I'm not using the parameter in the code of TestApiMethod, but Visual Studio is not giving me an unused variable warning.
- If I make the type of the parameter testString a string or even an int, the code below will route to the catcher. If I make it some variation of a model or a Jobject, it will not. It gets as far as running
HttpResponseMessage response = await client.PostAsJsonAsync("api/activity", sendData);
then just returns to the web page.
Here's the code:
Models
public class testStringModel
{
public string testString { get; set; }
}
public class apiResponse
{
public string response { get; set; }
}
Home controller calling Api:
public void TestApi()
{
Task myTask = testApiCall();
}
private async Task<string> testApiCall()
{
HttpClient client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:55144");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
testStringModel data = new testStringModel { testString = "cheese" };
string jsonData = JsonConvert.SerializeObject(data);
var sendData = new StringContent(jsonData, Encoding.UTF8, "application/json");
//var sendData = new Dictionary<string, string>
//{
// {"testString", "cheese"}
//};
HttpResponseMessage response = await client.PostAsJsonAsync("api/activity", sendData);
string responseBodyAsText = await response.Content.ReadAsStringAsync();
dynamic stuff = JObject.Parse(responseBodyAsText);
string finalResponse = stuff.response;
return finalResponse;
}
}
The api:
namespace ApplicationActivity
{
public class ActivityController : ApiController
{
[System.Web.Http.HttpPost]
public HttpResponseMessage Catcher()
{
apiResponse apiResponseObject = new apiResponse();
apiResponseObject.response = "You have somehow wound up in the catcher";
string json = JsonConvert.SerializeObject(apiResponseObject);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new StringContent(json, Encoding.Unicode, "application/json");
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
return response;
}
[System.Web.Http.HttpPost]
public HttpResponseMessage TestApiMethod(string testString)
{
apiResponse apiResponseObject = new apiResponse();
apiResponseObject.response = "OK from test";
string json = JsonConvert.SerializeObject(apiResponseObject);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK, "value");
response.Content = new StringContent(json, Encoding.Unicode, "application/json");
response.Headers.CacheControl = new CacheControlHeaderValue()
{
MaxAge = TimeSpan.FromMinutes(20)
};
return response;
}
}
}
Please will you tell me what I'm doing wrong with my code, how to fix it and what is happening when the code doesn't get to the catcher?
Thanks.
It turns out that I was using an older version of visual studio and as a result the whole thing got really confused with whether is was running .net core or not.
Upgrading to the latest and making sure the latest .net core is installed solved most of my troubles
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 working on creating an API that call the other third party API. The third party API is an REST API and returns response in the JSON format when I call it in the web browser
[{"Acc":"IT","Cnt":"023","Year":"16"}]
I am trying to get the same response when I call the third party API from my API.
public IHttpActionResult Get(string acctID)
{
using (var client_EndPoint= new HttpClient())
{
Uri uri_EndPoint = new Uri(BaseURL_EndPoint);
client_EndPoint.BaseAddress = uri;
client_EndPoint.DefaultRequestHeaders.Accept.Clear();
client_EndPoint.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
string EndPoint_URL = BaseURL_EndPoint+"api/NameCreation?Account="+acctID;
var response_EndPoint = client_EndPoint.GetAsync(EndPoint_URL).Result;
string responseString = response_EndPoint.Content.ReadAsStringAsync().Result;
return Ok(responseString);
}
}
What I have been doing is getting the response from the third party API in a string. But I am checking if there is a way I can get in the JSON format so I can return them directly. The return type of the get method is IHttpActionResult. If I am returning as string the response looks like
"[{\"Acc\":\"adm\",\"Cnt\":\"001\",\"Year\":\"16\"}]"
Any help is greatly appreciated.
Create a model to hold rest api data
public class Model {
public string Acc { get; set; }
public string Cnt { get; set; }
public string Year { get; set; }
}
Deserialize it from api
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
And then return that
return Ok(models);
Full example
public async Task<IHttpActionResult> Get(string LabName) {
using (var client_EndPoint = new HttpClient()) {
//...other code removed for brevity
var response_EndPoint = await client_EndPoint.GetAsync(EndPoint_URL);
var models = await response_EndPoint.Content.ReadAsAsync<Model[]>();
return Ok(models);
}
}
you can use Newtonsoft.Json ,Just add it from nuget and add this config to webapiconfig:
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
then use
return Json(responseString)
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 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.