Web API parameters binding - asp.net-web-api

I have this action in Web Api controller:
public Data GetData(ComplexModel model)
and model is
class ComplexModel
{
Guid Guid1 { get; set;}
Guid Guid2 { get; set;}
string String1 { get; set;}
}
i would like to specify custom binder for Guid type such as empty string or null would bind to empty guid and would like not use nullable type. Was trying to register model binder like this:
var pb = configuration.ParameterBindingRules;
pb.Insert(0, typeof(Guid), param => param.BindWithModelBinding(new GuidBinder()));
but it is not called and I am getting invalid model state with error message that empty string cant be converted to type Guid.

Remember, ParameterBindingRules checks the controller action parameter itself (ComplexModel in your case), not the contents of the parameter. You'd need to register a parameter binding against ComplexModel and do any processing with the custom binder to validate the model instance. Seems like you're better off making the Guid properties nullable despite your reluctance to do so.

Related

ASP.NET MVC model binding vs nullable reference types

I just created a new ASP.NET MVC application using .NET 6.0 and C# 10, and in this project template the Nullable Reference Types feature is enabled by default. But OK, I'm learning how to deal with this feature.
I had the following ViewModel class:
public class CustomerViewModel
{
public string Name { get; set; }
}
To avoid the Nullable Reference Type warning for the Name field, I created a constructor to initialize this field:
public class CustomerViewModel
{
public CustomerViewModel(string name) => Name = name;
public string Name { get; set; }
}
But now, when I try to receive this ViewModel in my controller action, the binding mechanism asks for a parameterless constructor:
public IActionResult CreateCustomer(CustomerViewModel customer)
{
}
If I add a parameterless constructor to my ViewModel, I get the Nullable Reference Type warnings again, because the Name field will not have a initial value outside the constructor.
This field is non-nullable, so I can't make it nullable by adding a question mark operator. And for me it doesn't make sense to initialize this field with a "random" value, like String.Empty.
How are you dealing with this feature? Have you ever faced a scenario like this? And how did you solve it?
Thank you.
Due to the nature of model binding (first instantiate an object, then fill its properties), there is a conflict with the Nullable Reference Types feature. However, there is a good blog post which offers 3 ways of dealing with this:
Declare all fields as nullable and add a [Required] attribute
[Required]
public string? Name { get; set; }
Add the Null-forgiving operator to all non-nullable properties
public string Name { get; set; } = null!;
Disable nullability warnings for the ViewModel
#nullable disable warnings
public class CustomerViewModel
{
public string Name { get; set; }
}
Just like the author of the blog, I prefer the third approach. Since the issue only occurs on classes that require a parameterless constructor, the nullable check can be disabled for these classes only. All properties remain uncluttered.

Validate parameters before model binding for PUT request in web api

How do I distinguish between a parameter being sent as String.Empty and not being sent at all for my parameter binding for a PUT request.
My request class looks like :
public class Person
{
string name {get; set;}
int? age {get; set;}
}
My problem is with binding
When my user sends request as
{
"name":"ABC"
}
In above mentioned case age parameter is mapped as null
However when request looks like below it maps to null as well. I would like to throw a validation error in below situation.
How do I achieve it in asp net core web api
{
"name":"ABC",
"age":""
}
You should take a look at DataAnnotations.
You can add the Range attribute on your nullable int. That will only allow integers or null, not empty strings.
public class Person
{
string name {get; set;}
[Range(0,300)]
int? age {get; set;}
}
If the data annotations are not fullfilled it will set the modelstate to false
Then check the modelstate in the controller method
if (ModelState.IsValid)
{
// your logic
return new HttpResponseMessage(HttpStatusCode.OK);
}
else
{
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
}

WebAPI OData v4 - Using a class to represent an action's parameters

