ASP.NET Web API with Decorations on Models - ajax

Technology Used: Code First,ASP.NET Web API (restful service) and HTML.
For code first I have a domain Object called User
public class User
{
[Required]
public Guid Id { get; set; }
[Required]
public string Email { get; set; }
[Required]
public byte[] PasswordHash { get; set; }
public bool IsDeleted { get; set; }
}
And I have decorated the properties with [Required].
Then I have my MVC Web Api Post Method
public string Post(Domain.User regModel)
{
return "saved";
}
and lastly I have my Ajax Call
var user = {
Id: "1",
Email: "test#test.com",
PasswordHash: "asjdlfkjals;dkjflkjsaldfjsdlkjfiovdfpoifjdsiojfoisj",
IsDeleted: true
};
$.ajax({
type: 'POST',
url: '/api/registration/post',
cache: false,
data: JSON.stringify(user),
crossDomain: true,
contentType: "application/json;charset=utf-8",
success: function (data) {
console.log(data);
}
});
Error As Requested
POST http://localhost.com:11001/api/registration/post 500 (Internal Server Error)
<Error>
<script/>
<Message>
The requested resource does not support http method 'GET'.
</Message>
</Error>
My Problem
If I decorate my Model with [Required] I get an Error 500 - No Get Method Supported
however if I remove that. Everything works well.
I just really want to understand why this is the case with MVC Web API. sure I can create view models but. I just want to understand why this is happening.
Can someone please explain
Thanks

I seem to have found a reason why abit late as I already changed from a web api to a standard MVC. (which works perfectly no work around to be done) you can find the answer in the following links:
asp net web api validation with data annotations
web api nullable required property requires datamember attribute
dataannotation for required property
Thank you all for your help

Could the problem actually be that you are trying to Post a user with Id = "1" while Domain.User specifies that Id is of type Guid. A "1" does not make a valid Guid, so when that property is marked with Required it can't make the call to your Post method. When you remove the required attribute, the Post method can be used/called, because it will just set the Id of the User object to Null or an empty Guid, as it is not required.

Related

Send 2 or more Raw Body Parameters Post Request with Postman

I have an ASP.NET Core 2.0 API Method:
[HttpPost("api/days")]
GetDays([FromBody] DateTime startTime, [FromBody]DateTime endTime)
{
}
And I tried to send a Post request with Postman, but there is a problem, the parameters always have default values.
Here is my Post request looks like:
Result: Not Worked; Both parameters in API method get the default values.
If I change my API params to:
[HttpPost("api/days")]
GetDays([FromBody] Inputparam param)
{
}
public class Inputparam
{
public DateTime startTime { get; set; }
public DateTime endTime { get; set; }
}
That's worked perfectly!
But I wanna to send parameters directly and not inside wrapper object.
So, I came back with first API method and then I tried:
Result: Not Worked; Both parameters in API method get the default values.
And This one:
Result: Not Worked perfectly; Just first parameter (startTime) set it and second parameter still have default value.
And This one:
Result: Not Worked; Both parameters in API method get the default values.
I also tried [FromForm] instead of [FromBody] in API, nothings changed.
If I don't use [FromBody] in api and send the request via x-www-form-urlencoded that's worked perfectly.
But I need send a raw body with JSon.
How could I sent 2 different parameters as a raw body json?
Any idea?
Where is the problem?
I found that it's just one [FromBody] is allowed in API, and that makes sense. So probably the answer is: There is no way to have 2 or more parameters with [FromBody] attribute.
[FromUri] can do the Job.For your reference Microsoft Documentation
public class DateTimes
{
public datetime startdate { get; set; }
public datetime enddate { get; set; }
}
GetDays([FromBody] DateTimes _date)
{
//Controller action
}
URI:
api/values/?startdate=2018-06-01&endate=2018-07-01

How to tell default value from clearing with FromBody in ASP.NET Core Web API

