locked
Instantiate DBContext From Class Files? RRS feed

  • Question

  • User2086073682 posted

    I have a large WebForms application I am trying to convert to .Net Core Razor Pages. I have many complex LINQ-Based queries which are placed in class files to keep things organized. In these class files, I have a database context constructor which I call like this:

    public static List<Core.DB.RecordsMgmt_PurgeCandidate> GetAllPurgeCandidates() {

      using (ECSToolsDBDataContext ECSdb = new ECSToolsDBDataContext()) {

        return ECSdb.GetTable<RecordsMgmt_PurgeCandidate>().ToList(); }

    }

    I need an equivalent of this in Razor Pages. I have scaffolded the database into the solution. I have tried everything under the sun and cannot make an equivalency. It does work if I use the override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) but this keeps the connection string hard-coded in compiled code. I have the dbcontext working using dependency injection, which appears to use the PageModel constructor to instantiate an injected dbcontext. This works, but only in the page. I can pass the instantiated dbcontext to the class files but this requires modifying every query and seems like a kludge. I have also tried adding a Controller to instantiate the dbcontext (which should theoretically be possible) but adding a controller and instantiating it like pagemodel does, but it instantiates a null dbcontext. I have also tried creating an interface to instantiate the dbcontext which theoretically ALL the queries could inherit, but also cannot make this concept work. Not sure where to turn.

    Wednesday, August 5, 2020 2:05 PM

