views:

319

answers:

4

I am relatively new to MVC, so this is likely a novice question.

I am trying to understand the best practices for how to maintain clear separation of concerns in a few scenarios that don't appear straightfoward.

There are two scenarios I am looking at right now. Imagine a very basic app that lets users view and edit online profiles for lawyers. There is an action/view to display a particular user's profile and an action/view to edit a particular user's profile. It's easy to imagine a nice and clean Model class to represent the details of a user's profile, perhaps made with the Entity Framework and mapped to the user profile SQL table.

In the view action/view for displaying a user's profile, functionally, I need to have a button or link that lets a user edit the profile. But that should only be available to some subset of users. For example, the user can edit their own profile. Also, super users can edit anyone's profile. My question is how should the View decide if the link should be there when rendering a particular profile. I assume it is wrong for the View to contain the logic to determine if the current user can edit the current profile. Should I add a IsEditable property to the UserProfile model class? That doesn't feel tragic, but it doesn't feel completely right either. Should I make a new Model class that aggregates the UserProfile with additional information about security?

Another scenario... When editing a particular profile, one of the things that is editable is the list of specialties for a particular lawyer. The list of possible specialties is not fixed. If the view wants to render them in combo box, it needs the list of all possible specialties form the database. The view shouldn't be getting them from the database directly, so do I do the aggregate Model thing again and provide the View with both the UserProfile and a list of valid specialties?

I guess the generic issue I am trying to figure out is should I be comfortable with creating lots of little Model classes that are essentially specific to individual views. Each class would include the various unrelated parts of the larger Domain Model needed for that particular view.

+2  A: 

For your scenario I pass along another parameter in the ViewData, ViewData["AllowEdit"] which is set to true if the View should show the edit link. I prefer this to cloning the model into a view-specific model to add this single attribute. I do sometimes create view specific models -- for instance I have Grid ViewUserControl that takes a Grid model, which I can produce from any list of other model classes -- but I wouldn't in this case.

In my view I would do something like this:

<% if (Convert.ToBoolean(ViewData["AllowEdit"])) { %>
<%= Html.ActionLink("Edit", "Edit", "Profile",
                    new { id = ViewData.Model.ID }, null ) %>
<% } %>
tvanfosson
+1  A: 

For your first situation, I would probably try to encapsulate the logic for this in the profile model, perhaps with a function like CanEdit() which accepts user information parameters and checks whether the user is the owner of the profile or if they have superuser permissions. Then in the controller I would call the function and pass the results to the view using ViewData.

For the second, in the edit profile controller action, retrieve the specialties list (via the model) and pass it on to the view using ViewData.

CodeMonkey1
A: 

You can make a base model class for all your view model classes and include there information which can be considered useful in many view, even if not in all of them. For example, the ID of the currently logged in user.

public class BaseModel { Guid ActiveUserId; }

public class EditModel : BaseModel { Guid AuthorUserId; }

Then, in your view you can make a basic comparison:

<% if (Model.ActiveUserId == AuthorUserId)
    Response.Write (Html.ActionLink (.....)) %>

This simple check is quite okay, it's not much of the logic and anyway, someone should decide whether this link should appear. You can make of course two different views, with the link and without one, but it's rather overkill.

User
A: 

ViewModel pattern is more specifically geared towards the scenario that you have described. You can use the ViewData but this is the less recommended solution since you loose lots of the benefits of the ASP.NET MVC framework. For example, when you use ViewData you do not have type-safety, compile-time chekcing and intellisense support in your views.

For a more comprehensive look on the usage of ViewModel pattern in ASP.NET MVC see this blog post. http://theminimalistdeveloper.com/2010/08/21/why-when-and-how-to-use-typed-views-and-viewmodel-pattern-in-asp-net-mvc/

The post goes into good detail on what it is, how it came about and when best to use it? It also discusses how the ViewModel pattern came about, what problem it addresses and how it can be implemented in ASP.NET MVC

Bikal Gurung