Any comments are welcome. However I'd like to call specific attention to my... interpretation of the N-Tier application architecture and how I'm consuming data. Note that the namespacing and inline comments have been factored out for brevity.
The Data Tier (DataModel.csproj)
// Base class for EF4 Entities
public abstract class EntityBase {
public int Id { get; set; }
}
// Entities
public class Account : EntityBase {
public string UserName { get; set; }
public string Password { get; set; }
public byte[] Salt { get; set; }
public string EmailAddress { get; set; }
}
public class Entry : EntityBase {
public string Title { get; set; }
public DateTime Created { get; set; }
public Account Owner { get; set; }
}
// EF4 Code-First Data Context
public class DataContext : DbContext {
public DbSet<Account> Accounts { get; set; }
public DbSet<Entry> Entries { get; set; }
}
// Repository Pattern
public interface IRepository<TEntity>
where TEntity : EntityBase {
TEntity Create();
void Delete(TEntity entity);
TEntity Get(int id);
TEntity Get(Expression<TEntity,bool>> where);
void Insert(TEntity entity);
void Save();
IQueryable<TEntity> Where(Expression<TEntity,bool>> where);
}
public class Repository<T> : IRepository<T>
where T : EntityBase, new() {
private readonly DataContext context;
private readonly DbSet<T> set;
public Repostory(DataContext context) {
// context injected via ioc.
this.context = context;
this.set = this.context.Set<T>();
}
// Implementation of IRepository<T>
}
Business Logic Tier (Runtime.csproj)
// IOC Container
public static class IOC {
public static readonly IWindsorContainer Container = new WindsorContainer();
static IOC() {
InstallAssembly("Presentation");
InstallAssembly("Runtime");
InstallAssembly("DataModel");
}
public static void InstallAssembly(string name) {
Container.Install(FromAssembly.Named(name));
}
}
// Also includes System.Configuration ConfigSections, HttpModules and Provider classes
// which are strongly tied to IRepository<>.
Presentation Layer (Mvc App) (Presentation.csproj)
protected void Application_Start() {
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
// Controller Factory instance makes initial reference to IOC class, causing
// the installers to run.
ControllerBuilder.Current.SetControllerFactory(new Runtime.Mvc.WindsorControllerFactory());
}
// Data-Driven Controller
public class DashboardController : SecureController {
private readonly IRepository<Entry> entries;
public DashboardController(IRepository<Entry> entries) {
// entries injected via ioc.
this.entries = entries;
}
[ChildActionOnly, HttpGet]
public ActionResult RecentEntries() {
var viewModel = new RecentEntriesViewModel( entries.Where( stuffHappens ) );
return PartialView(viewModel);
}
}
I feel like letting IRepository<> reach the presentation layer may be a violation of the pattern. Exposition of an IQueryable<> through IRepository<>.Where seems like a bad idea at the Presentation level. There's no way to moderate the use of IQueryable and could lead to brittle code. Inputs?