I want to add an action to my OData controller. I'll be calling this action with the request body matching the following structure, and with the following validation requirements:
public class PublishModel
{
[Required, EnumDataType(typeof(JobEventType))]
public JobEventType Type { get; set; }
[Required, StringLength(100)]
public string ExternalRef { get; set; }
public DateTimeOffset? DateTime { get; set; }
}
With a normal ApiController, I'd normally have my controller method simply take an argument of this type, and it'd work. With OData, it seems I have to implement my method using a ODataActionParameters argument.
I can't figure out how I'm supposed to tell OData that the body of the request should match the above. The closest I've got is to have it expect it in a parameter:
var pa = mb.EntityType<Edm.JobEvent>().Collection.Action("publish");
pa.ReturnsFromEntitySet<Edm.JobEvent>("jobevent");
pa.Parameter<PublishModel>("evt");
But this requires me to send
{"evt":{"type":"...","externalRef":"...","dateTime":"..."}}
When what I want to send is just
{"type":"...","externalRef":"...","dateTime":"..."}
I understand that I can just specify the properties of my class as individual parameters, but that'll be harder to maintain and I'll lose the data annotation validation. Is there a way to handle this?

Is there a way in MVC3 to define data validation annotation for a group in a class?

I am new to MVC, recently I am working on the data validation, and I was wondering that in stead of giving a validation annotation for each parameter, is there a way that I can define validation rules for a group of parameters in a class? For example, a class is like this:
namespace MvcApplication1.Models
{
public class Product
{
public int Id { get; set; }
[Required]
[StringLength(10)]
public string Param1 { get; set; }
[Required]
public string Param2 { get; set; }
[DisplayName("Param3")]
[Required]
public string Param3 { get; set; }
}
}
Is there a way to define a rule that for Param1, Param2, and Param3, for example, at least 2 of them are required?
So easy to use. try this one.
MVC Foolproof Validation
and this is how you can build your own custom validation.
http://www.nickriggs.com/posts/build-model-aware-custom-validation-attributes-in-asp-net-mvc-2/
For more advanced validation like this, I would recommend FluentValidation
http://fluentvalidation.codeplex.com/
You can create your own custom validators:
http://fluentvalidation.codeplex.com/wikipage?title=Custom&referringTitle=Documentation
DataType
Specify the datatype of a property
DisplayName
specify the display name for a property.
DisplayFormat
specify the display format for a property like different format for Date proerty.
Required
Specify a property as required.
ReqularExpression
validate the value of a property by specified regular expression pattern.
Range
validate the value of a property with in a specified range of values.
StringLength
specify min and max length for a string property.
MaxLength
specify max length for a string property.
Bind
specify fields to include or exclude when adding parameter or form values to model properties.
ScaffoldColumn
specify fields for hiding from editor forms.

Validating and modifying a variable from MetaData Class

I’m using ASP.NET MVC 3 for a project I have.
The problem is that I would like to save a value to the database, which should before saving into the database be "cleaned" (say removing trailing and ending spaces, and also validate).
I use a MetaData Class to validate the models before I save it to the database with data annotations, using the following code to validate:
if (ModelState.IsValid) {
My MetaData Class looks like this:
public class OrganizationMD {
[Required(ErrorMessage = "*This field is required.")]
[CustomValidationRule(ErrorMessage = "*Another error message")]
public string OrganizationNumber;
}
My first idea was to give the OrganizationNumber string a getter and setter, and there let the value become “fixed”.
For example if someone tries to save a company with "19860415-4785" as organizationnumber, it should automatically remove the trailing "19" and the dash in the string before validating and saving that new value into the database.
I can’t give the model a getter and setter because we’re developing using Model-First, otherwise I think that should work.
Does anyone have any idea how to solve this?
You could create a view model to pass the the data to/from the view and controller instead of using your domain (entity framework) model directly.
Put your data annotations on the view model's property.
public class OrganizationMDViewModel
{
[Required(ErrorMessage = "*This field is required.")]
[CustomValidationRule(ErrorMessage = "*Another error message")]
public string OrganizationNumber {get; set;}
}
Then you can do whatever you think will work in the getter and setter before mapping back to the domain model for persisting.
For readability and easier debugging, you could do your 'cleaning' in the controller instead of in the getter and setter, but that's up to you.
[HttpPost]
public ActionResult SaveData (OrganizationMDViewModel viewModel)
{
if (ModelState.IsValid) {
viewModel.OrganizationNumber...//clean up the value here
OrganizationMD = new OrganizationMD{OrganizationNumber = viewModel.OrganizationNumber}
//...and save
}
}

Resources