How to use axios.put to send JSON to ASP.NET controller - asp.net

I'm trying to send a PUT request with JSON data using the following client code:
const url = new URL(`${process.env.REACT_APP_API}/datas/edit/${id}`);
axios.put(url, data);
And on the server side, when I'm trying to look at in the HttpRequest.Form, the Controller throws InvalidOperationException exception . The message is Incorrect Content-Type: application/json;charset=UTF-8.
[HttpPut("edit/{id}")]
public void Edit([FromRoute] int id, [FromBody] Data data)
...
I also tried axios.put(url, JSON.stringify(data)); but server returns 415.
EDIT: I tried with Postman instead of my front-end:
public class A { public int /*or string*/ A1 { get; set; } }
[HttpPut("edit/{id}")]
public void EditQuestion([FromRoute] int id, [FromBody] A a) ...
IMPORTANT:
I shouldn't have looked at HttpRequest.Form because I'm sending JSON data and it should be parsed into my model.

I see the json response from postman returns a string, instead your "A" class has an int property for A1.
Try changing the class to:
public class A { public string A1 { get; set; } }

Related

Cannot parse Json from HTTP request to Model class C#

I have a HTTP Post request like below:
[HttpPost]
[Route("edit-request")]
public async Task<IActionResult> EditRequet(Json request)
{
var response = await _claimProcessorService.ProcessClaim(request);
return Accepted(response);
}
The model class Json has:
public class Json
{
public string Prop1 { get; set; }
public string Prop2 { get; set; }
}
The Request data can be both cases as shown below.
Case I:
{
"Prop1": 1234,
"Prop2": "test"
}
Case II
{
"Prop1": "1234",
"Prop2": "test"
}
The Case I does not trigger the API whereas, the Case II is running smoothly. But I need both of the request to run
Since Json's Prop1 is a string and in Case I you pass an integer this will not work.
You should probably make Prop1 an integer and have the client always send this value as an integer instead of a string.
Alternatively you could create a second endpoint that accepts Prop1 as a string.
Finally, you could create a custom JsonConverter that converts strings to numbers - if convertible.
However both the second and the third solution are really bad, I would go with the first and avoid these.

ASP.Net OData with string keys

I am trying to use ASP.Net OData v4 (e.g. ODataController) to allow access where the key is a string. 95% of the examples out there use an integer as a key and the couple of posts I've found that discuss the steps to use a string as the key aren't working for me.
In all cases, I am trying to access my resource with the following URL:
/api/ContactTypes('Agency')
Optimistically, I started with just changing the type of the key from int to key:
public SingleResult<ContactType> Get([FromODataUri] string key)
But I get a 404 response. Changing the URL to an integer, /api/ContactTypes(1) does "work" in that it routes to the correct method and that the key is a string type, but obviously, that doesn't help me. This is the scenario described in this post: How to get ASP.Net Web API and OData to bind a string value as a key? except that that post implies that accessing the URL the way I am should work (and also is for OData v3).
After further searching, I found this article: https://blogs.msdn.microsoft.com/davidhardin/2014/12/17/web-api-odata-v4-lessons-learned/ which basically says that you have to decorate the Get method with an explicit routing:
[ODataRoute("({key})")]
public SingleResult<ContactType> Get([FromODataUri] string key)
If I do that alone, though, I get "The path template '({key})' on the action 'Get' in controller 'ContactTypes' is not a valid OData path template. Empty segment encountered in request URL. Please make sure that a valid request URL is specified."
The comments in this post (https://damienbod.com/2014/06/16/web-api-and-odata-v4-crud-and-actions-part-3/) suggest that I need to decorate the Controller with an ODataRoutePrefix:
[ODataRoutePrefix("ContactTypes")]
public class ContactTypesController : ODataController
That seems counter-intuitive since I do not have anything ASP.Net should be confusing. My controller name is already following convention and I have no Web API controllers that could be confusing it.
Regardless, it does seem to "fix" the issue in that the error goes away, but then I am right back at square one (e.g. only integer values can be passed in the URL).
What am I missing?
Full controller code:
[Authorize]
[ODataRoutePrefix("ContactTypes")]
public class ContactTypesController : ODataController
{
PolicyContext _Db;
public ContactTypesController(PolicyContext db)
{
if (db == null)
throw new ArgumentNullException("db");
this._Db = db;
}
public ContactTypesController() : this(new PolicyContext())
{
}
protected override void Dispose(bool disposing)
{
_Db.Dispose();
base.Dispose(disposing);
}
[EnableQuery]
[ODataRoute()]
public IQueryable<ContactType> Get(ODataQueryOptions options)
{
return _Db.ContactType;
}
[EnableQuery]
[ODataRoute("({key})")]
public SingleResult<ContactType> Get([FromODataUri] string key)
{
IQueryable<ContactType> result = _Db.ContactType.Where(p => p.ContactTypeKey == key);
return SingleResult.Create(result);
}
Full WebApiConfig:
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
builder.EntitySet<ContactType>("ContactTypes");
config.MapODataServiceRoute(
routeName: "ODataRoute",
routePrefix: "api",
model: builder.GetEdmModel()
);
}
1.If in your EdmModel, the string property is key, then no ODataRoute is need, for example:
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
ConventionModelBuilder will use property named "Id" as the key, or you should specify it's a key like:
public class Product
{
[Key]
public string StringKey { get; set; }
public string Name { get; set; }
public double Price { get; set; }
}
Then the call like localhost\api\Products('test') should just go to
public SingleResult<Product> GetProduct([FromODataUri]string key)
2.If you already have a int as a key, but you want use string as another key, then you should try this feature: http://odata.github.io/WebApi/#04-17-Alternate-Key , and you can call like:
localhost\api\Products(StringKey='test')

Post json data in body to web api

I get always null value from body why ?
I have no problem with using fiddler but postman is fail.
I have a web api like that:
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] string value)
{
string result = value;
}
My postman data:
and header:
WebAPI is working as expected because you're telling it that you're sending this json object:
{ "username":"admin", "password":"admin" }
Then you're asking it to deserialize it as a string which is impossible since it's not a valid JSON string.
Solution 1:
If you want to receive the actual JSON as in the value of value will be:
value = "{ \"username\":\"admin\", \"password\":\"admin\" }"
then the string you need to set the body of the request in postman to is:
"{ \"username\":\"admin\", \"password\":\"admin\" }"
Solution 2 (I'm assuming this is what you want):
Create a C# object that matches the JSON so that WebAPI can deserialize it properly.
First create a class that matches your JSON:
public class Credentials
{
[JsonProperty("username")]
public string Username { get; set; }
[JsonProperty("password")]
public string Password { get; set; }
}
Then in your method use this:
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] Credentials credentials)
{
string username = credentials.Username;
string password = credentials.Password;
}
You are posting an object and trying to bind it to a string.
Instead, create a type to represent that data:
public class Credentials
{
public string Username { get; set; }
public string Password { get; set; }
}
[Route("api/account/GetToken/")]
[System.Web.Http.HttpPost]
public HttpResponseBody GetToken([FromBody] Credentials value)
{
string result = value.Username;
}

