0

ASP.NET MVC 5 Project.

I know that the best practice of using EF context object as the following

using(var context = new ContextDB())
{
}

But I am working with a large existing project which not used this practice.
the project using the following pattern

public abstract class BaseService
{
    private static ContextDB _data { get; set; }
    public static ContextDB Data
    {
        get
        {
            if (_data== null)
                _data= new ContextDB();

            return _data;
        }
    }
}

Actually, because of this pattern, I am receiving this exception (sometimes, not always)

So to solve this I have to change all the code which is using the shared Data property and replace it with the new instance of ContextDB as I mentioned in the beginning of the question.

The problem that this is a very large modification, and I will not be allowed to do that modification.

The Question, can I solve this problem without changing a ton of code, In another word, can I solve the problems with modifications done only inside the BaseService class, for example, Is there any event which I could handle to know if any query is executed and then dispose of the ContextDB

here is the pseudo-code of the idea in my mind

public abstract class BaseService
{

    public static ContextDB Data
    {
        get
        {
            ContextDB _data= new ContextDB();
            _data.SqlQueryExecuted += () => { this._data.dispose(); }
            return _data;
        }
    }
}  

NOTE: the SaveChanged event is not suitable, because not all of the query are updating or inserting.

Igor
  • 60,821
  • 10
  • 100
  • 175
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131
  • You are not allowed to modify code at the right place but you are allowed to modify the class which is responsible for the whole project? – Tim Schmelter Oct 22 '18 at 14:09
  • So you'll replace one exception with another if some code happens to use a context twice without re-accessing this property to "refresh" it between uses? – Damien_The_Unbeliever Oct 22 '18 at 14:09
  • @TimSchmelter I discussed the problem with my boss, and he said that it is prefered to solve the problem in the base class. I know this is not ideal, and I know the ideal place to solve the problem is to modify every method (one by one), but I just wonder if this is possible it could really be easier. – Hakan Fıstık Oct 22 '18 at 14:11
  • You never mention what type of app this is (this makes a difference in lifetime scope) or the type of exceptions that are thrown. The solution would be determined by these answers. Also I don't see a way around having to change all the location's where the code is used. – Igor Oct 22 '18 at 14:11
  • Even if that would work automagically, what if someone wants to execute two queries with that context? You would silently break that code from here. – Tim Schmelter Oct 22 '18 at 14:11
  • @Igor I updated the question, see the top of the question please. – Hakan Fıstık Oct 22 '18 at 14:13
  • A static context with asp.net? Yeah, you are going to run into lot's of race conditions! You will have to change each location' there is no easy way around it. This is a design bug that can't be mitigated with a small change to the base class. You have to find all the points of use and change them. My preference would be to go a step further and introduce a DI framework (like Autofac) to handle the lifetime scope of the `DbContext` (as well as other instances). Or you could constrain the change to just the DbContext creation/disposing at all the points where it is used. – Igor Oct 22 '18 at 14:14
  • @TimSchmelter I think there is no problem, It is accepted for us to execute each query in new instance. we will not need to execute two query with the same instance. – Hakan Fıstık Oct 22 '18 at 14:14
  • @Igor yes exactlly, static context with asp.net – Hakan Fıstık Oct 22 '18 at 14:15
  • I would also go ahead and mark that property as `Obsolete` with warning (so the code still compiles/runs) right away so no new changes are introduced that have to be corrected later. – Igor Oct 22 '18 at 14:21
  • @HakamFostok: maybe you don't need, but nothing prevents your colleagues from using this service in a way that the returned `ContextDB` will be used for multiple queries. Apart from the fact that the user will see an exception at runtime. – Tim Schmelter Oct 22 '18 at 14:21
  • @TimSchmelter, I think now I understand you. You mean that someone could hold this property in a local variable in the inherited class and use it twice. In that case the first query will be executed by the second with throw exception because the Context instance is disposed of. You are right. I did not think of this problem. – Hakan Fıstık Oct 22 '18 at 14:24
  • @Igor marking the property as `obsolete` is good idea, thank you – Hakan Fıstık Oct 22 '18 at 14:24

1 Answers1

0

I may use following solution.

  1. In Global.asax Begin Request : Create Instance of your dbContext. Store it in HttpContext.Current.Items.

    End Request : Grab the context and close / dispose connection.

  2. Another better solution is to use DI. Dependency Injection and limit the scope of your instance. There are many way Like Singleton, PerRequest etc.

dotnetstep
  • 17,065
  • 5
  • 54
  • 72
  • Thank you for the suggestion, but both solutions will not work in my case. The first one will not work because I am using Layered Architecture, the second solution will be a very big modification and in that case, we will prefer to modify every method by hand. – Hakan Fıstık Oct 22 '18 at 14:29