I am using EF4.3 code first and fluent mapping.
I have:
protected override void OnModelCreating
being executed on application startup. This is done via Windsor DI as my RepositoryContext is created.
When my views come to use the model eg
<div class="editor-field">
#Html.EditorFor(model => model.CostPrice)
#Html.ValidationMessageFor(model => model.CostPrice)
</div>
any attribute on the model is reflected in the validation, but any mapping from OnModelCreating is now lost.
I don't know where to start debugging, so I can't paste the code up without including a large cunk of the application. How do I start investigating?
Validations specified with attributes are recognized by MVC; validations specified in EF initialization code are not, because they aren't accessible at all by MVC.
Only possible solution to avoid repetition: move validations to model attributes.
Related
In my ASP.NET MVC 5.2 application running .NET Framework v4.5.2, my AdminController has an InventoryQueryList method that accepts the model:
[HandleError]
[HttpPost]
public ActionResult InventoryQueryList(CheckInventoryQueryModel model)
{
// ...
}
My view contains the model and calls the InventoryQueryList method on POST:
#model CCNRebuild.Models.CheckInventoryQueryModel
#{
ViewBag.Title = "InventoryQuery";
Layout = "~/Views/Shared/_ConsoleLayout.cshtml";
}
#using (Html.BeginForm("InventoryQueryList", "Admin", FormMethod.Post))
{
#Html.AntiForgeryToken();
<label>
Dealer:#Html.DropDownListFor(m => m.DealerID, Model.Dealerships)
</label>
...
<input type="submit" value="Submit" />
}
But, whenever I click the submit button, I get an error:
MissingMethodException: No parameterless constructor defined for this object.
Why is the view not passing my model parameter to the controller?
The controller has never had a parameterless constructor in the 3 months that I have been working here.
NOTE: I tried to only show relevant code, and I left out anything unnecessary. If there is anything missing that needs to be seen, please comment and I'll try to oblige.
The error is telling you that CheckInventoryQueryModel doesn't have a parameterless constructor, and it needs one. So you would either:
Remove whatever non-parameterless constructor(s) it does have (and update related code accordingly), or
Add a parameterless constructor.
The model binder needs a parameterless constructor in order to construct an instance of the model. (Unless you write a custom model binder for this type. Which probably isn't the road you want to take, but is an option.) This is a fairly common pattern in frameworks that automate model instance creation. Entity Framework, for example.
As for the actual questions being asked...
How does Controller get the Model from the View FormMethod.Post?
and
Why is the view not passing my model parameter to the controller?
It just sounds like you were misinterpreting the error. I see no reason to suggest that the page isn't passing the form value(s) to the server. Though you can always confirm this in your browser's debugging tools by observing the HTTP request being made when posting the form.
The request sends the data to the server, and can do so in a variety of ways. Form posts are generally key/value pairs. The ASP.NET MVC framework's model binder uses those key/value pairs to populate properties on the model. It just couldn't do that in this case because it couldn't create an instance of the model to be populated.
I use FluentValidation to validate my ASP.NET MVC 5.1 viewmodels (using the default unobtrusive client-side validation). I register/create my validators via Ninject (no attributes on the viewmodels):
FluentValidationModelValidatorProvider.Configure(x => x.ValidatorFactory = new NinjectValidatorFactory(_kernel));
AssemblyScanner.FindValidatorsInAssembly(Assembly.GetExecutingAssembly()).ForEach(match => _kernel.Bind(match.InterfaceType).To(match.ValidatorType));
I have a partial view that is used often throughout the application. This partial view has its own viewmodel. The "main" viewmodel (the one for the entire view) just inherits from this "partial" viewmodel.
public class IndexViewModel : PersonalInfoViewModel { ... }
The same pattern is used on the validators:
public class IndexValidator : PersonalInfoValidator { ... }
This works fine and the server-side validation works as well as the client-side validation on the "main" view. But the client-side validation on the partial view is not triggered (no data-val-* attributes on input fields there).
My "main" view Index.cshtml
#model IndexViewModel
#Html.TextBoxFor(x => x.SomeProperty) // client-side validation works fine
#Html.Partial("PersonalInfo") // client-side validation in the partial view does not work (see below)
My partial view PersonalInfo.cshtml:
#model PersonalInfoViewModel
#Html.TextBoxFor(x => x.FirstName) // client-side validation does not work
I noticed that it works when I change the model for the partial view to the "main" viewmodel:
#model IndexViewModel
#Html.TextBoxFor(x => x.FirstName) // client-side validation works
So I guess somewhere when building the client-side validation the correct validator does not get picked up and no data-val-* attributes are injected into the HTML. But I can't changed the viewmodel on the partial view, because it's used on several different pages with different "main" views (all inherit from PersonalInfoViewModel though).
Any ideas on how to get my client-side validation working in this case?
Update
After a few hours of digging through the ASP.NET WebStack source, I found that the problem seems to occur in the TextBoxFor method. There the ModelMetaData is created from the model - and in there somewhere it starts to use IndexViewModel instead of PersonalInfoViewModel to get the metadata for client-side validation:
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
Html.GetUnobtrusiveValidationAttributes("FirstName", metadata); // no client-side validation attributes found
But this generates the correct client-side validation attributes if I don't specify the metadata explicitly:
Html.GetUnobtrusiveValidationAttributes("FirstName");
Unfortunately, I have not found a way to use this knowledge for my advantage so far.
I wasn't able to find a nice solution to my problem, and didn't want to play around with the ASP.NET WebStack source anymore, so I settled with an ugly workaround:
I "manually" inject the missing data-val-* attributes when rendering the input fields, like this:
#Html.TextBoxFor(x => x.FirstName, Html.GetUnobtrusiveValidationAttributes("FirstName"))
Since GetUnobtrusiveValidationAttributes (called stand-alone) builds the correct HTML attributes I just take them and add it the to TextBox. Definitely not beautiful, but it works and I can go on with my work. If somebody has a better solution, I'd be very happy to hear it.
I scaffolded a CRUD scenario for my model to start from. Now I need to add a radio button list field (which doesn't exist but the scenario for a dropdownlist is the same so think of that) for one field (an association to another type, think of a foreign key) to my "create"-view with database driven listitems. I found no other way to do this (without losing my strongly typed view) then to wrap my whole model in another one so I can add the list items.
That means I have to adapt almost every line in the view because they are no longer:
#Html.EditorFor(model => model.Name)
but now:
#Html.EditorFor(model => model.Model.Name)
Is there no way around this?
Let's say we have an ASP.NET MVC View like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<%: Html.EditorFor(model => model.ServiceDate) %>
<%: Html.ValidationMessageFor(model => model.ServiceDate, "*")%>
and we have Model classes that are similar but not exactly the same, for instance Invoice and Quote, which both contain the ServiceDate property. Those two classes do not inherit from the same base class, actually they have no base class currently.
How can I get them to inherit from the same base class when those two are generated by EF? If I would be able to do that, I could replace the dynamic and specify the base class as the View's strong type.
I was under impression that this was the case that dynamic was built for. But obviously it does not work because there's an exception that's apparently coming from LINQ to EF:
CS1963: An expression tree may not contain a dynamic operation
Although it does say in the VS 2010 editor that expression will be resolved at runtime, it is not, but fails in error.
1) Classes generated by Entity Framework use the partial keyword. This means you can easily extend them and not worry about code generation wiping out your changes.
So lets say EF generates: public partial class Customer
What you can do is define another .cs file called Customer_Partial.cs ( just my personal naming preference ) and then do something like:
public partial class Customer : IMySharedInterface
{
}
Then your view pages use:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IMySharedInterface>" %>
and then access your model properties in a strongly typed way.
2) I think this is caused by you passing an IQueryable into your view. Not sure though. With the above solution you won't have to worry about it.
First of all, which EF version are you using?
I suppose your using EFv1, right? You can add inheritance to your models that come from EF. They are all defined as parcial classes by the framework. That means you can create another class with the same name (also parcial) that inherits from the base class.
By the way, I recommend you to use ViewModels in that case. Avoid using inheritance just to reuse some properties, inheritance should be used to add polymorphic behaviour to your classes.
It seems that you are trying to use classes generated by EF in your views. I would recommend you not doing this. That's what ViewModels are supposed to do. Don't be afraid to create a view model for each view (even if you had to repeat some properties) and avoid passing the Model. Also having views that are strongly typed to <dynamic> is as if you had weakly typed views. Once again: avoid them:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<SomeAdaptedViewModel>" %>
<%: Html.EditorFor(model => model.ServiceDate) %>
<%: Html.ValidationMessageFor(model => model.ServiceDate, "*")%>
I have two different user controls both of which has a textbox with the ID: txtEmail. When I render both controls in MVC, I'm running into conflicting IDs. Does anyone have any suggestions to resolve this issue?
Yeah what I generally do is preface the id with the model name.
So my model might be MyModel so my id would be MyModel.txtEmail.
Unsure why you have txtEmail though in MVC. Generally you would have a textbox like so;
Html.TextBox("email") where email is the name of the field in your model.
I would place a small snip of code in the controller that will assign a dynamic name based on which control its coming from.
What griegs said except that if you have strongly typed your view to use a model with Email in you can use <%: Html.TextBoxFor(model => model.Email) %>. It will prefix the ID for you with the model name and everything will generally rock. You will need MVC2 though