validate model state without passing model - asp.net-mvc-4

I want to validate model using below code
if (ModelState.IsValid)
{
}
The issue is that when I passed model object to controller action its working properly but when I called controller action using below code
public ActionResult Save()
{
}
Then my model state is always return true.So please clarify me is it possible to check ModelState.IsValid using above code.In my case save method is common which is call from multiple controller,so model is not fixed parameter.So please let me know how validate model.

MVC uses a model to extract the validation attributes, as a means for validation. You can explicitly call ValidateModel() or TryValidateModel() in the controller directly, but again that is validating a model, using model validation attributes. If you aren't explicitly using a model, you can access the form directly as you probably know, or can manually validate input and then add appropriate model validation errors using:
ModelState.AddModelError("PropertyName", "ErrorMessage");
Or use this technique depending on how your app is structured: How to add ModelState.AddModelError message when model item is not binded

ModelState.Clear();
Validate(model);
if (ModelState.IsValid)
{
// Do something
}

Related

Umbraco custom controller not using declared model type

Umbraco 9 - I've created a page type called SiteSearch and a controller to hijack requests to pages of that page type. This all works correctly.
The controller gets an IEnumerable from a very simple search service and sets it on a ViewModel, which is then passed to the view.
However, I simply cannot get the view to respect the model declaration. I am getting the error:
ModelBindingException: Cannot bind source type
Maysteel_Web.ViewModels.SiteSearchViewModel to model type
Umbraco.Cms.Core.Models.PublishedContent.IPublishedContent.
It seems to be forcing my view to use an instance IPublishedContent (singular), even though I'm declaring the model as my custom object. I've tried changing the model declaration to string just to see what would happen:
InvalidOperationException: The model item passed into the
ViewDataDictionary is of type
'Maysteel_Web.ViewModels.SiteSearchViewModel', but this
ViewDataDictionary instance requires a model item of type
'System.String'.
There it recognized the model, but when I declare my custom object as a model, it goes back to trying to bind to IPublishedContent (singular). I've verified that the model I'm passing is not null and actually has results. I'm not sure what else to try. Can anyone help me undertand why this is happening?
SiteSearchController action:
public override IActionResult Index()
{
var searchPage = new SiteSearch(CurrentPage, _publishedValueFallback);
var results = _searchService.QueryUmbraco("about");
var viewModel = new ViewModels.SiteSearchViewModel();
viewModel.Results = results;
return View("~/Views/SiteSearch/index.cshtml", viewModel);
}
View:
#model Maysteel_Web.ViewModels.SiteSearchViewModel
#{
Layout = "/Views/Main.cshtml";
}
<h1>Site Search Page</h1>
ViewModel:
public class SiteSearchViewModel
{
public IEnumerable<IPublishedContent> Results { get; set; }
}
I just figured it out. My layout view had the following line in it:
#inherits Umbraco.Cms.Web.Common.Views.UmbracoViewPage
Once I removed that, I no longer get the error. It must have been forcing the ViewModel to be IPublishedContent.

Which filter to manually deserialize incoming JSON to a specified type

I'm developing an application with ASP.NET Core WebAPI. What I would like to do is create a filter that I can apply to my controller method that will then let the system know to explicitly convert the incoming JSON object into a specified type.
For example, this is what I envision being able to do:
[HttpPost()]
[MyFilter(typeof(MyType))]
public IActionResult Post(MyType model)
{
....
}
The reason I want to do this is because the incoming JSON object does not match (at all) the structure of "MyType". So I have written a special converter whose logic I can call from this Filter. I want to explicitly state the type and not try to infer it from values within the JSON object (which is, in my case, impossible).
What I would like to do is create a filter that I can apply to my
controller method that will then let the system know to explicitly
convert the incoming JSON object into a specified type.
Filter is not quite right tool for performing custom model binding you described. You should not reinvent the wheels here: custom model binding should be performed by means of (sorry for this pun) custom model binder.
If the only argument against model binder is:
I cannot use CustomModelBinder as that is injected into the pipeline.
then ASP.NET Core provides an elegant way how to apply model binder to specific action arguments, without adding it to the whole pipeline. This could be done via ModelBinder attribute applied to action paramter, which specifies the binder in BinderType property.
Here is a sample:
[HttpPost]
public IActionResult Post([ModelBinder(BinderType = typeof(MyTypeBinder))] MyType model)
{
return Ok();
}
public class MyTypeBinder : IModelBinder
{
public Task BindModelAsync(ModelBindingContext bindingContext)
{
// Put your custom MyType binding code here
}
}

ASP.NET Core MVC - Model Binding : Bind an interface model using the attribute [FromBody] (BodyModelBinder)