Reading the parameters sent in the body from applet to the post method of web api controller

Consider the following class
public class StController:apicontroller {
public void PostBodyMethod() {
HttpRequestMessage request=this.request;
//How to read the header and body parameters
}
}
The applet sends both the header and body parameters to the post method.
How to retrieve the information which is sent along with post method inside the webapi controller using the HttpRequestMessage object?
If the body parameter is a JSON object, all what you need is to just pass Model parameter in Post method. Web API supports json by default. You might need to read this.
To reader headers in HttpRequest, you can use:
var headers = ControllerContext.Request.Headers;
Sample code:
class Model
{
public int Id { get; set; }
public int Hj { get; set; }
}
public class StController : ApiController {
public void Post(Model model) {
//How to read the header and body parameters
var headers = ControllerContext.Request.Headers;
}
}

Pass a JSON array to a WCF web service

I am trying to pass a JSON array to a WCF service. But it doesn't seem to work. I actually pulled an array [GetStudents] out the service and sent the exact same array back to the service [SaveStudents] and nothing (empty array) was received.
The JSON array is of the format:
[
{"Name":"John","Age":12},
{"Name":"Jane","Age":11},
{"Name":"Bill","Age":12}
]
And the contracts are of the following format:
//Contracts
[DataContract]
public class Student{
[DataMember]public string Name { get; set; }
[DataMember]public int Age{ get; set; }
}
[CollectionDataContract(Namespace = "")]
public class Students : List<Student>
{
[DataMember]public Endorsements() { }
[DataMember]public Endorsements(IEnumerable<Student> source) : base(source) { }
}
//Operations
public Students GetStudents()
{
var result = new Students();
result.Add(new Student(){Name="John",12});
result.Add(new Student(){Name="Jane",11});
result.Add(new Student(){Name="Bill",12});
return result;
}
//Operations
public void SaveStudents(Students list)
{
Console.WriteLine(list.Count); //It always returns zero
}
It there a particular way to send an array to a WCF REST service?
I had similar issue.
I was calling the service from a browser and the problem was Firefox dynamically changing the request content-type from 'application/json' to 'application-json;charset=utf-8'.
If you are calling the service from a browser, test it with non-firefox browser and if that was the case you need to remove the charset from the request content-type header

Resources