My question is quite basic and to do with validating an object in your view model using enterprise library validation application block 5.0.
It seems that when a user enters invalid data, whilst the UI displays the error template for a control, the property in the view model that the control is bound to does not get updated.
This is a problem as I wanted to call code such as this
ValidatorFactory factory = EnterpriseLibraryContainer.Current.GetInstance<ValidatorFactory>();
myValidator = factory.CreateValidator<Customer>();
ValidationResults results = myValidator.Validate(this.CustomerProperty);
if (!results.IsValid)
{
// etc
}
in my save button command in the view model to check that the data is valid.
Example of problem I'm having.
e.g.
If I have a textbox bound to a string property in the vm with a string length validator (min length 1, max 10) then the following could happen;
Enter text of 'ABC'.
UI does not show error.
View model property updated to 'ABC'.
Delete contents of textbox (so now invalid).
UI now shows error (good).
But view model property is now out of sync with UI. Property in the view model is still set to ABC.
Save validation will still pass as the view model data is still valid.
How should I be doing this?
To solve this I ended up removing the validationRule (as per the example in the EntLib 5 hands-on labs documentation) and implemented IDataErrorInfo in my Customer class.
I then changed my XAML and in my textbox binding added
ValidatesOnDataErrors=True
This then validates my object as I'd expect. i.e. Invalid data is propagated to the view model property which I can then validate on my save command.
Related
This question has been asked before by other, but still don't get it.
I am using MVC3 Razor and I have screen for entering trouble tickets.
Once data (a textarea note) is entered, the controller redirects back to the same screen.
Most of the data is for display only. If I use DisplayFor or DisplayTextFor, the data
is not being posted back. I have used HiddenFor. That works. However, I keep hearing
from others that HiddenFor is not ideal. I don't want to editorfor because, I want to easily disable the field. (I follow working says HiddenFor is wrong, but won't say why. :< lol)
Razor
#Html.DisplayTextFor(m => m.Ticket.Name)
ViewModel
public class TicketDetailsViewModel
{
[DisplayName("Customer Name")]
public string Name { get; set; }
Control
[HttpPost]
public ActionResult Detail(TicketDetailsViewModel viewModel)
return RedirectToAction("Detail");
Only values that are part of an input or other form control will be posted back to the client. DisplayFor is just meant for the model to display its data, nothing else.
You have two options; use a hidden field so that the model is populated with the data each time, or fetch the value again. The former method would be fine if your data isn't sensitive because an end user can change the hidden value and repost your form. So for example a UnitPrice would NOT be something you'd want to ever get from the client as even in a hidden field a malicious user can modify the unit price. In that case you'd always want to reload the data yourself and repopulate the model.
There's nothing wrong with that either; if the data isn't editable and you need to display it, you need to get it every time. I'd personally err on the side of caution and refetch the read-only data each time on the server and not put the data into hidden fields.
Still new to LINQ2SQL so please forgive my ignorance ...
I have one user component which includes one Textbox and one button. The component is used as a generic ListOfValue Filter.
The component has one function to set a IQueryable which is passed to a form that is opened when the user clicks a button on the control.
The form consists of a grid (c1flexgrid) which is filled with the data from the IQueryable. There is a bindingsource on the form that gets the IQueryable as datasource.
The user can select inside the grid and after he selected an entry the dialog is closed and the selected row (or better the selected LINQ2SQL object from the row) is passed back to the control.
On this control i want to show one specific field out of that selected object. The name of that field is passed in to the user control as string.
My problem is, i don't know how to get that field data from an "generic" LINQ2SQL object.
In debugger i can see, that the selected object is of a specific enity type (corresponding to the query)
Probably somthing similar to
Workaround for lack of 'nameof' operator in C# for type-safe databinding?
but just the opposit way :)
Any help would be very welcome
I'm assuming in your IQueryable you don't know at design time the type T. If this is correct, you need to use reflection to get the value you want.
var value = typeof(T).GetProperty("MyField").GetValue(instance, null);
Alternatively, cast the instance to a common base type that implements your field.
CommonBase castInstance = (CommonBase)instance;
var value = castInstance.MyField;
I am currently working on a project in MVC 3 where I am leveraging Entity Framework to persist one data model over two Views which each contain one HTML Form (similar to wizard-based design).
Yet after the user fills out the appropriate fields on the first View and submits the form, client-side validation for the entire model is triggered, and validation errors are shown for fields that will not even be available for input until the second View instantiates.
I have currently implemented a workaround where I simply turn off client-side validation for the first View entirely, but I am certainly not keen on the idea of populating my model with data that has not been validated at all. This is bad. M'kay.
Is there any way to partially validate the fields on the first View and not trigger valdiation for the whole data model?
That's where ViewModels comes. Instead of directly binding the domain model with the views, you should create view models over them and bind to the views.
If you are not required to put validation on the EF models directly then you can use the MetadataType to do partial validation as needed. Take a look at my long example here on stackoverflow.
Thanks for the input all. However, I was able to obtain a solution in a very simple way. By placing the following code in the HttpPost element of the first View...
if (ModelState.IsValidField("FirstField") && ModelState.IsValidField("SecondField"))
return RedirectToAction ("NameOfAction", model);
else
return View();
...I was able to achieve partial field validation. However, this field-specific approach will ONLY work provided the Submit button on the first View has class "cancel" and the additional validation errors that are generated (for the fields that are NOT present on the first View) are manually cleared before the above if statement. To do this, use:
ModelState["FieldName"].Errors.Clear();
No major change in architecure. No partial Views. No handing off unvalidated Data.
Works very well...
NOTE: If the second View loads with validation errors, use:
ModelState.Clear();
in the Action where the second View is initially called. This will make the second View load clean and error free, while still showing the validation errors later upon final form submission.
I am using MVC 3 with ASP.NET. I have a dropdown box and getting it populated from database. I am using validation on the View. If it fails the validation, I am displaying the same view with errors being caught in ViewDate.ModelState.AddModelError.
I am checking for the ViewData.Modelstate.IsValid property if true then execute the code else display the errors in the view.
It is diplaying the errors in the page, but the selected value in the drop down is getting reset when validation fails.
How do I make sure the seleceted drop down does not change when validation fails?
In the action that handles the form submission and validation, make sure you set the properties on your model object from the form before rendering the form view.
For example, in this question you can see how the Dinner object parameter in the Create action is reused when the View() is returned.
Set a breakpoint in the action handling the submission and check the property for the list of values. If it's null or empty reload it.
If your dropdownlist is being populated via javascript then it is possible that the property holding the list of values is empty on submission. This is common when using cascading dropdownlists such is the case with loading Province / State lists based off country. All cascading lists loaded after the model has been passed to the view must be reloaded using the selected value of for each dropdownlist in the controller action that is handling the submission.
I am trying to implement validation using IDataErrorInfo or INotifyDataErrorInfo but either way I am struggling to make it work only once user start entering data or clicking save button. Since I am using MVVM, I am setting my view's datacontext to ViewModel and my ViewModel is implementing IDataErrorInfo / INotifyDataErrorInfo. I need to make sure validation happens but not when form loads up. Anyone has got any suggestion how I can implement?
Thanks
Add IsDirty property to your business object. Return no error when IsDirty == false.