I want to bind an interface model from my action method with a request that the content-type is application/json. I'm using the [FromBody] attribute in my action method.
I tried to create a custom modelBinder derived from ComplexTypeModelBinder, by following this link: Custom Model Binding in Asp.net Core, 3: Model Binding Interfaces, but it doesn't work, my model is always null. I learned after that when you use the atribute [FromBody] the BodyModelBinder is called and internally is calling JsonInputFormatter and it doesn't use the custom modelBinder.
I'm looking for a way to bind my interface model. I can use the MVC DI to map each interface with its implementation. My action method is defined as :
public async Task<IActionResult> Create(IOperator user)
{
if (user == null)
{
return this.BadRequest("The user can't not be null");
}
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
IOperator op = await this.AuthenticationFrontService.CreateOperatorAsync(user.Login, user.Password, user.FirstName, user.LastName, user.ValidUntil, user.Role, user.Comment);
return new CreatedAtActionResult("Get", "operators", new { id = ((Operator)op).Id }, op);
}
I tried another solution by using the MetadataType attribute in my interface but it doesn't exist in the namespace System.ComponentModel.DataAnnotations and i read that asp.net core mvc doesn't use this attribute Asp.Net MVC MetaDataType Attribute not working. I don't want to install the package microsoft.aspnetcore.mvc.dataannotations in domain model project to use the ModelDataType attribute.
I tried another solution by creating a custom JsonInputFormater in other words i derived the class JsonInputFormatter and by analyzing the source code, i've found that the JsonSerializer couldn't deserialize an interface which is logical. So i'm looking for a solution where i could custom the jsonserializer maybe by using a resolver or a generic converter.
Any help will greatly appreciated.
Thanks.
Using an interface is fine for a C# method, but MVC needs to know what concrete type it should instantiate when calling an Action since it's creating it. It doesn't know what type to use, so it can't bind input from Form/QueryString/etc to. Create a very basic model for use in your action that does nothing but implement your interface IOperator, if your goal was to keep it slim, and set that to your Action parameter and it should work fine.
I have tried using an interface on a action as well, and through my own searching, I found no way to get it to work, other than just using classes instead of interfaces to bind to.
public class Operator : IOperator
{
//Implement interface
}
.
public async Task<IActionResult> Create(Operator user)
{
if (user == null)
{
return this.BadRequest("The user can't not be null");
}
if (!this.ModelState.IsValid)
{
return this.BadRequest(this.ModelState);
}
IOperator op = await this.AuthenticationFrontService.CreateOperatorAsync(user.Login, user.Password, user.FirstName, user.LastName, user.ValidUntil, user.Role, user.Comment);
return new CreatedAtActionResult("Get", "operators", new { id = ((Operator)op).Id }, op);
}

How to model bind path segment to object property

I have the following controller method which accepts command as a change model passed from the client.
[HttpPut]
[Route("api/features/{name}")]
public async Task<IActionResult> PutFeatureValueAsync(
string name,
[FromBody] SetFeatureCommand command,
CancellationToken token)
{
command.FeatureName = name;
await mediator.Send(command, token).ConfigureAwait(false);
return Ok();
}
The problem is that I have to copy a FeatureName property to the command object manually if I want to keep the {name} in the url. The other problem is that I can't properly do a validation if the FeatureName is not set during model binding.
What would be the best way to have {name} segment of the path to automatically model bind to FeatureName property of the command.
This could be achieved by using custom model binding.
I would recommend starting from reading Model Binding documentation and then look into Custom Model Binding topic. It explains both available approaches and samples shows almost what you need:
the custom model binder (via own implementation of IModelBinder)
This approach requires your model modification: you will need to apply [ModelBinder] attribute to your SetFeatureCommand class
the custom model binder provider (via own implementation of IModelBinderProvider). This is how the built-in framework binders are implemented. Provider then is registered using MVC middleware options:
services.AddMvc(options =>
{
// add custom binder to beginning of collection
options.ModelBinderProviders.Insert(0, new OwnBinderProvider());
});

RedirectToAction with model and List properties

I have a 2 views with model as Account. From view one, I am using RedirectToAction to go to view two and sending the model object as below:
[HttpPost]
public ActionResult Login(Account account)
{
//Some code here
return RedirectToAction("Index", "AccountDetail", account);
}
AccountDetail controller looks like this:
public ActionResult Index(Account account)
{
return View("ViewNameHere", account);
}
The model object contains a property like this:
public class Account
{
// Some code here
public List<Details> Details{
get;
set;
}
In the first controller, before making call to RedirectToAction there is one item in Details. However, in the Index method of second controller, there is nothing.
Can someone help pointing out the flaw here? Since I am beginner with MVC, cannot seem to figure it out.
You should not pass a complex object to a GET method. Apart from the ugly URL it would create, you could easily exceed the query string limit and throw an exception.
In any case you cannot pass a collection (or a complex object containing a collection) to a GET method using RedirectToAction(). Internally the method uses reflection to generate the query string by calling the .ToString() method of each property of the model, which in the case of your collection property will be something like ../AccountDetail/Index?Details=System.Collections.Generic.List<Details>.
When the Index() method is called, a new instance of Account is initialized and the value of its property Details is attempted to be set to the string System.Collections.Generic.List<Details> which fails and the result is that property Details is null.
Options include passing an identifier and get the collection from the repository or Session or TempData