At present, I have very successfully architected my applications as follows:
-
Data model (Entity Framework 4.1)
-
Validation using Enterprise Library 5.0 Validation Application Block.
-
Object Context managed by a reusable class library.
So, the UI is pretty light on code but I know I’m not completely there yet.
If I wanted to have my projects set up so I could implement a Web Forms, MVC, WPF Desktop or Silverlight – even Windows Phone 7 – application, what additional steps might I need to take?
Here’s some code, deliberately simplified, to illustrate my current state of play (I’ve omitted Code Contracts and the class libraries):
(Currently EF4 Model First and ASP .Net Web Forms)
Partial class for auto-generated entity
namespace MyNamespace.Database
{
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
[HasSelfValidation]
public partial class MyEntity : IMyEntity
{
[SelfValidation]
public void Validate(ValidationResults validationResults)
{
// Custom validation can go here, just add a new ValidationResult
// to validationResults if the rule fails.
if (validationResults != null)
{
validationResults.AddAllResults(
ValidationFactory
.CreateValidator<IMyEntity>()
.Validate(this));
}
}
}
}
Validation
namespace MyNamespace.Database
{
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.Contracts;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators;
[ContractClass(typeof(MyEntityContract))]
public interface IMyEntity
{
int Id
{
get;
set;
}
[Required]
[NotNullValidator]
[StringLengthValidator(0, RangeBoundaryType.Ignore, 50,
RangeBoundaryType.Inclusive,
MessageTemplate = "MyEntity Name must be 50 characters or less.")]
string Name
{
get;
set;
}
void Validate(ValidationResults validationResults);
}
}
Facade for data access
namespace MyNamespace.Facade
{
using System.Collections.Generic;
using System.Linq;
using Common.ObjectContextManagement;
using Database;
public sealed class MyEntityFacade : FacadeBase<MyEntities, MyEntity>
{
public IEnumerable<MyEntity> GetAll()
{
return this.ObjectContext.MyEntitys
.Distinct()
.ToList();
}
}
}
Web App UI
using (new UnitOfWorkScope(false))
{
this.MyEntityList.DataSource = new MyEntityFacade().GetAll();
this.MyEntityList.DataBind();
}
// Or...
using (var scope = new UnitOfWorkScope(false))
{
var myEntityFacade = new MyEntityFacade();
var myEntity = new MyEntity();
PopulateEntity(myEntity);
// Validation errors are automatically presented
// to the user from the Validate method
if (Validate(myEntity))
{
try
{
myEntityFacade.Add(myEntity);
scope.SaveAllChanges();
}
catch (Exception exception)
{
Logging.Write("Error", LoggingLevel.Error, exception.Message);
}
}
}
How close am I?
The easiest way to expose your middle/backend so that a variety of clients can hook up is to wrap it all in one or more web services. In your example you can consider either exposing MyEntityFacade as a WCF service, or you can build an entirely new tier that passes back and forth between your client(s) and the facade.
If you stick to POCO objects and SOAP, you can probably factor in connectivity from java, javascript, python, etc. in addition to your listed clients.