In asp.net-mvc, what is causing my model state errors? - c#

I am posting a form in an asp.net-mvc page. Here is my controller action:
public ActionResult UpdateData(MyFormObject entity)
{
bool isValid = IsValid(entity);
if (!isValid)
{
var firstError = ModelState.Values.SelectMany(v => v.Errors).First();
throw new HttpException(404, firstError.ErrorMessage);
}
return Json(BuildResult(entity));
}
Even thought the post passes all of my explicit validation logic, when i check ModelState I see errors. I am seeing errors in ModelState when any of my properties are empty. Here is my object:
public class MyFormObject
{
public int Id{ get; set; }
public int TestId{ get; set; }
public int OtherId{ get; set; }
}
and I am looking at Model.State and i see errors for any element in my object that is not populated.
If I change this to (NOTE: the "?")
public class MyFormObject
{
public int? Id{ get; set; }
public int? TestId{ get; set; }
public int? OtherId{ get; set; }
}
then i no longer get any errors. Is there some default validation that is happening here that I am not setting. I am trying to figure out what is setting ModelState errors in the first case above.

When you are positing to a controller action that takes MyFormObject class object as a parameter, MVC engine will try to create an instance of that class via automatic model-binding. In order to create MyFormObject one needs to provide all of these:
public int Id{ get; set; }
public int TestId{ get; set; }
public int OtherId{ get; set; }
and if you don't provide at least any of these, it will try to assign null to the corresponding property. The int (value type) doesn't support null values, whereas int? does.
This is logically correct and actually helps you in a long run.

As #Maxim V. Pavlov said, when you post, ASP.MVC engine will try to validate the model, ie its class, and based on class you cited as example, the properties don't accepts a null or empty value, then it will throw an exception and ModelState will be invalid.
You can see more here # Validating Model Data in an MVC Application and here ModelStateDictionary.IsValid Property

You are probably submitting an empty MyFormObject to your UpdateData method. Value-types cannot be null and must be assigned a value. If a value is missing for a value-type, then it automatically will trigger a required field validation.
ASP.NET MVC even has a property that allows you to tweak this behaviour, although I believe it will only influence client-side validation:
DataAnnotationsModelValidatorProvider.AddImplicitRequiredAttributeForValueTypes

Related

ASP.NET Core MVC ViewBag always get zero or NULL from other class

I got this problem when I receive values from a class that use ExecuteAsync.
For example check tempPrice, this nullable var continue to change every second fraction and it's never zero. Other va are props and can be true, false or null... I always get null.
The following is the action method of a specified controller:
public IActionResult Index()
{
ViewBag.tempPrice = _Strategy.TempPrice.ToString().Replace(".", ",");
ViewBag.TradingPair = _Strategy.Symbol;
ViewBag.StopOrderPrice = _Order.StopPriceSpotOrder.ToString().Replace(".", ",");
ViewBag.CurrentTradePrice = _Trade.LastPublicTrade.ToString().Replace(".", ",");
return View();
}
These are parts of codes where i get values , just for example...
public class OrdersFunctions
{
public string ClientOrderId { get; set; }
public string Id { get; set; }
public string Symbol { get; set; }
public string Side { get; set; }
public string Status { get; set; }
}
Only where I manually set the value during app testing (for example)
public string Symbol { get; set; } = "ETHBTC";
I can get the correct value.
As you can see in the screenshot, every value is set to zero, or null, but in the class that contain vars, are all valued.
I supposed it was a problem of services Singleton, Transient, etc... but in any case I set them, I always have this problem (with or without interfaces).
Can someone help me?
EDIT :
As results from the following pic, you can see that all my values, during task operation, are OK. ONLY when i pass the values by contructor in this controller, all values go zero to or null.
The pic show that _trade var has Side value filled in main logic class, but it pass a null value to Controller class
I have used this contructor, but nothing... always zero...
public StrategyController(IOptions<StrategyManager> sm, IOptions<TradeFunctions> trade, IOptions<OrdersFunctions> order )
{
_Strategy = sm.Value;
_Order = order.Value;
_Trade = trade.Value;
}

Dynamic type model binding in ASP.NET Core

I'm currently working on a content editor that can be used for multiple types of content, where a developer could specify their own model. For example, a model might look like this:
public class ImageWithCopyWidgetModel : WidgetModel, IWidgetModel
{
public string ImageUrl { get; set; }
public string ImageAltText { get; set; }
public string HeaderText { get; set; }
public string BodyContent { get; set; }
}
On the editor side, I have a view model that looks like:
public class EditContentViewModel<TModel> where TModel : IWidgetModel
{
public int Id { get; set; }
public string Name { get; set; }
public TModel WidgetModel { get; set; }
}
I have the binding on the GET/form display side working fine. My issue comes with getting the model binder to accept the data on the POST? I've tried the following, but each returns null for model.WidgetModel:
// Option 1
EditContent(int pageId, int id, EditContentViewModel<dynamic> model)
// Option 2
EditContent(int pageId, int id, EditContentViewModel<object> model)
// Option 3
EditContent(int pageId, int id, EditContentViewModel<IWidgetModel> model)
Note, for testing purposes, I tried explicitly setting the type of WidgetModel to a concrete class (the ImageWithCopyWidgetModel noted above) and that works.
I'm really trying to avoid having to use Request.Form here as its going to limit future plans for this implementation.
What you're wanting is not possible, at least out of the box. On post, all the modelbinder has is a bunch of key-value pair string. What informs its decision about how to bind those values to something useful is the action param(s). Specifically, it has no way of knowing that it should actually create an instance of ImageWithCopyWidgetModel when you're binding to EditContentViewModel.
Also, the modelbinder is designed to discard values it doesn't know what to do with. That means that it's unfortunately not even possible to cast to ImageWithCopyWidgetModel after the fact, because all properties not present on EditCopyViewModel would have been discarded by that point.
Your best bet is a custom model binder, but the implementation of that is too broad for the scope of Stack Overflow. I suggest you refer to the documentation.

