Design pattern for an ASP.NET project using Entity Framework
- by MPelletier
I'm building a website in ASP.NET (Web Forms) on top of an engine with business rules (which basically resides in a separate DLL), connected to a database mapped with Entity Framework (in a 3rd, separate project).
I designed the Engine first, which has an Entity Framework context, and then went on to work on the website, which presents various reports. I believe I made a terrible design mistake in that the website has its own context (which sounded normal at first).
I present this mockup of the engine and a report page's code behind:
Engine (in separate DLL):
public Engine
{
DatabaseEntities _engineContext;
public Engine()
{
// Connection string and procedure managed in DB layer
_engineContext = DatabaseEntities.Connect();
}
public ChangeSomeEntity(SomeEntity someEntity, int newValue)
{
//Suppose there's some validation too, non trivial stuff
SomeEntity.Value = newValue;
_engineContext.SaveChanges();
}
}
And report:
public partial class MyReport : Page
{
Engine _engine;
DatabaseEntities _webpageContext;
public MyReport()
{
_engine = new Engine();
_databaseContext = DatabaseEntities.Connect();
}
public void ChangeSomeEntityButton_Clicked(object sender, EventArgs e)
{
SomeEntity someEntity;
//Wrong way:
//Get the entity from the webpage context
someEntity = _webpageContext.SomeEntities.Single(s => s.Id == SomeEntityId);
//Send the entity from _webpageContext to the engine
_engine.ChangeSomeEntity(someEntity, SomeEntityNewValue); // <- oops, conflict of context
//Right(?) way:
//Get the entity from the engine context
someEntity = _engine.GetSomeEntity(SomeEntityId); //undefined above
//Send the entity from the engine's context to the engine
_engine.ChangeSomeEntity(someEntity, SomeEntityNewValue); // <- oops, conflict of context
}
}
Because the webpage has its own context, giving the Engine an entity from a different context will cause an error. I happen to know not to do that, to only give the Engine entities from its own context. But this is a very error-prone design. I see the error of my ways now. I just don't know the right path.
I'm considering:
Creating the connection in the Engine and passing it off to the webpage. Always instantiate an Engine, make its context accessible from a property, sharing it. Possible problems: other conflicts? Slow? Concurrency issues if I want to expand to AJAX?
Creating the connection from the webpage and passing it off to the Engine (I believe that's dependency injection?)
Only talking through ID's. Creates redundancy, not always practical, sounds archaic. But at the same time, I already recuperate stuff from the page as ID's that I need to fetch anyways.
What would be best compromise here for safety, ease-of-use and understanding, stability, and speed?