Adding and removing items dynamically in one View with Entity Framework and MVC - asp.net

I've been at this same question in different forms now for a while (see e.g. Entity Framework and MVC 3: The relationship could not be changed because one or more of the foreign-key properties is non-nullable ), and it's still bugging me, so I thought I'd put it a little more generically:
I feel this can't be a very unusual problem:
You have an entity object (using Entity Framework), say User. The User has some simple properties such as FirstName, LastName, etc. But it also has some object property lists, take the proverbial example Emails, to make this simple. Email is often designed as a list of objects so that you can add to that object properties like Address and Type (Home, Work, etc). I'm using this as an example to keep it generic, but it could be anything, the point is, you want the user to be able to add an arbitrary number of these items. You should also be able to delete items (old address, or whatever).
Now, in a normal web page you would expect to be able to add these items in the same View. But MVC as it seems designed only makes it easy to do this if you call up an entirely new View just to add the address. (In the template for an Index View you get the "Create New" link e.g.).
I've come across a couple of examples that do something close to what I mean here:
http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
and
http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/
The problem is, although the sample projects on these sites work fine, with mock model objects, and simply lists (not an object with a child list), it's a different thing if you actually want to do something with the posted information - in my case save to database through the Entity Framework model. To adapt these cases to that, all of a sudden I'm in a maze of intricate and definitely not DRY code... Juggling objects with AutoMapper and whatnot, and the Entity Framework won't let you save and so on (see above link if you're interested in the details).
What I want to get at is, is it really possible that this is such an uncommon thing to want to do? Update a child collection in the same View as the parent object (such as the email addresses in this case)? It seems to me it can't be uncommon at all, and there must be a standard way of handling this sort of scenario, and I'm just missing it (and no one here so far has been able to point me to a straighforward solution, perhaps because I made it too abstract with my own application examples).
So if there is a simple solution to what should in my view be a simple problem (since the design is so common), please tell me.

Have you tried updating the project at your link to Steven Anderson's blog to bind to a complex object? Create a class in models called Sack and give it a single property and see if you can get it to work.
public class Sack
{
public IEnumberable<Gift> Gifts { get; set; }
}
It only took me a minute to get it up and running as I think you intend. The improvement I would have made next would be to add an HtmlHelper extension that is essentially the same as Html.EditorFor(m => m.SomeProperty), only call it something more meaningful and have it interface with the prefix scope extensions provided in the project.
public static class HtmlExtensions
{
public static IHtmlString CollectionEditorFor<TModel, TValue>(this HtmlHelper html, Expression<Func<TModel, TValue>> expression)
{
if (/* type of expression value is not a collection */) throw new FailureToFollowTheRulesException("id10t");
// your implementation
}
}

Related

ViewModel classes VS defining an Exclude Bind list on the domain class

I have a model class named Server, it contains many navigation properties and properties, which I want to prevent users from binding it. So I find two approaches of doing so to avoid over-posting attacks.
The first approach is to go to each model class and define an Exclude Bind list , with all the properties and navigating properties that should not be bind by users , as follow:-
[MetadataType(typeof(TMSServer_Validation))]
[Bind(Exclude = "Technology,IT360SiteID, VirtualMachines, TMSServer1,DataCenter,OperatingSystem,Rack,ServerModel,TechnologyBackUpStatu,TechnologyRole,TechnologyStatu ")]
public partial class Server {
}
}
The second approach is to create a view model class , with only the properties that can be modified by users as follow:-
public class ServerViewModel
{
public int ServerSize { get; set; }
[Required]
public String OperatingSystem { get; set; }
public String Commnet { get; set; }
}
I find that the first approach is faster to implement , as I only need to define the Exclude list, while the second approach will require me to create view-model class for each of the domain classes. So which approach is recommended to use and why ?
Thanks
Over-posting occurs due to the default model binder not knowing which fields you actually included in the form.
It will try to map all values in the request to object. Attackers can use your form to add additional fields to
query strings/form post data and add properties as part of the request. The default model binder won't
know the difference. Your Server class will deactivate once the mapping is complete and the update is processed.
To prevent over-posting, set the annotation to include fields in the binding, or create a ViewModel like you mentioned in your code.
So which approach is recommended to use and why ?
Both annotation and ViewModel allow binding only on specified fields, but when you use ViewModel you will not bind against business objects or entities, and you will only have properties available for the input you expected.
Once the model is validated, you can then move values from the input model to the object you used in the next layer.
k. Soctt Allen has a good article about which approach is better, you can take a look at by the following link:
http://odetocode.com/blogs/scott/archive/2012/03/11/complete-guide-to-mass-assignment-in-asp-net-mvc.aspx
It's difficult to tell without seeing the rest of your code, but in general I'd say using the ViewModel is probably a better approach for the following reasons:
You separate your view from your business logic
It is safer. If in the future someone adds a property on Server and forgets the Bind-exclude, you're exposed to over-binding without knowing it. If you use the ViewModel-approach you have to explicity add new properties
Maybe this question is a little bit ambiguous because the answers are going to be based on opinions or something. But I'll try to answer it the best I can and indeed is kind of my opinion. So this is the way I see it:
First approach (Bind attribute): Is faster to implement because you only need to add on your class the name of the property you don't want to expose, but the problems comes when you want your class to exclude some properties for one feature and other properties for another feature, and you can't add fields and sometimes in MVC, the views need more fields that the ones provided by the model class and then you're gonna need to use ViewBag or something else. This approach is very handy for fast and smalls projects, but I still don't like to use ViewBag (For aesthetics reasons)
Second approach (ViewModels): Is more work, and more time but at the end (again in my opinion) you get a cleaner and ordered code and you don't need to use the ViewBag, because you can have the perfect object to send to the view depending on what this View needs, so if you a have an object with different views, again depending on the needs, they could share the same ViewModel or they could have a ViewModel for each one. If you have a solution or a big web project, this approach is going to be very handy to keep an ordered code.
Let me know.

