OK, I have a problem where the ModelState errors are not mapping to the correct properties.
Let me see if I can explain this.
I have a ViewModel like so:
public class MyViewModel
{
public string Prop1 {get;set;}
public string Prop2 {get;set;}
....
}
In my view, I have a model that has a collection of this type which I have an EditorTemplate for. So it generates MyViewModels[0].Prop1, MyViewModels[1].Prop1, etc.
Problem is, when I set the error on the ModelState in my service layer via an interface I have made called IValidationDictionary which has a wrapper around model state, it does not attach the error to the correct row in the view, rather to the end of the model as Prop1.
EDIT
Here is the ModelStateWrapper (VB - Sorry!)
Public Class ModelStateWrapper
Implements IValidationDictionary
#Region "Private Members/Properties"
Private modelState As ModelStateDictionary
Public ReadOnly Property IsValid As Boolean Implements IValidationDictionary.IsValid
Get
Return modelState.IsValid
End Get
End Property
#End Region
#Region "Constructor(s)"
Public Sub New(modelState As ModelStateDictionary)
Me.modelState = modelState
End Sub
#End Region
#Region "Methods"
Public Sub AddError(key As String, message As String) Implements IValidationDictionary.AddError
modelState.AddModelError(key, message)
End Sub
#End Region
End Class
Sounds like you may be using Dependency Injection and injecting the ModelStateDictionary into your ModelStateWrapper class, which is again injected into your Service Layer?
I can only guess whatever is getting injected is not using the Controller class ModelState property (ModelStateDictionary) of your current HTTP request.
Are you by any chance initializing a new instance of ModelStateDictionary and passing it into your ModelStateWrapper?
If you are using Dependency Injection, please show me your Injection configuration so I can give you a better answer.
Related
I'm new to ASP.NET MVC, altough could call myself experinced programmer in web forms field.
I'm learning MVC now. Trying to add controller with Entity framework abolities.
Here is below code of model class:
Imports System.Data.Entity
Public Class Users
Public Property ID() As Integer
Public Property Login() As String
Public Property Password() As String
Public Property Avatar() As Image
Public Property Country() As Integer
Public Property City() As Integer
Public Property Phone() As String
Public Property Email() As String
Public Property Registered() As Date
End Class
Public Class StopSaleDBContext
Inherits DbContext
Public Property Users() As DbSet(Of Users)
End Class
When I'm adding controller I got error Unable retrieve metadata from ProjectName.Users Object reference not set to an instance of object.
Compile your project and try again.
I have a controller with a constructor like so:
Public Sub New(Service As ICategoryService)
The service's constructor looks like this:
Public Sub New(Repository As IRepository(Of Category), IValidationDictionary)
I have a class Named ModelStateWrapper that implements IValidationDictionary:
Public Class ModelStateWrapper
Implements IValidationDictionary
Private ModelState As ModelStateDictionary
Public Sub New(ModelState As ModelStateDictionary)
Me.ModelState = ModelState
End Sub
Public Sub AddError(Key As String, Message As String) Implements Core.Interfaces.IValidationDictionary.AddError
ModelState.AddModelError(Key, Message)
End Sub
Public ReadOnly Property IsValid As Boolean Implements Core.Interfaces.IValidationDictionary.IsValid
Get
Return ModelState.IsValid
End Get
End Property
End Class
I want to inject the ModelState of the controller into the ModelStateWrapper, and inject that into the service. Is this possible?
I have looked at custom providers in Ninject, and have the controllers inherit a BaseController class, but it does not seem to work. Any ideas?
Also, what is the standard way to do validation in the service layer that can be used from the controller?
It seems like you would have a problem trying inject ModelState because of the fact that once in an action method you already have the instance of ModelState that you want to pass into your wrapper.
Not every single object needs to or should be injected. Sometimes, this case potentially being one of those times, it is cleaner and easier and simpler to "inject" or provide the dependency or object as a parameter to the method that requires it. That is, pass IValidationDictionary as a parameter to the methods in your Service. Construct a ModelStateWrapper in the controller (new it up or use a Factory), and pass it in.
I refactored some common properties into a base class and immediately my model updates started failing. UpdateModel() and TryUpdateModel() did not seem to update inherited public properties.
I cannot find detailed info on MSDN nor Google as to the rules or semantics of these methods. The docs are terse (http://msdn.microsoft.com/en-us/library/dd470933.aspx), simply stating:
Updates the specified model instance using values from the controller's current value provider.
SOLVED: MVC.NET does indeed handle inherited properties just fine. This turned out to have nothing to do with inheritance. My base class was implemented with public fields, not properties. Switching them to formal properties (adding {get; set; }) was all I needed. This has bitten me before, I keep wanting to use simple, public fields. I would argue that fields and properties are syntactically identical, and could be argued to be semantically equivalent, for the user of the class.
MVC will bind to properties of the inherited class. The model binder calls something like typeof(yourtype).GetProperties() which returns all the inherited members just fine.
Just tested it out with:
public class PersonBase
{
public string Name { get; set; }
}
public class User : PersonBase
{
public string FavoriteFood { get; set; }
}
"My assumption is the methods are reflecting on the top class only,"
How would that work? The "top" class IS the base class too.
this one made me curious too.
i made a edit form for a class Manager who derives from a Person
(after all, managers are persons too :-))
then in this action method
public ActionResult Edit(Manager manager )
{
return View(manager);
}
which wass called from a view with the Manager (derived type) as strong typed Model variable, when hovering the manager variable, it shows me the base class (it actually said: base: Person ) AND the one extra property for the manager
tried the formcollection too, and that also works:
public ActionResult Edit(FormCollection formCollection )
{
Manager manager = new Manager();
UpdateModel(manager );
return View(manager);
}
Is there a difference in terms of security between these two models to be given to View? Ie. in the second example can a webuser/hacker access the methods in any way?
public class ObjectViewModel
{
public PropertyA {get;set;}
public PropertyB {get;set;}
public PropertyC {get;set;}
}
public class ObjectViewModel2
{
public PropertyA {get; private set;}
public PropertyB {get; private set;}
public PropertyC {get; private set;}
private void SetPropertyA()
{
...GetDataFromRepository();
}
private void SetPropertyB()
{
...GetDataFromRepository();
}
private void SetPropertyC()
{
...GetDataFromRepository();
}
}
First, the model itself is not exposed to the web browser. It's only exposed to the view rendering engine which resides on the server. You can expose access via your actions to certain properties in your model, but these are only via query or form parameters. It won't give access to the underlying methods.
Second, one thing you should know is that the default model binder requires that any properties you wish to set be available via public accessors. If you make a property with a private setter, it won't updated via the model binder.
No, those methods cannot be accessed in any way via a View unless you explicitly tell it.
Unless your controller specifically exposes those methods, only properties are available via Model Binding.
When by-passing the view engine and returning something like a Json(model) or XmlResult(model) you can expose your data. However, since your data is being serialized
your view model methods no longer apply.
I have a custom ViewModel defined as :
public class SampleFormViewModel
{
public SampleFormViewModel(SelectList companies, Widget widget)
{
Companies = companies;
Widget = widget;
}
public SelectList Companies { get; private set; }
public Widget Widget { get; private set; }
}
In my Edit POST handler I have the following entry:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(SampleFormViewModel model)
{
Edit form is set up as:
Inherits="System.Web.Mvc.ViewPage<Sample.Web.Models.SampleFormViewModel>"
And it just blows up, not sure what’s going on, has the following error:
No parameterless constructor defined for this object.
Certain I’m missing something really obvious here. Some background, the GET works perfectly and display the dropdown from the SelectList as expected.
I’m guessing the auto-binding back to the custom view model is what is failing but not sure what to do about it.
You need to have a parameterless constructor and I believe that the properties need to have public setters. The default binder creates the object using a constructor that takes no parameters, then uses reflection on the public properties to set values from the form/query parameters.
public class SampleFormViewModel
{
public SampleFormViewModel() { }
public SelectList Companies { get; set; }
public Widget Widget { get; set; }
}
I suspect, though, that what you really want to do is not get the view model, but the underlying Widget model and select list value on form post. I don't think the binder will be able to reconstruct a SelectList on post since it only has the selected value in the parameters.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit( int CompanyID, Widget widget )
{
}
MVC requires, on strongly typed views, that the view can create the class used on that view. This means a constructor without any parameters. And this makes sense. Folks new to MVC will see similar "huh?" issues when they forget/fail to make parameters public and all such related errors that popup when the view attempts to put itself together (as opposed to a compiler error).
But what is "interesting" in this class of parameterless constructor problems is when a property of your class also does NOT have a parameter-free constructor. I guess this is the pessimistic approach?
Having spent some learning time on the SelectList class - a class specific to MVC - I wanted to hopefully help some folks save a few minutes/hours.
This really important tool/class for dropdown list creation, has the following constructors:
public SelectList(IEnumerable items);
public SelectList(IEnumerable items, object selectedValue);
public SelectList(IEnumerable items, string dataValueField, string dataTextField);
public SelectList(IEnumerable items, string dataValueField, string dataTextField, object selectedValue);
..and therefore, if these are properties on your class (the one used for the view), MVC will give you the elusive "No parameterless constructor" error.
BUT, if you create something like a helper class, cut-n-paste the exact code from your original class, and then make that helper class a parameter (NOT a get/set) on your original class; you're good to go.
And in this manner, you can use a single view for gets and posts. Which is more beautiful :)
Personnally, I'd have either created the compiler to recognize the associations and requirements of strong typed views, or let the dropdown (or other "customer" of the SelectList) just fail to work rather then wonder if there's a specific level of recursive checking on paramerterless constructors.
Thankfully, the current version seems to only be top-level. Feels like a hack and I hope it's by design.
HTH.