Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

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?

share|improve this question
    
I see this question which is very similar, but not the same: programmers.stackexchange.com/questions/163239/… –  MPelletier Nov 6 '13 at 20:51

2 Answers 2

up vote 1 down vote accepted

I don't think you are a million miles away from where you need to be.

What you need to do really depends on the level of abstraction that you need and what you foresee the future of this application to be.

You definitely do not want to be using multiple contexts in a single http request. That will cause you a lot of pain.

As a bare minimum I would alter your Engine to have the context dependency injected in (through the constructor or setter). That will allow you to isolate the engine for testing purposes by injecting in a mocked context.

I would then consider creating a BasePage class that new ups an Engine Instance in the constructor (passing in a new Context). Each subsequent page would then inherit from the BasePage and would therefore have an Engine instance by default.

I would then work on the Engine class to provide all the functionality that your pages require (possibly sub-classing if it starts to get a bit monolithic). You then make sure that all interaction between the UI and the underlying database is channelled through the Engine. This way you could extend the Engine as required say for instance Engine.Ajax.Get... or something along those lines.

Like I say the level of abstraction you require may reveal other design considerations that you will need to make. You may wish to implement a repository and unit of work pattern on top of the context (technically an EF context already gives you this but if you are not sure about sticking with EF or know that you will need to introduce alternative data access options then you will need to consider it).

If you are injecting dependencies and those dependencies are 'volatile' then you may look to use an Inversion of Control Container such as AutoFac or Windsor.

share|improve this answer

I would guess you have a reason for using WebForms rather than MVC but my first tip would be this: If you possibly can, use ASP.Net MVC.

Right, Got that off my chest, lets continue.

You are right to suspect your architecture, having your entity store and then a second way of directly accessing your database when using Entity Framework is a big no-no. The simple rule to consider is this: Only one way to and from the database.

Even if you're stuck with a tired technology like WebForms, you can still take a useful page out of the MVC book by using the MVC architecture. You're half way there with your Engine which sounds like it is doing most of the work of the Model layer. In fact it sounds to me like you want to go a little further and use a ViewModel type approach - a ViewModel behaves like a Model, but has extra things that make it easier to work with from the front end, so it effectively behaves as a DTO, but if there are any properties you don't want to be able to write on the front end or other view related logic it goes in the ViewModel class.

Then you make sure your entity layer can take a ViewModel object ( or probably you create an interface for your entities so if you had a BookRecord object you would create an IBookRecord interface that the BookRecord entity would implement and the BookRecordViewModel would also implement. If possible it is always nicer to pass around interfaces and it really facilitates DI, mocking and all that good stuff that helps build resilience in general.

The only real difference this makes is that you will have to handle logic to manage updates in your engine - when you push down a BookRecordViewModel from the interface you will need to check whether it has an Id field set and if it does query and update, if not add it as a new record. You may well have that all implemented already in your Engine project, in which case this should present no problem at all.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.