Is there a standard way to implement an Edit form for an object that uses collections in ASP.NET MVC2?

Given an extremely simple object with only fields, e.g.:
class Contact {
string firstName;
string lastName;
DateTime birthday;
...
}
When you add a strongly-typed View with view content "Create", you get a nice form with all the fields of your object that passes the form back to the controller, etc, and life is good.
However, when the object becomes slightly more complex, like say we want to store email addresses for Contacts (and of course a Contact can certainly have more than one email address):
class Contact {
string firstName;
string lastName;
DateTime birthday;
ICollection<EmailAddress> emailAddresses;
...
}
Now when you add the strongly-typed view with view Content "Create", you get the same form as before, and the collection is not represented in the form in any way.
So now you have a form which is complete with one exception: you would like to add a section where the user can enter in as many or as few email addresses as they like and have those wrapped up and passed to the Controller on submit.
Is there a standard best-practice way of doing this in ASP.NET MVC2? If so, what is it?
MVC3 handles this a lot better but as your using MVC2 take a look at Steve Sanderson's detailed post on Editing a variable length list, ASP.NET MVC 2-style.
Phil Haack's Model binding to a list also gives you further information on how the default MVC2 model binders handle lists
Well, conceivably you can have your entire view be
HTML.EditorForModel()
If you follow the answer I posted to How to display the content of asp.net cache? to allow the Editor to do a deep dive against your model.
That's not the optimal solution. Manipulating List data in MVC is HARD. Mostly because of years of ASP.NET development has left us so disjoint from the metal of the web that the concepts of editing a list client side is easily lost on us.
For working with lists, you will also most likely need to work with client templating to be able to add new elements and remove elements easily. This can be get very complex due to the fact MVC requires all lists to be indexed and follow numerically otherwise on post backs you will be missing items (aside: I feel this was a terrible design decision)
Now with this being said, I would recommend looking at the KnockoutJS and KnockoutMapping frameworks which with the combination of jQuery and jQuery templating will allow you to create a very rich client experience. This unfortunately will most likely be a very radical departure from your existing development style however I feel what Knockout brings to the table is revolutionary and will open up the web so much further to ASP.NET MVC developers.

Keep a history of values for specific properties of EF entities

I have a requirement to keep a history of values of some fields in an EF4 ASP.NET MVC3 application. This just needs to be a log file of sorts, log the user, datetime, tablename, fieldname, oldvalue, newvalue.
Although it would be pretty easy to code this in various save routines, I'm wondering if I can get global coverage by wiring it into some sort of dataannotation, so that I can perhaps declare
[KeepHistory()]
public string Surname { get; set; }
in my partial class (I'm using POCO but generated from a T4 template).
So Questions
1) Is this a bad idea ? I'm basically proposing to side-effect changes to an entity, not directly referenced by the code, as a result of an annotation.
2) Can it be done ? Will I have access to the right context to tie up with my unit of work so that changes get saved or dropped with the context save?
3) Is there a better way?
4) If you suggest I do this, any pointers would be appreciated - everything I've read is for validation, which may not be the best starting point.
Actually, validation might be a good starting point. Since an attribute does not know about which property or class it was assigned to, but a validation-attribute gets called by the validation framework with all the necessary informátion. If you implement the System.ComponentModel.DataAnnotations.ValidationAttribute class you can override the IsValid(object, ValidationContext) method, which gives you the actual value of the property, the name of the property and the container.
This might take a lot of work, since you need to get to the currently logged-in user etc. I'm guessing that the .NET implementation provides some sort of caching for the specific attributes on an entity type, which would be a pain to implement by yourself.
Another way, would be to use the ObjectStateManager exposed by your EF ObjectContext, which can provide you with the ObjectStateEntry-objects for all entities of a given state. See the
ObjectStateManager.GetObjectStateEntries(EntityState) method, for more information about how to call it (and when). The ObjectStateEntry actually contains a record of the original and current-values, which can be compared to find any changes made within the lifetime of the current ObjectContext.
You might consider using the ObjectStateManager to inject your custom logging behavior, while this behavior decides based on property-attributes which change should be logged.

ASP.NET EntityFramework 4 data context issues