Making class property optional WebAPI MVC5

I am using MVC5 WebAPI and i have a class as follows:
public string Name { get; set; }
public string Sub { get; set; }
public List<Actions> Actions { get; set; }
(Actions is another custom class)
When client makes an API call they have to send the Actions property as null. Is there a way that the client may not send the actions property at all?
How could this be done?
Thanks in advance.
I think this public List Actions { get; set; } is optional by default.
if user/client don't specify it will be null.
Have you added any required field validations to it?
If the client doesn't post actions. Then Actions at the time of model binding would be null. So there isn't any extra work from your side. In other words, if you post only Name and Sub, then Actions would be null.

Web API model validation and default values

This is the spiritual successor to my previous question Web API attribute routing and validation - possible?, which I think was too general to answer. Most of those issues are solved, but the default value question remains.
Basically I have solved many pieces of the puzzle. I have this:
[HttpGet]
[Route("test/{id}"]
public IHttpActionResult RunTest([FromUri]TestRequest request)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
return Ok();
}
My TestRequest class:
public class TestRequest
{
public string id { get; set; }
[DefaultValue("SomethingDefault")]
public string something { get; set; }
}
The problem is that if no parameter is in the query string for something, the model is "valid" and yet something is null.
If I specify a blank value for something (i.e. GET test/123?something=), then the default value comes into play, and the model is valid again.
Why is this? How can I get a default value into my model here? As a bonus, why is it when a parameter is not specified, the default value is not used, but when a blank string is explicitly specific, the default value is used?
(I've been trawling through the ASP.NET stack source code and am knee-deep in model binders and binding contexts. But my best guess can't be right - it looks like the DefaultValueAttribute is used only if the parameter value is null. But that's not the case here)
You need to initialize the default value in the constructor for your Model:
public class TestRequest
{
public TestRequest()
{
this.something = "SomethingDefault";
}
public string id { get; set; }
[DefaultValue("SomethingDefault")]
public string something { get; set; }
}
Update:
With C# 6, you don't need to initialize it in the constructor anymore. You can assign the default value to the property directly:
public class TestRequest
{
public string id { get; set; }
[DefaultValue("SomethingDefault")]
public string something { get; set; } = "SomethingDefault";
}
As documentation of the DefaultValueAttribute states:
Note
A DefaultValueAttribute will not cause a member to be
automatically initialized with the attribute's value. You must set the
initial value in your code.
In the case where you're providing no value for your something property, the property is initialized and the ModelBinder doesn't have a value to assign to it and thus the property defaults to its default value.
Specifying the default in the constructor works for when no parameter is specified at all, but when a blank string is specified, null is put into the field instead.
As such, adding [DefaultValue("")] actually worked the best - when a blank string was specified, a blank string was passed in. Then the constructor can specify default values for when the parameter is missing.
To get around this, I've created PreserveBlankStringAttribute, derives from DefaultValueAttribute which is equivalent to [DefaultValue("")].
I would very much welcome a better answer than this, please.

In an MVC4 controller action, how can I validate a model only when it's passed in?

I have a class as such..
public class TestClass
{
[DataMember(IsRequired = true)]
[Required]
public string Test { get; set; }
[DataMember(IsRequired = true)]
[Required]
public string Test2 { get; set; }
}
I'm basically trying to achieve this with my controller action..
public ActionResult Index(string value1, string value2, TestClass testClass)
{
if (testClass != null && !ModelState.IsValid)
{
//return validation errors
}
//continue processing
However due to MVC model binding, TestClass is not null and therefore it's instantiated containing null properties for the strings Test and Test2, which in turn forces it to check the ModelState.IsValid which is of course false.
Can someone point out where I'm going wrong or suggest a better alternative?
EDIT.
I'm checking for a null because the requirement is that value1 and value2 have to be passed into the system, then the TestClass contains extra information on what is being supplied. The extra information isn't required, however it is supplied it needs to be validated.
I think the only solution is to use custom model binding (implement IModelBinder).
This gives you full access over the deserialization of the object.
See this article on SO and Figure 7 from MSDN:
Or maybe you can get in between using an action filter (see section Handling Validation Errors).

Categories

Resources