views:

39

answers:

1

I have a couple of questions about good design with EF4 in an ASP.NET MVC 2 project.

First, validation. Should I place my form validation within my entities' SavingChanges events? How would I obtain the form data within the partial class? Or is there a better way to do it?

Second, maintaining logged in users. I come from a PHP background where it's customary to pass user info around in sessions. Should I do this with a User entity object? Seems like overkill for that.

+2  A: 

I wrote an app in ASP.NET MVC 1 (.NET 3.5) and used this "design pattern" to handle validation in my Models:

namespace MyProject.Models {

    public partial class SomeModel {

        public bool IsValid {
            get { return (GetRuleViolations().Count() == 0); }
        }

        public IEnumerable<RuleViolation> GetRuleViolations() {

            SomeModelRepository smr = new SomeModelRepository();

            if (String.IsNullOrEmpty(Title))
                yield return new RuleViolation("Title required", "Title");

            if (String.IsNullOrEmpty(Author))
                yield return new RuleViolation("Author required", "Author");

            // Add more validation here if needed

            yield break;
        }

        partial void OnValidate(System.Data.Linq.ChangeAction action)
        {
            if (!IsValid)
                throw new ApplicationException("Rule violations prevent saving");
        }
    }
}

This relies on a class named RuleViolation:

namespace MyProject.Models
{
    public class RuleViolation
    {

        public string ErrorMessage { get; private set; }
        public string PropertyName { get; private set; }

        public RuleViolation(string errorMessage)
        {
            ErrorMessage = errorMessage;
        }

        public RuleViolation(string errorMessage, string propertyName)
        {
            ErrorMessage = errorMessage;
            PropertyName = propertyName;
        }

    }
}

In the controller Create/Edit POST functions, I can check if the model validated with:

    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Create(SomeModel somemodel)
    {
        if (ModelState.IsValid)
        {

            try
            {
                somemodel.DateCreated = DateTime.Now;
                somemodel.DateModified = DateTime.Now;

                somemodelRepository.Add(somemodel);
                somemodelRepository.Save();

                return RedirectToAction("Index");
            }
            catch
            {
                foreach (var issue in chapter.GetRuleViolations())
                {
                    // This add the errors to the view so the user knows what went wrong
                    ModelState.AddModelError(issue.PropertyName, issue.ErrorMessage);
                }

            }
        }

        return View(somemodel);
    }

You can then use the following line in your views to display all the validation errors:

<%= Html.ValidationSummary() %>

And also put this next to the fields like so:

<label for="Title">Title:</label>
<%= Html.TextBox("Title") %>
<%= Html.ValidationMessage("Title", "*") %>

I can't say this is the best way to do it in MVC 2, but it definitely worked great for me in MVC 1 and continues to work in MVC 2.

As far as user sessions go, you can use them in ASP.NET MVC. I am using System.Web.Security.FormsAuthentication and FormsAuthenticationTicket to handle things like creating the session, keeping the username stored in the session, session expiry time and a few other things. Once the session has been created with that, you can store additional info in the session if needed. I do this for data I need on each page load. If its something dynamic like number of forum posts that could change during the session, just grab that from the database as needed.

I did find this block of code in the project, but its been forever since I remember what it all means:

        FormsAuth.SignIn(userName, rememberMe);
        FormsAuthentication.SetAuthCookie(userName, rememberMe);
        FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddDays(1), rememberMe, Convert.ToString(somePieceOfDataIAlsoWantedSaved));

(I copypasted this from the project and changed some variable names. It wouldn't hurt to double-check my syntax and check the relevant documentation as well :p)

Colin O'Dell
That's exactly the same approach I designed using MVC1 and .NET3.5. Good to know I'm not alone! :)
James Dunne
I think I might have gotten that from a book or a website somewhere, although I can't remember. I just know that it works great for my needs, even if it does involve copypasting that code into each model.
Colin O'Dell
Wow, good stuff! Thanks!
kevinmajor1