I'm working on a site and there are two projects in the solution a business logic project and the website project. I understand that I want to keep the entity context out of the web project and only use the business objects the framework creates but I can't figure out how to save a modified object this way.
Let's say my entity model created this class:
public class Person //Person entity
{
Int32 Id {get;set;}
String Name {get;set;}
Address Address {get;set;} //Address entity
}
And I created this class to get a specific person:
public static class PersonController
{
public static Person GetById(int id)
{
using (Entities context = new Entities())
{
return context.Persons.FirstOrDefault(x => x.Id == id);
}
}
}
This allows me to get a person without a context by calling PersonController.GetById(1); and I can change the persons properties after I get them but I can't figure out how to save the modified information back to the database. Ideally I would like to partial class Person and add a .Save() method which would handle creating a context adding the person to it and saving the changes. But when I tried this a while ago there were all kinds of issues with it still being attached to the old context and even if I detatch it and attatch it to a new context it gets attached as EntityState.Unchanged, if I remember right, so when I call context.SaveChages() after attaching it nothing actually gets updated.
I guess I have two questions:
1) Am I going about this in a good way/is there a better way? If I'm doing this in a really terrible way I would appreciate some psudo-code to point me in the right direction; a link to a post explaining how to go about this type of thing would work just as well.
2) Can someone provide some psudo-code for a save method? The save method would also need to handle if an address was attached or removed.
There are many ways to handle Entity Framework as a persistence layer.
For one, it looks like you're not using pure POCOs. That is, you let EF generate the classes for your (in the EDMX.designer.cs file).
Nothing wrong with that, but it does inhibit a clean separation of concerns (especially when it comes to unit testing).
Have you considering implementing the Repository pattern to encapsulate your EF logic? This would be a good way to isolate the logic from your UI.
In terms of Save - this is where it gets difficult. You're right, most people use partial classes. Generally, you would have a base class which exposes a virtual "Save" method, which the partial classes can then override.
I personally don't like this pattern - i believe POCOs should not care about persistence, or the underlying infrastructure. Therefore I like to use pure POCOs (no code gen), Repository pattern and Unit of Work.
The Unit of Work handles the context opening/saving/closing for you.
This is how (my) Unit of Work does the magic. Consider this some code in your "Web" project:
var uOw = new UnitOfWork(); // this is class i created, implementing the UOW pattern
var person = repository.Find(10); // find's a "Person" entity (pure POCO), with id 10.
person.Name = "Scott";
uOw.Commit();
Or adding a new Person:
var uOw = new UnitOfWork();
var newPerson = new Person { Name = "Bob" };
repository.Add(newPerson);
uOw.Commit();
How nice is that? :)
Line 1 creates a new sql context for you.
Line 2 uses that same context to retrieve a single "Person" object, which is a hand-coded POCO (not generated by EF).
Line 3 changes the name of the Person (pure POCO setter).
Line 4 Saves the changes to the data context, and closes the context.
Now, there is a LOT more to these patterns than that, so I suggest you read up on these patterns to see if it suits you.
My repository is also implemented with Generics, so I can re-use this interface for all business entity persistence.
Also take a look at some of the other questions I have asked on Stack Overflow - and you can see how I've implemented these patterns.
Not sure if this is the "answer" you're looking for, but thought I'd give you some alternative options.

Which method of re-use is better in this case - ascx or other

I've got an ASP.NET application that shows grades for different kinds of students. Some students have a self-paced course that doesn't include late penalties and quizzes, and others have a standard classroom course that does.
So, when displaying a student's grade, I determine which category that student falls in, and then render the grade appropriately.
Right now I do this with conditional statements, but I thought about making each case into an ascx file (i.e. one ascx with a gridView for self-paced, and one with a gridView for classroom, each of which calls data population methods in my data access class).
I may need to re-use this functionality elsewhere in the app, to show grades on different pages, so some kind of custom control seems warranted.
Is this approach feasible?
This approach sounds good to me - controls are designed to help you reuse code. I think a set of UserControls would work just fine here.
This approach is definitely feasible, and it makes it easy to change if you want to modify the way the HTML is displayed at a later time (new styles, etc.). I would say ASCX is a good approach.
Make sure you are adequately separating your calculation logic from the display. I would use a class to actually determine the grades (perhaps multiple classes with a nice inheritance tree) to actually do the match, and the just render appropriately in your user control.
If you have multiple classes (or some property for determining what type a particular isntance is) you could also then easily create a factory to instantiate user controls for you where you will get the correct user control type, based on the calculation passed.
Here's how I understand your app:
You have students that are registered for courses.
Students can be standard or self-paced.
The grading method per course is different for different types of students.
You need a way to display the correct grade based on the student's type.
I would think you could get by with a single control for displaying grades but would definitely make sure to separate your logic. Maybe something like:
public class Student{
public GradingType Type {get;set;}
public List<Course> RegisteredCourses{get;set;}
//etc...
}
public class Course{
//etc...
}
public static class GradeCalculator{
public static CalculateStudentGrade(Student student, Course course){
//grade logic...
}
}

Resources