I have coded in C# for years, but I am new to ASP.NET Core. I have created a Web API where I generated my Model classes from an existing database and used the scaffolding to create a Controller for each model that gives me Get, Put, Post, and Delete. My question is how do I know if the caller is clearing a value vs the value is the default for the C# object?
For example, in Vue.js I send
var sendstuff = {userName: "TestUser1", userId: 7, email: null};
In C#, my user object has
public int UserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public string FavoriteColor { get; set; }
In my controller, my put method begins
public async Task<IActionResult> PutUsers([FromRoute] int id, [FromBody] User user)
My User instance in the database is TestUser1, 7, test#test.com, purple. The User that comes into PutUsers is TestUser1, 7, null, null.
At this point, I want to compare the values sent in for user 7 to the values in the database for user 7. However, since both FavoriteColor (that is not sent) and Email (that is sent) look the same as they both appear as null, how do I know whether or not it should be changed? I want test#test.com to be cleared, but I want purple to remain.
It seems my only other option is to have Vue.js send in every single column for every table, with the values either the original value I don't want changed or the new value. This doesn't feel right.
Am I missing something?
Thanks in advance!
The only way I can think of is to accept a Generic Json-Object and checking wether or not the Properties are set.
Most Json Frameworks will be able to cast to a specific Object from the Json Object so you won't even need to change your further code.

When POST has Id in the URI - should Id also be in Body Model Parameters? Web API

I have a ViewModel used in a Web API web service.
public class Customer
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
}
Then I have an ApiController with a method like this:
[Route("api/Customer/{Id}")]
public IHttpActionResult Post(int Id, [FromBody]Customer Customer)
{
...Add to db, Id also exists in Customer
return Ok();
}
Customer Id is available in the URI - but the Customer object contains a Customer Id - which could be passed into the Post.
This seems to be redundant - and may lead to the Id being put in the wrong place.
What is best practice? If I need to remove Id from Customer body how do I do it?
Reference - "Using HTTP Verbs with the Task Resource" - level 2 in the REST Maturity Model - states the Id should be passed in the URI for updating or inserting tasks with an Id:
Generally we call a POST method when we try to create a new record, in your case "Customer" and PUT method to update an existing record. But that is not mandatory. You can create and update an existing record by using POST method too.
In general, we set auto generated field to the Id (primary key) field of a table. That means, we don't need to pass data for Id field when we try to add a record. In that case you don't need to pass Id in your URI and you don't need to write a parameter for Id in your API POST method.
So your ajax method will be like this bellow,
$.ajax({
url: 'myURL',
type: "json",
contentType: 'application/json; charset=utf-8',
data: myFormData,
success: function(data)
{
alert("success");
}
})
As I mentioned above you can use the same method (POST) for add a new record or edit an existing record, so how is that possible ?
I assume you are passing Id value in your ajax code in data parameter.
So your API Post method will be like this,
[Route("api/Customer")] // I removed Id here
public IHttpActionResult Post([FromBody]Customer Customer)
{
if(Customer!=null && Customer.Id==0) //You can check Id with null value
{
// Add a new record to Customer
}
else
{
// fetch Customer data by Customer.Id and update here
}
return Ok();
}
As simple as that. But yes, you can write this update code in a PUT method.
But if you are passing value to the Id field(that is not auto generated field) in POST method, then also you can remove the Id parameter from your POST method and your Route will be like this,
[Route("api/Customer")]
Hope it helps :)

Using IDictionary in controller method ASP.NET MVC 4/JSON

