ASP.NET MVC Framework Preview

Steven Sanderson

Mentioned 2

The ASP.NET MVC framework is the latest evolution of Microsoft's ASP.NET web platform. It introduces a radical high–productivity programming model, promotes cleaner code architecture, supports test–driven development, and provides powerful extensibility, combined with all the benefits of ASP.NET 3.5. ASP.NET MVC Framework Preview is a first look at this technology's main features, designed to give you a head start getting to grips with this powerful new technology.

More on Amazon.com

Mentioned in questions and answers.

The thing I think I spend most time on when building my business models is the validation of business entities and making sure the entity objects and their relationships maintains good integrity. My dream for a good entity/value object framework would help me create reusable entities/value objects and easily create constraints and rules for relationships as you would in a db but since I feel this really is business rules they belong in the model and should be totally independent of the database.

It should be easy to define that the Name property of a Person object should be required and that the Email property should be required and match a certain regex and that these rules should be easily reusable f.ex. in validating input in my web app.

I have absolutely most experience with Linq to sql and even though it certainly is nice to work with it has limit by not supporting value objects and others. My question is would Entity framework or NHibernate be more suiting or are there other technologies that fit my needs better?

There was a small book I read last year by Steve Sanderson himself that briefed me on DDD concepts. Even though the book was on ASP.NET MVC as a preview, he really focused on the "M" in MVC as a true and pure Domain Model - using almost 1/2 the book on modeling approaches (which I very much enjoyed). One thing he approached was using Value Objects in the context of Aggregate Roots (obviously). But, he also showed how to use Linq to represent the entities, as well as the Value Objects.

The point is, he noted the limitation of Linq that it must have an identity on every object, including Value Objects. He acknowledged it broke the pure domain model approach; but, it was the only way to get it to work with Linq-to-SQL.

His work-around was to give your Value Object an Identity; but, make that identity internal so it is not exposed outside of your model. This will allow you to link and share your objects using Linq in your repositories; while not exposing it to the client layers - so, it is as though they are Value Objects exclusively.

The Entity Framework I believe suffers from the same requirement.

A C# example is below.

public class MyEntity
{
  [Column(IsPrimaryKey = true
    , IsDbGenerated = true
    , AutoSync = AutoSync.OnInsert)]
  public int EntityID { get; set; }

  [Column(CanBeNull = false)]
  public string EntityProperty
  {
    get
    {
      // insert business rules here, if need be
    }
    set;
  }
}

public class MyValueObjectForMyEntity
{
  // make your identity internal
  [Column(IsPrimaryKey = true
    , IsDbGenerated = true
    , AutoSync = AutoSync.OnInsert)]
  internal int ValueObjectID { get; set; }

  // everything else public
  [Column(CanBeNull = false)]
  public string MyProperty { get; set; }
}

in this MVC tutorial it showed how to decouple Controller from database logic using Repository and a Service layer. However the example is for a very simple model of pure properties. What about associations?

Say if Product model has an association to the Users table through Owner association. The controller calls the service or the repository to get a list of users, pass it to View, and View displays the users as a drop-down list.

Then on a standard POST: product/Create, controller needs to get the chosen userID, then grab the User entity of that id, and associate it with the to be created Product.

  if (!String.IsNullOrEmpty(Request["SelectedUserId"]))
        {
            int selectedUserId = Convert.ToInt16(Request["SelectedUserId"]);
            newProduct.Owner = _productService.GetUserById(ownerId);
        }

  _productService.AddProduct(newProduct);

But this process complicates the controller logic. Even worse if we need to validate the associations (since there wouldn't be OnChanging events for the associations, we can't do it in the Model partial class).

My question is, is there any better way to handle associations? Is it better to pass the Request parameters to the service layers as well and do everything there? What about validations?

This is the perfect book you should read about how to properly model (the "M" in MVC) the repositories, models, and he includes direct Linq associations. As a bonus, he tackles how to auto-wire up all of your custom controllers with the repository they expect. Yes, it was written for a version of ASP.NET MVC that is 4 versions old (before the release), but the concepts stick with you. The information applies to all MVC (or any DDD project w/Linq rather) projects.

In short, the book introduces DDD concepts to inject a repository into your custom Controller.

public class ContentController : Controller
{
  IContentRepository _repository;
  public ContentController(IContentRepository repo)
  {
    _repository = repo;
  }

  public ActionResult Add(Content c)
  {
    _repository.Add(c);
    _repository.SubmitChanges();

    return View(c);
  }
}

Notice the dependency injection concept in use here by forcing a repository into the constructor. Now, you could just wire it up yourself without the constructor. But, when you get into a large project (50+ repositories), it helps to use an inversion of control container that facilitates the creation of these objects for you, like Castle Windsor (again, all in that 100 page book above).

For your use-case, you'd simple access the User object from a user repository and then let the rest follow-through.

The book goes into how to model, say your User and Product entities, using LinqToSql with EntityRef and EntitySet, so all of your associations are honored. Which is too much code to write here. Basically, link a User() object to your Product() object by the UserID and decorate each of those entities with Linq attributes:

[Table(Name="ut_Content")]
public class Content : EntityBase
{
  [Column(IsPrimaryKey = true
      , IsDbGenerated = true
      , AutoSync = AutoSync.OnInsert)]
  public int ContentID { get; set; }

  [Column(CanBeNull = false)]
  public string ContentKey { get; set; }

  [Column(CanBeNull = false)]
  public string Title { get; set; }

  [Column]
  public string Description { get; set; }

  [Column]
  public string Body { get; set; }

  [Column]
  public string BodyFormatted { get; set; }
}

He tackles the different LinqToSql use cases, and shows why "Create your model first, do not use Schema-Generated Linq objects" works here.

And, a repository example I guess for good measure:

public class ContentRepository : IContentRepository
{
  private Table<Content> _contents;

  public ContentRepository(string connectionString)
  {
    DataContext db = new DataContext(connectionString);
    _contents = db.GetTable<Content>();
  }

  public void Add(Content entity)
  {
    _contents.InsertOnSubmit(entity);
  }
}

Remember, one of the best things about Linq is its deferred execution feature. You are not operating on an entire Linq Table here. Your query gets deferred so you can filter your IQueryable with Where and Joins and order bys. Only when you request the .ToList() or alike methods is when the query is executed.

Use a DDD Service

Finally, to address your original issue of "getting a user, then adding the product", the DDD (Domain Driven Design) playbook has the perfect solution: Services.

You'd create a UserProductService() class in your Domain that does exactly what you what you did above. But it has the advantage of abstracting the business logic out into your Domain, so other locations can access and use the same business rule.

public class UserProductService
{
  private IProductRepository _productRepository;
  private IUserRepository _userRepository;
  public UserProductService()
  {
    // this is where CastleWindsor can really help
    _productRepository = new ProductRepository();
    _userRepository = new UserRepository();
  }

  public void AddProduct(int userID, Product product)
  {
    User user = userRepository.GetUserByID(userID);

    // your logic above, abstracted into a service
    if (user.IsValid && product.IsValid)
    {
      product.Owner = user.UserID;        
      _productRepository.AddProduct(product);
    }  
  }
}

The DDD rule for services is: When you have two entities, but you need to perform a common action on both, use a service to act upon both entities.