Querying database when using viewmodel on web application asp.net mvc3 - asp.net-mvc-3

I have a problem with viewmodel, when I try to add new enregistrement to my database when I have view titly typed with my viewmodel I get DbEntityValidationErrors.
This is code using viewmodel :
[HttpPost]
public ActionResult Create(Annonce annonce)
{
/*
if (ModelState.IsValid)
{
*/
_userservice.addannonce(annonce);
return RedirectToAction("Index");
/*
}
return View(new AnnonceView(annonce));
* */
}
But when I use my entity domain Annonce directly on view, there is any problem. Help me please and sorry for my bad english

I am assuimng your addannounce method is expecting an object of your EntityModel type. Not Viewmodel. ViewModel is specific to handle the View. It is not same as your Entity Model. You can not send a View Model which you created as it is to the entity framework to save it. You need to send an Entity Model. So probably you can read the values of ViewModel and set as the relevant property values of Entity Model and send that to be saved. Something like this
YoueEntity.Announce objEntityAnnounce=new YoueEntity.Announce();
//Read from the posted viewmodel and set the values to entity model.
objEntityAnnounce.ID=annonce.ID;
objEntityAnnounce.Title=annonce.Title;
//Other relevant Properties as well
_userservice.addannonce(objEntityAnnounce);
There are libraries like AutoMapper which does this mapping, You may take a look at them,

Related

MVC 4 automated Model Validation stucks on ViewModel with nested ViewModel