I'm attempting to post data using AJAX back to an ASP.NET MVC Controller with a viewModel like so:
public class FunkyThingUpdateModel
{
public int FunkyThing_ID{get;set;}
public string Name{get;set;}
public IDictionary SizesAvailable{ get; set;}
}
Unfortunately, I'm struggling to get the model binder to bind to the IDicationary.
If in the JSON passed to the controller the sizesAvailable is null then the controller method is called successfully. However if there is data in sizesAvailable then I'm getting an internal server error 500.
My JSON is formatted as follows:
{"FunkyThing_ID":1,"Name":"Pogo Stick","SizesAvailable":{"1":"Extra
Large","2":"Extra Tiddly"}}
What I'm not sure is - am I trying to do something impossible. Is there a way of binding to an IDictionary - if not what is the best alternative?
Or does my JSON just need to be formatted in a different fashion?
I found a number of similar questions on here, but most of them are quite old.
There seemed to be some indications that this was possible in MVC 4 which I'm using - but I could have been misunderstanding the context.
Not tested, But i think you have to specify Generic interface definition for the object to be created.
public IDictionary<int, string> SizesAvailable{ get; set;}
and also you have to change the data in ajax definition to notify SizesAvailable as array
$.ajax({
url:'your url',
type: 'post',
contentType : 'application/json',
data: JSON.stringify({FunkyThing_ID:1, Name:"Pogo Stick", SizesAvailable:[{key: 1, value:"Extra Large"},{key:2, value: "Extra Tiddly"}]}),
success: function(response){
console.log(response);
}
});
Edit
If your intention is to only get string array(not a dictionary) of sizes, change
public string[] SizesAvailable{ get; set;}
and send data as,
data: JSON.stringify({FunkyThing_ID:1, Name:"Pogo Stick", SizesAvailable:["Extra Large","Extra Tiddly"]}),
hope this helps.

ASP.NET MVC AllowHtml bug or something I didn't use correctly

My model contains a string field called "longdescription" which gets the value of the tinymce editor's content
Public class ArticleModel:BaseModel{
[StringLength(8000, ErrorMessage = "Long description must be in 8000 characters or less"), AllowHtml]
public string LongDescription { get; set; }
}
Here is my controller code
[HttpPost]
public ActionResult AddEdit(ArticleModel model)
{
string buttonName = Request.Form["Button"];
if (buttonName == "Cancel")
return RedirectToAction("Index");
// something failed
if (!ModelState.IsValid)
{
}
// Update the articles
}
My problem is when I use Request.Form to access the post value, it's working fine without throwing "A potentially dangerous...." error, but when I use Request.Params["Button"], it threw that errors. Is something I am missing?
Thanks
Updated
Sorry the answer Adam gave doesn't really answer my question. Can anyone give more suggestion?
Ideally you shouldn't really be using either. Those are more Web Forms centric values even though they 'can' be used.
Either pass in a FormsCollection item and check it there using collection["Button"] or even better - your cancel button itself should probably just do the redirect. Why post when you do nothing but redirect?
In your view you can emit the url via Url.Action() and put that into your button's click handler (client side)
It is the HttpRequest.Params getter that is throwing this exception. This getter basically builds and returns a key/value pair collection which is the aggregation of the QueryString, Form, Cookies and ServerVariables collections in that order. Now what is important is that when you use this getter it will always perform request validation and this no matter whether you used the [AllowHtml] attribute on some model property or if you decorated the controller action with the [ValidateInput(false)] attribute and disabled all input validation.
So this is not really a bug in the AllowHtml attribute. It is how the Params property is designed.
As #Adam mentioned in his answer you should avoid accessing request values manually. You should use value providers which take into account things such as disabled request validation for some fields.
So simply add another property to your view model:
public class ArticleModel: BaseModel
{
[StringLength(8000, ErrorMessage = "Long description must be in 8000 characters or less")]
[AllowHtml]
public string LongDescription { get; set; }
public string Button { get; set; }
}
and then in your controller action:
[HttpPost]
public ActionResult AddEdit(ArticleModel model)
{
string buttonName = model.Button;
if (buttonName == "Cancel")
{
return RedirectToAction("Index");
}
// something failed
if (!ModelState.IsValid)
{
}
// Update the articles
}

Resources