The question is, as in title, whether the MVC model binder allow private constructors for the view model objects. Apparently it doesn't, saying MissingMethodException: No parameterless constructor defined for this object. even if there is a private parameterless constructor.
In case if there is no private constructor allowed, is there an arhitectural workaround?
Such constructor might be useful to ensure that only the model binder could create ViewModel objects whose fields might not be consistently filled - there would be no chance that in other parts of code some fields are forgotten to complete.
Entity Framework, in a similar situation, can use private constructor and private properties.
No, it does not.
If you want to prevent actual code from calling that constructor, you can add [Obsolete("For model binding only", true)] to a public constructor. This will cause a compiler error if the constructor is explicitly called.
You can always write a custom model binder that does support private/protected ctors.
Related
I got a problem with my project , when i am adding a controller it gives me an error which reads like this: There was an error running the selected code generator: 'Unable to retrieve metadata for 'Invotech.Model.LoginView". No parameterless constructor defined for this object.
I had this problem, too. The issue was that the DbContext class had no parameterless constructor.
Make sure both your model class and your DbContext class have parameterless constructors
Compile/Build your solution before trying to create your new controller/views -- It uses the versions from the .DLL and not the version from the source.
Also note that while using Visual Studio's scaffolding is super-easy, it couples your business logic, database logic, and views together. Not good separation of concerns!
Just saying.
Add [key] as your primary key identifier in your table and check whether your DataContext is declared as the following :
public class DataContext : IdentityDbContext <ApplicationUser>
I would like to pass a connection string to the constructor of DbContext. The way to do this has been answered here: Pass connection string to code-first DbContext
(code if you don't like to click)
public MyContext(string connString)
: base(connString)
{
}
However, when I attempt to enable migrations I receive the error: "The target context '...' is not constructible. Add a default constructor or provide an implementation of IDbContextFactory."
Also, when I attempt to use EF PowerTools to generate an Entity Data Model is receive the error: "A constructible type deriving from DbContext could not be found in the selected file."
Is this a common problem? I have a fix, but it feels like a hack. Any one else have to deal with this before?
Add also an empty constructor, e.g...
public MyContext()
{
}
Thing is once you define a parametrized ctor your default one gets hidden
e.g. see Why does the default parameterless constructor go away when you create one with parameters
That's also one way of 'hiding' default construction from the outside users.
Usually you don't even expose that 'other' ctor to the outside - as its 'yours', you just hardcode inside what you need. Or alternatively and better - you use the 'app.config' to specify the connection string. For details (and problems with it) see...
Migration does not alter my table
Migration not working as I wish... Asp.net EntityFramework
I have a custom model binder that inherits the DefaultModelBinder that looks like this.
Public Class GridFormBinder : Inherits DefaultModelBinder
Public Overrides Function BindModel(controllerContext As System.Web.Mvc.ControllerContext, bindingContext As System.Web.Mvc.ModelBindingContext) As Object
Dim result As Object = MyBase.BindModel(controllerContext, bindingContext)
'Code to handle special case for grid/List binding.
Return result
End Function
End Class
The reason I have this custom binder is that I am presenting various list of items in a grid (using devexpress mvc gridview) and I bind the controls in the grid to the list of items.
If I use a class derived from BusinessCollectionBase (from a very modified CSLA framework class) everything works exactly like I want. BusinessCollectionBase derives from a class that looks like...
<Serializable()> Public MustInherit Class BindableCollectionBase(Of T As IBusinessData)
Inherits CollectionBase
Implements IBindingList
Implements System.Collections.Generic.IEnumerable(Of T)
But if I bind to, say, a class that inherits from BindingList<Customer> the MyBase.BindModel(controllerContext, bindingContext) always returns nothing. I have tried various generic and non-generic BCL collections and the BindModel method always returns null.
Is there something I have to do to get the DefaultModelBinder to create and return the model for regular collections?
I looked at the source for DefaultModelBinder and figured out the problem.
In the DefaultModelBinder in the BindComplexModel method if the type is not an array and is a generic IEnumerable ( IEnumerable<>) AND it is an instance of ICollection<> it will call UpdateCollection. It cannot populate the collection for all the reasons stated. Because the count = 0 the UpdateCollection method returns null. So my classes that derive from ICollection (BindingList for example) will have this behavior.
However my custom collection actually derives from the old CollectionBase class (and it implements the generic IEnumerable seperatly). This means that BindComplexModel does not try to populate the collection and instead just binds to the object as normal.*
Personally I think this is a bug or at least an oversight. If you are binding to a collection and the form has 0 items (say the user has deleted all the rows) you would get nothing back from the default binding. But shouldn't you just get the collection with zero items? What is the reasoning behind returning nothing? This puts more work on the MVC developer because now they have to check for nothing first.
But anyway this is the reason why.
*And this is also the reason I couldn't get the examples of binding to collections to work with my classes. They are not arrays but neither are they IEnumerable<> or IDictionary<>. Yet another bug I think.
In a class derived from WebViewPage<TModel> (say MyCustomWebViewPage) that is used as a base class of all views in an MVC application, I am creating and initializing another class that needs ViewData and TempData. My first attempt was to construct this class in constructor of MyCustomWebViewPage. While ViewData is constructed by that time, TempData is not (it is null). I looked for some other method I could override, may be ConfigurePage or InitializePage but none of them are virtual. So, for now, I implemented delayed construction of this class. Curious to know when TempData is constructed and if there is another method that can be overridden.
How do bind my domain object Car to View?
MVC says "your class must have default constructor". But I don't want to change any business rules by creating a default constructor. The only solution I can see - is to use CarView in my View and then map it to Car.
P.S. NHibernate wants a default constructor too, but it can be protected. This I can do.
IMHO, its a good idea to seperate the objects that go to your view from you domain objects. This has a long list of advantages (which I am not going into now).
You can then use Automapper to map your view models to your domain objects
You could create the object yourself and call UpdateModel to do the binding instead:
public ActionResult MyAction()
{
var car = new MyCar(somethingToPassIntoTheConstructor);
UpdateModel(car);
// Do stuff with car.
}