In my WebApi I have a HttpGet and HttpPost method, the get method is working fine and the post method is called but the body content is always null, unless used in a HttpRequestMessage. I tried providing the body content in a string format(preferred datatype) aswell as in a model but neither one of those methods worked. I also tried switching the content type without success. Does anyone know if I'm doing something wrong or how I can easily get the variable data from the HttpRequestMessage, which in the example below is "test".
Method 1:
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]string filecontent, string companycode)
{
MessageBox.Show(filecontent);
Return Ok("");
}
Method 2 (with model):
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]ItemXML filecontent, string companycode)
{
MessageBox.Show(filecontent.XMLContent);
Return Ok("");
}
Model:
public class ItemXML
{
public ItemXML(string content)
{
XMLContent = content;
}
public string XMLContent { get; set; }
}
Method 3:
[System.Web.Http.HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem(HttpRequestMessage filecontent, string companycode)
{
var content = filecontent.Content.ReadAsStringAsync().Result;
MessageBox.Show(content);
Return Ok("");
}
Method 3 content string ("test" is the provided value): " content "------WebKitFormBoundarydu7BJizb50runvq0\r\nContent-Disposition: form-data; name=\"filecontent\"\r\n\r\n\"test\"\r\n------WebKitFormBoundarydu7BJizb50runvq0--\r\n" string"
Create a model store data to be sent to server
public class Model {
public string filecontent { get; set;}
public string companycode { get; set;}
}
Update Action
[HttpPost]
[Route("api/v1/AddItem")]
public IHttpActionResult AddItem([FromBody]Model model) {
if(ModelStat.IsValid) {
return Ok(model); //...just for testing
}
return BadRequest();
}
On the client make sure the request is being sent properly. In this case going to use JSON.
public client = new HttpClient();
var model = new {
filecontent = "Hello World",
companycode = "test"
};
var response = await client.PostAsJsonAsync(url, model);
If using another type of client ensure that the data being sent is formatted correctly for the Web API action to accept the request.
Reference Parameter Binding in ASP.NET Web API
Related
I'm trying to pass a big string in my controller using json. Also i need Controller to send me an answer.
Here is my controller in web api:
public class CustomersController : ApiController
{
// GET: api/Customers
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// GET: api/Customers/5
public string Get(int id)
{
return "value";
}
// POST: api/Customers
public void Post([FromBody]string value)
{
}
// PUT: api/Customers/5
public void Put(int id, [FromBody]string value)
{
}
// DELETE: api/Customers/5
public void Delete(int id)
{
}
}
First of all where i should read my string and where should i send an answer?
And here is my client which try to send a string
using (var client = new HttpClient())
{
var response = await client.PostAsync("http://192.168.1.15:8282/",new StringContent("Mystring", Encoding.UTF8, "application/json"));
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
}
I need my web api to read my string, and then to send me an answer
Instead of having the methods as void you need to return the string value from the controller methods.
Also, don't forget to decorate the methods with respective http verb attribubte (HttpGet, HttpPost, HttpPut etc.) which the method is responsible to serve.
Here's an example where the method returns an Ok result, this generate an http status code 200 with the string in the response body
[HttpPost]
public IHttpActionResult Post([FromBody]string value)
{
return Ok(value);
}
Then for the client call.
First of, you need to specify the route to the controller correctly
192.168.1.15:8282/api/Customers
Then, sending a single string as content when using the content-type of application/json is not suitable as json always start parsing from an object {} or array [].
The easiest way of sending a single string is therefore to just change the content type to application/x-www-form-urlencoded and adding a = sign infront of the string
using (var client = new HttpClient())
{
var response = await client.PostAsync("http://192.168.1.15:8282/api/Customers",new StringContent("=Mystring", Encoding.UTF8, "application/x-www-form-urlencoded"));
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync();
}
}
I'm trying to post anonymous object via httpclient, however orderId is null and collection empty when it hits controller.
public async Task<Response> CancelOrderAsync(int orderId, ICollection<int> ids)
{
Response result = null;
using (IHttpClient client = HttpClientFactory.CreateHttpClient())
{
var obj = new {OrderId = orderId, Ids = ids};
string json = JsonConvert.SerializeObject(obj);
HttpContent postContent = new StringContent(json, Encoding.UTF8, "application/json");
using (var response = await client.PostAsync($"{url}/admin/cancel", postContent).ConfigureAwait(false))
{
if (response != null && response.IsSuccessStatusCode)
{
...
}
}
}
return result;
}
// Controller
[HttpPost]
[ActionName("cancel")]
public async Task<Response> Cancel(int orderId, ICollection<int> ids)
{
// order is null, collection empty
...
EDIT:
Changed my controller to this for simplicity
[HttpPost]
[ActionName("cancel")]
public async Task<SimpleResponse> Cancel(int orderId)
Via Postman, i'm posting this body:
{
"orderId": "12345"
}
Still, orderId comes in as 0 (zero) ??
The controller action on the server side will need a concrete type to read the entire body of the request
public class Order {
public int OrderId { get; set; }
public int[] Ids { get; set; }
}
This is primarily because the action can only read from the body once.
Update action to...
[HttpPost]
[ActionName("cancel")]
public async Task<Response> Cancel([FromBody]Order order) {
if(ModelState.IsValid) {
int orderId = order.OrderId;
int[] ids = order.Ids;
//...
}
//...
}
the original code used to send the request in the example will work as is, but as mentioned it can be improved.
The HttpClient can do the serialisation for you. See if
var response = await client.PostAsJsonAsync($"{url}/admin/cancel", obj);
works better. Then you don't need to write the serialisation code yourself.
If you still have a problem, use a tool such as Fiddler to monitor the actual request and see what parameter and values are submitted in the request body, to see if they match what's expected by the endpoint.
First, I am not sure if my question reflects my needs, please let me know if that needs to be changed.
What I am doing here is creating functions in DLL application to be called from DotNET outside c#. The issue with my function now is the Model class. Where I am going to use this DLL, I cannot see/use my model class from the outside, therefore how do I change my code to use a string instead of Product model? I still need to send my request as JSON though.
I am working with JSON
I have the following 2 classes:
In Class 1 (SetupWebAPIAsync): Function that puts a product (Model)
public static async Task<ApiResponse> PutProductAsync(string endpoint, Product p)
{
StringContent httpContent = new StringContent(JsonConvert.SerializeObject(p), Encoding.UTF8, "application/json");
string result = "";
HttpResponseMessage response = await client.PutAsync(endpoint, httpContent);
response.EnsureSuccessStatusCode();
result = await response.Content.ReadAsStringAsync();
return new ApiResponse(response.StatusCode, result);
}
In Class 2:
public static ApiResponse PutIn(string user, string password, string endpoint , Product Httpcontent)
{
User = user;
Password = password;
Endpoint = endpoint;
Content = Httpcontent;
ExecutePUTRequest().Wait();
return apiResponse;
}
private static async Task ExecutePUTRequest()
{
SetupWebAPIAsync.SetAPIAuthentication(User, Password);
apiResponse = await SetupWebAPIAsync.PutProductAsync(Endpoint,Content);
}
My Model Class:
public class Product
{
public string id { get; set; }
public string name { get; set; }
public bool inactive { get; set; }
}
ex:
{
"id" : "12",
"name" : "test",
"inactive": false,
}
Now this is how I call my function and it works this way BUT I need to replace product by a string I pass in from my test outside Dll.
Product product = new Product { name = "API_Testing" };
PutIn("user", "pass", "https://localhost/api/product", product);
Well you can't cause your PutIn() method expects an Product Httpcontent as method parameter. instead take a stringified product as JSON and convert that to product and call the main method like
public static ApiResponse PutIn(string user, string password,
string endpoint , string Httpcontent)
{
User = user;
Password = password;
Endpoint = endpoint;
Content = NewtonSoft.Json.JsonConvert.DeserializeObject<Product>(Httpcontent);
ExecutePUTRequest().Wait();
return apiResponse;
}
You can then call it like
string product = "{id : 12,name : API_Testing,inactive: false,}"
PutIn("user", "pass", "https://localhost/api/product", product);
I'm posting a file and a json object to my API using angularjs. I'm able to get all the data from the server (file and model object):
public async Task<IHttpActionResult> send()
{
var path = HttpContext.Current.Server.MapPath("~/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
var modelFromClient = result.FormData["model"];
}
The modelFromClient i receive has this format : "model":"{\"name\":\"James\",\"comments\":\"test\"}
But i want to cast the modelFromClient json to my user model which is :
public User {
public string name{ get; set; }
public string comments{ get; set; }
}
So at the end, i want to be able to get my attributes like i used to do when i send the object explicitly trought the url :
public async Task<IHttpActionResult> add(User user) {
// here, my user object will have all the values that i set in my client side and i get them like this :
user.name;
user.comments;
...// other attributes
// Save the object in dataBase
user.Save();
}
I hope you understand my need
If you are in control of the client json, then perhaps you could omit the model field and just send the content like so:
{
"name": "james",
"comments": "test"
}
This would allow you to use your existing controller implementation "as-is".
If however, the client json is out of your control, then you need to deserialize it into a model that is representative of the json. Changing your model to the following would likely work:
public Model
{
public User model { get; set; }
}
Because you are reading out the raw json from the request, you can deserialize it manually before calling add() directly
And then your controller would change to this (Assumes Json.Net is referenced):
public async Task<IHttpActionResult> send()
{
var path = HttpContext.Current.Server.MapPath("~/uploads");
var provider = new MultipartFormDataStreamProvider(root);
var result = await Request.Content.ReadAsMultipartAsync(provider);
var modelFromClient = result.FormData["model"];
var clientModel = JsonConvert.Deserialize<Model>(modelFromClient);
return await add(clientModel.user);
}
public async Task<IHttpActionResult> add(User user)
{
//Do whatever you need with user
//Save the object in database
user.Save();
}
I am consuming a web api wrote in c#, MVC, that looks like:
public IEnumerable<Day> Post([FromBody] string postObject)
Using fiddler or poster I can post to that REST service since my body has a = before my sending JSON, something like
={"BillTypeId":"4","RestId":"1"}
Using retrofit to make this call I can not send that initial = and my request looks like
{"BillTypeId":"4","RestId":"1"}
That makes the rest service receive always a null parameter.
Do you know a way to send it before my json? Since I am calling that rest like this
void postToGetDayList(#Body ResquestListenerBillType request, Callback<List<Day>> callback);
Thank you!!!
If you haven't fixed your issue, I think you can refer to my following code:
WebAPI:
public class ValuesController : ApiController
{
// GET api/values
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
// POST api/values
public string Post([FromBody]string value)
{
return value;
}
}
Retrofit WebAPIService:
public interface WebAPIService {
#GET("/api/values")
List<String> listValues();
#POST("/api/values")
String postValues(#Body String value);
}
Call webAPIService.postValues("BNK");
You will find the result as the following image. Hope this helps!
before send class convert to string and add one " fist string and add one " on last string then send body
my client API is :
[Put("/WebPage/{key}/")]
Task<string> PutWebPage([AliasAs("key")]string id, [Body]string value);
sample code is :
WebPageModel webPageModelSave = new WebPageModel();
webPageModelSave = ObjectCopier.CloneClass(Public.CashEntity.webPageModel);
webPageModelSave.Address = uxLabel_AddressTitle.Text;
string codeingData = JsonConvert.SerializeObject(webPageModelSave);
codeingData = ArmanSerialize.CryptoString.Encrypt(codeingData, "5552552");
string resutlt = await Public.Helper.ApiServer.PutWebPage("123", "\""+codeingData+"\"");
and on server remove the " fist and last string like this:
// PUT api/<controller>/5
[HttpPut("{id}/")]
public string Put(string id, [FromBody]string value)
{
string removeCotation = value.Remove(value.Length - 1, 1).Remove(0, 1);
string valueItem = ArmanSerialize.CryptoString.Decrypt(value, "5552552");
string baseUrl = Request.Host.Host;
baseUrl = baseUrl.ToLower().Replace("http://", "").Replace("https://", "");
var serverID = 123;
if (id.Replace("\"", "") == serverID.Replace("\"","") && !string.IsNullOrEmpty(valueItem))
{
WebPageModel webPageModel = new WebPageModel();
webPageModel = JsonConvert.DeserializeObject<WebPageModel>(valueItem);
EntityFrameworkCore.LogicLayer logicLayer = new EntityFrameworkCore.LogicLayer();
logicLayer.UpdateWebPageModel(webPageModel);
return JsonConvert.SerializeObject("OK");
}
else
{
//error
return JsonConvert.SerializeObject("Error");
}
}
I test it on xamarin form and asp.net core 3 its work it.