All replies

  • User-474980206 posted

    Asp.net core abstracted configuration, so that the implementation would be in startup, and the handler would be injected. This is not compatible with static classes. You can build a static configuration handler that you initialize in startup. The other option is a static configuration variable that is set at startup.

    But I’d probably redesign to be static extension methods of an injected context.

      public static List<Core.DB.RecordsMgmt_PurgeCandidate> GetAllPurgeCandidates(this ECSToolsDBDataContext dB)

    then in page use injected context

      var list = db.GetAllPurgeCanidates();

     

    Wednesday, August 5, 2020 2:40 PM
  • User2086073682 posted

    Appreciate your suggestion. However I don't quite get it.

    I modified GetAllPurgeCandidates as you suggested and get no errors, but trying to call it with my injected dbcontext from my Page says it doesn't contain a definition for it. On the Page, the instantiated injected context is _ECSdb and this is coming from

    public partial class ECSToolsDBDataContext : DbContext

    If I place it into the ECSToolsDBDataContext class that inherits DbContext, I can't get a syntax that's acceptable, but also this is the file where all the virtual DbSets are and placing all the query code in here eliminates being able to have the various different class files that allow me to organize all the queries nicely. Maybe there's something I'm not understanding.

    Wednesday, August 5, 2020 8:48 PM
  • User1120430333 posted

    Using static  is not an optimal programming choice, becuase it produces static cling, tight coupling and it also leads to not doing clean coding.

    https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/may/asp-net-writing-clean-code-in-asp-net-core-with-dependency-injection

    https://objcsharp.wordpress.com/2013/07/08/why-static-code-is-bad/

    Here is a Core 3.0 Razor solution using Layered Architecture that's implementing SoC and using DTO and DAO patterns. The EF model was scaffolded in the Model folder in the DAL with DI being used in all layers.

    https://en.wikipedia.org/wiki/Separation_of_concerns

    https://www.codeproject.com/Articles/1050468/Data-Transfer-Object-Design-Pattern-in-Csharp

    https://javarevisited.blogspot.com/2013/01/data-access-object-dao-design-pattern-java-tutorial-example.html

    https://docs.microsoft.com/en-us/previous-versions/msp-n-p/ee658117(v=pandp.10)

    https://github.com/darnold924/PubCompanyCore3.x

    Hopefully, the code may help you.

    Wednesday, August 5, 2020 9:24 PM
  • User475983607 posted

    ASP.NET Core uses a service pattern to organize code.  Below is a general pattern.  The AdventureWordDb is the backing store.

    Service:  The Dbcontext is injected into the concrete service.

        public interface IPersonService
        {
            Person GetPersonById(int id);
        }
    
        public class PersonService : IPersonService
        {
            private readonly AdventureWorks2016Context db;
            public PersonService(AdventureWorks2016Context Db)
            {
                db = Db;
            }
    
            public Person GetPersonById(int id)
            {
                return db.Person.FirstOrDefault(p => p.BusinessEntityId == id);
            }
        }

    Register the service with DI

            public void ConfigureServices(IServiceCollection services)
            {
                services.AddControllersWithViews();
    
                services.AddDbContext<AdventureWorks2016Context>(options => 
                    options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
    
                services.AddSingleton<ICacheManager, CacheManager>();
                services.AddScoped<IPersonService, PersonService>();
            }

    Inject the service in a controller.  Constructor injection works the same in Razor Pages.

        public class PersonController : Controller
        {
            private readonly IPersonService service;
            public PersonController(IPersonService Service)
            {
                service = Service;
            }
            public IActionResult Index(int? id)
            {
                Person person = service.GetPersonById(id.GetValueOrDefault());
                return View(person);
            }
        }

    Wednesday, August 5, 2020 9:27 PM
  • User-474980206 posted

    DA924

    Using static  is not an optimal programming choice, becuase it produces static cling, tight coupling and it also leads to not doing clean coding.

    static methods are generally good. static data is suspect. your static method should have all data passed to them and be pure when possible. this is the foundation of functional programming and with C# linq features and lambda expressions (which are static) functional programming is easier than ever.

    also I hope we all know inheritance is bad (at least more than 1 level), that why we use interfaces. if you like the object.method syntax, then use extension methods to interfaces. a much better approach than class methods. 

    the OP original design had two issues. access to global setting, which should have been the a factory, and directly creating DbContext in method call without a factory. 

    using a global settings factory may be a good compromise over injecting the settings object.

    injecting the dbcontext would avoid the settings factory as DI could be used, and the dbcontext methods could easily be converted to extension methods. 

     

     

    Wednesday, August 5, 2020 9:58 PM
  • User1120430333 posted

    static methods are generally good. static data is suspect. your static method should be pure (all data passed to them). this is the foundation of functional programming and with C# linq features and lambda expressions (which are static) functional programming is easier than ever.

    Well, if one does unit testing,  then static methods do not lend towards code coverage and the ability to mock out the static method, making the static method tightly coupled to any code using it. You can't mock out Linq either or unit test it. It comes back to the business needs, and most software development is trying to solve business requirements in a business domain. And unit testing in Domain Driven Design is critical in today's  software development environment from a business standpoint..  

    also I hope we all know inheritance is bad (at least more than 1 level), that why we use interfaces. if you like the object.method syntax, then use extension methods to interfaces. a much better approach than class methods. 

    I never seen extension methods being used in unit testing and code coverage in Domain Driven Design. I have seen lots of classes that implement an interface being used in unit testing.

    Sure, one can have different views on things. My view is always in a business domain view, unit testing and code coverage. I have seen and used some of the Gof4 patterns in business needs, but they are used in solutions that were one off and on the bleeding edge from solutions that addressed normal business needs such as banking, purchase orders, payroll, general ledger. etc. and etc. where the well know design patterns and architectural styles are used in software development for business.

    he OP original design had two issues. access to global setting, which should have been the a factory, and directly creating DbContext in method call without a factory. 

    using a global settings factory may be a good compromise over injecting the settings object.

    injecting the dbcontext would avoid the settings factory as DI could be used, and the dbcontext methods could easily be converted to extension methods. 

    I believe you.

    Wednesday, August 5, 2020 10:53 PM
  • User-474980206 posted

    A large part of the .net core code and all of linq is extensions methods and they all have unit tests. Generally static methods are easier to unit test, because you don’t have to mock methods, you just pass the test data.

    you really should code to limit the amount of mocking required, thats just code smell.

    in modern programming, traits or extension method on interfaces/protocols is preferred to class methods and inheritance if the language supports this.

    Thursday, August 6, 2020 2:41 PM
  • User1120430333 posted

    A large part of the .net core code and all of linq is extensions methods and they all have unit tests. Generally static methods are easier to unit test, because you don’t have to mock methods, you just pass the test data.

    Static methods are almost non existence in enterprise level solutions I have worked on in Windows desktop and ASP.NET Web solutions where the developer made static methods or classes. Those kind of methods/classes have limited capabilities/requirements - mainly utility functionality.  However, those kind of methods/classes  do run in unit test, because the developer has no other choice but to allow the static code  to be executed in order to unit test the method the unit test is actually being done against.

    you really should code to limit the amount of mocking required, thats just code smell.

    I have to disagree with this, becuase of the arrange,  act and assert pattern  used in unit testing where mocked data is sent into a method due to the arrange, the mocked method acts upon the mocked data and the assert is verified on mocked data returned from the actual method being tested.  And several methods can be involved in a single  method that is being unit tested that must be mocked out with mocked data used and accounted for during the unit test of the actual method being unit tested.

    in modern programming, traits or extension method on interfaces/protocols is preferred to class methods and inheritance if the language supports this.

    It may be viable in some situations but not all situations.

    Thursday, August 6, 2020 3:56 PM
  • User-474980206 posted

    we have taken this thread off topic.

    mocking (test) data for unit tests is fine, mocking methods, which is mostly required for external calls (database, network, i/o) should be limited. If you have a lot of mocking, these calls are probably nested too deep in the call hierarchy. also the use of DI allows fakes rather mocks which can also make unit test easier to write.

    if you switch to functional programing, then you only have static methods and composition instead of inheritance. there is no issue unit testing functional programs. its typically easier than testing class instances.

    extension methods (which are static) are for writing common extension methods for an interface.  the advantage of interface extensions, is they only need to be written once. using extension methods reduces the number of methods an interface must implement. as you should always prefer use of an interface instead of a class type this greatly simiplfies building interfaces.

    Thursday, August 6, 2020 8:03 PM
  • User1120430333 posted

    I'll just say that we have taken two different paths on unit testing and the involvement of static methods.

    Friday, August 7, 2020 9:26 PM