I am using C# MVC 4 serversided. The Gerenel purpose of the site is to get some textual information entered as well as a file committed by the user.
Therefore I use a ViewModel which is the "parent" ViewModel holding information about the textual information entered by the user called FileInformationViewModel. This "parent" ViewModel contains another "child" ViewModel, lets call it FileUploadViewModel.
Each of these ViewModels are derived from the IValidateObject and own their custom Validate function validating only the current attributes of the Model. This means that the "parent" ViewModel will not do any validation for the "child" ViewModel because the "child" ViewModel owns it's own specific validation function.
The "child" ViewModel will be validated through the automated Model Validation offered by MVC 4 and the ModelState will be set as expected. After that the "child" ViewModel is successfully bound to the "parent" ViewModel by MVC Model binding logic.
If the validation fails for the "child" ViewModel the Validate function for the "parent" ViewModel will not be handled anymore but I would like to handle both Validations automated on Model Binding. Is there any way to achieve this or is the only possibility to manually validate the ViewModels on my controller?
To illustrate my construction, here's the "parent" ViewModel:
public class FileInformationViewModel : IValidatableObject
{
public FileInformationViewModel()
{
ViewModel1 = new FileUploadViewModel();
}
public FileUploadViewModel ViewModel1 { get; set; }
public string InputFieldToBeSet { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (!string.IsNullOrWhiteSpace(InputFieldToBeSet))
{
var result = new ValidationResult("Enter some information, please!", new[] { nameof(InputFieldToBeSet) });
yield return result;
}
}
Using IValidatableObject short-circuits validation. The first error returned will cause further validation to stop. That's just the breaks of the game. There's no way around that.
If you need all the errors at once, then you need to let the model binder handle the validation, using data annotations on your view model properties. You can actually handle pretty much every scenario imaginable this way, as you can always add your own validation attributes or there's multiple libraries of validation attributes out there.

.NET MVC3/Holding temp model

I have a situation where i have to take input(form) from user. After continue button is pressed next view page is displayed. But after continue is pressed i don't want to store the model in the DB. I have to display some details(combining some tables) according to input given by the user earlier and again get some data from user. Only then i want to store the model in the respective tables.
How can i perform this? I tried getting Model from user and passing to the function that generates next page. Is this is way to do it? or there is other way around?
Store the model submitted by the first form in session.
[HttpPost]
public ActionResult ContinueForm1(Model1 model1)
{
if(ModelState.IsValid)
{
Session["Model1"] = model1;
return View("Form2");
}
return View();
}
[HttpPost]
public ActionResult ContinueForm2(Model2 model2)
{
if(ModelState.IsValid)
{
... model2 is already here, get the model1 from session
... and save to datatbase finally return a different view or redirect to some
... other action
}
return View();
}
You are heading down the right track.
You need to grab the model that is passed back from the first view - preferably you are using ViewModels here rather than binding directly to your db models. Have a look at http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ and Why should I use view models? as to why these are good things.
The easiest way to do this is to pass the model in as an argument to your method e.g.
Assuming that your views are using the same ViewModel ( which may or may not be true) then you can send the viewmodel straight to your new view - else you can copy the elements into a new viewModel and send that.
e.g.
[HttpPost]
public ViewResult Step1(MyViewModel viewModel)
{
//Do some validation here perhaps
MySecondViewModel secondViewModel = new MySecondViewModel{
Id = viewModel.Id,
// etc. etc.
};
return View("Step2", secondViewModel);
}
Then you can carry on as you need until you have to persist the entity to the database.
NB as you do not need to do anything special in the form to make it post the model as an argument as long as the view is strongly typed to that ViewModel.

which is the best practices for exposing entity or DTO to view in mvc3?

I have created my own customized lots of architecture including n-tier layers for different different technology.
Currently working on n-tier architecture with asp.net mvc framework. The problem is I have entity framework at data access layer. As the entities will have all it's relational metadata and navigation properties, it becomes heavier one. I am feeling like it is not wise to expose this entities directly over mvc view.
I am more favor in exposing own customized model of entities over mvc view which one be lighter one.
But this also leads me overhead of converting data from my original entities to customized model.
For example I have Employee entity which is as generated from edmx file of entity framework. It contains total 20 fields with all navigation properties.
Now over view in mvc I need to show only 2 fields for edit.
So do we need to expose original entity to view or need to create DTO/customized model of that two field and than expose that view?
I would use a view model. I have learnt not to expose my domain objects to the view, I rather map my domain object to the view model and return this view model to the view.
Here is a partial view model, you might have more properties if you need more employee data to create/edit or display:
public class EmployeeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
In my action method of my controller it would look something like this:
public ActionResult Edit(int id)
{
Employee employee = employeeRepository.GetById(id);
// Mapping can be done here by using something like Auto Mapper, but I am
// manually mapping it here for display purposes
EmployeeViewModel viewModel = new EmployeeViewModel();
viewModel.FirstName = employee.FirstName;
viewModel.LastName = employee.LastName;
return View(viewModel);
}
And then your view might look something like this:
<td>First Name:</td>
<td>#Html.TextBoxFor(x => x.FirstName, new { maxlength = "15" })
#Html.ValidationMessageFor(x => x.FirstName)
</td>
I prefer to have a view model that has only the values of employee that is needed on the view. Let say your employee has 20 properties, and you only need to update 2 fields, why then pass all 20 to the view? Use only what you need.
You can expose original entity, that is nothing bad. But as soon as you need some other information on the view e.g. instead of Name and Lastname you need FullName, then you should create an EmployeeViewModel with only needed properties. You initialize it with desired values in an action and then pass it to the view.

How do you exclude properties from binding when calling UpdateModel()?

I have a view model sent to the edit action of my controller. The ViewModel contains references to EntityObjects. (yea i'm fine with it and don't need to want to duplicate all the entities properties in the viewmodel).
I instantiate the view model and then call UpdateModel. I get an error that a property is "null" which is fine since it is a related model. I am trying to exclude the property from being bound during model binding. On debugging it I see in the entity where the model binder is trying to set the value of the property to null.
Here is my edit action:
var model = new SimplifiedCompanyViewModel(id);
var excludeProperties = new string[] {
"Entity.RetainedEarningsAccount.AccountNo"
,"Property.DiscountEarnedAccount.ExpenseCodeValue"
,"Entity.EntityAlternate.EntityID"
,"Property.BankAccount.BankAccountID"
,"Entity.PLSummaryAccount.AccountNo"
,"Property.RefundBank.BankAccountID"
,"Company.Transmitter.TCC"
};
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
I have looked at a few other issues about specifying a "prefix" but I don't think that is the issue since I am telling it to bind to the viewmodel instance not just the entity object.
Am I excluding the properties correctly? Strange thing is is only seems to happen on this item. I suspect it may be an issue with the fact that there is actually no refund bank related to my entity. But I have other related items that don't exist and don't see the same issue.
More info... since I'm told me model isn't designed well.
The Company is related to a BankAccount. The Company view shows the currently related BankAccount.BankAccountId and there is a hidden field with the BankAccount.Key. I use jQueryUI autocomplete feature to provide a dropdown of bank account displaying the BankAccount.BankAccountId and when one is selected the jQuery code changes the hidden field to have the correct Key value. So, when this is posted I don't want the current bankaccounts BankAccountID modified, hence I want it to skip binding that field.
If I exclude BankAccountId in the model then on the BankAccount edit view the user would never be able to change the BankAccountId since it won't be bound. I'm not sure how this indicates a poor model design.
Use the Exclude property of the Bind attribute:
[Bind(Exclude="Id,SomeOtherProperty")]
public class SimplifiedCompanyViewModel
{
public int Id { get; set; }
// ...
}
This is part of the System.Web.Mvc namespace. It takes a comma-separated list of property names to exclude when binding.
Also you should consider using TryUpdateModel instead of UpdateModel. You can also just have the default model binder figure it out by passing it as an argument to the constructor:
public ActionResult Create([Bind(Exclude="Id")]SimplifiedCompanyViewModel model)
{
// ...
}
A very simple solution that I figured out.
try
{
UpdateModel<SimplifiedCompanyViewModel>(model, String.Empty, null, excludeProperties);
ModelState.Remove("Entity.RetainedEarningsAccount.AccountNo");
ModelState.Remove("Property.DiscountEarnedAccount.ExpenseCodeValue");
ModelState.Remove("Entity.EntityAlternate.EntityID");
ModelState.Remove("Property.BankAccount.BankAccountID");
ModelState.Remove("Entity.PLSummaryAccount.AccountNo");
ModelState.Remove("Property.RefundBank.BankAccountID");
ModelState.Remove("ompany.Transmitter.TCC");
if (ModelState.IsValid)
{
//db.SaveChanges();
}
return RedirectToAction("Index");
}
catch
{
return View(model);
}
Another option here is simply don't include this attribute in your view and it won't be bound. Yes - you are still open to model injection then if someone creates it on the page but it is another alternative. The default templates in MVC will create your EditorFor, etc as separate items so you can just remove them. This prevents you from using a single line view editor with EditorForModel, but the templates don't generate it that way for you anyways.
EDIT (adding above comment)
DRY generally applies to logic, not to view models. One view = one view model. Use automapper to easily map between them. Jimmy Bogard has a great attribute for this that makes it almost automatic - ie you create the view model, load up your Customer entity for example, and return it in the action method. The AutpMap attribute will then convert it to a ViewModel. See lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models
Try the Exclude attribute.
I admit that I haven't ever used it.
[Exclude]
public Entity Name {get; set;}

How do I pass an object from the Index view to the edit view using MVC3

I have created a simple WCF service that is to be configured by an MVC3 UI.
When I call the index page from my controller, I want to display the values held in the configuration, which has been returned by the service. The user could then chose to edit these settings and then send them back to the service.
I want to do something like this in the index view ...
<div>
#Html.ActionLink("Edit", "Edit", model)
</div>
and then consume the model in the controller like this...
[HttpPost]
public ActionResult Edit( SettingsModel Config)
{
try
{
List<string> configErrors = null;
if (ModelState.IsValid)
{
// Set up a channel factory to use the webHTTPBinding
using (WebChannelFactory<IChangeService> serviceChannel = new WebChannelFactory<IChangeService>(new Uri(baseServiceUrl)))
{
IChangeService channel = serviceChannel.CreateChannel();
configErrors = channel.SetSysConfig(Config);
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
but this doesn't work.
Any suggestions???
When the form gets posted, all the input type fields data is collected and sent to the server. You can see this data using FireBug. The key point here is that, is the data that is being posted in a form, that MVC's default model binder can understand and map it to the model object, which is being passed as input parameter to the action method.
In your case, the model is of type "SettingsModel". You have to ensure that, the form data that is being posted is in format, that can be mapped to the "SettingsModel" object.
Same kind of question discussed in another thread : Can't figure out why model is null on postback?
Check Out this article : NerdDinner Step 6: ViewData and ViewModel
In the above article, carefully go through the "Using a ViewModel Pattern" section. My guess is that, this is what you are looking for.
You will need to post the values to populate the SettingsModel object on the Edit action. You can do this using hidden form fields if you don't want the user to see it. Otherwise you could have no parameters on the Edit action and make another call to the web service to populate the Settings model.

Resources