Base solution for your next web application
Open Closed

Use DBContext instead of Repository #12256


User avatar
0
[email protected] created

I purchased ASP NETZERO just two weeks ago. My solution is ASP .Net Core & JavaScript and my target framework is .NET 8. I am migrating my old solution, which was created in ABP. However, all my entities do not inherit the Entity base class, hence I cannot use ABP repositories. So I want to use my DbContext instead of the Repository pattern. I applied the workaround suggested here #6984

    public class EstProductSectionAppService : ABMAppServiceBase, IEstProductSectionAppService
    {
        private readonly IDbContextProvider<ABMDbContext> _context;
        public EstProductSectionAppService(IDbContextProvider<ABMDbContext> context)
        {
            _context = context;
        }

        public IEnumerable<EstProductSectionDto> EstProductSections_Read(bool onlyActive = false)
        {
            var estproductsections = _context.GetDbContext().EstProductSections.Select(c => new EstProductSectionDto
            {
                Id = c.Id,
                SectionName = c.SectionName,
                IsDefault = c.IsDefault,
                IsActive = c.IsActive,
                CreationTime = c.CreationTime,
                CreatorUserId = c.CreatorUserId
            }).AsEnumerable();

            if (onlyActive)
                estproductsections = estproductsections.Where(x => (bool)x.IsActive);

            return estproductsections;
        }
    }

But still, it returns the following error:

System.ObjectDisposedException: Cannot access a disposed context instance. A common cause of this error is disposing a context 
instance that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. 
This may occur if you are calling 'Dispose' on the context instance, or wrapping it in a using statement. 
If you are using dependency injection, you should let the dependency injection container take care of disposing context instances.
Object name: 'ABMDbContext'.
   at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
   at Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
   at Microsoft.EntityFrameworkCore.DbContext.get_InternalServiceProvider()
   at Microsoft.EntityFrameworkCore.DbContext.get_ChangeTracker()
   at Microsoft.EntityFrameworkCore.Query.CompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.RelationalCompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async)
   at Abp.EntityFrameworkCore.AbpCompiledQueryCacheKeyGenerator.GenerateCacheKey(Expression query, Boolean async)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute[TResult](Expression query)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryProvider.Execute[TResult](Expression expression)
   at Abp.EntityFrameworkCore.AbpEntityQueryProvider.Execute[TResult](Expression expression)
   at Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable`1.System.Collections.IEnumerable.GetEnumerator()
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Serialize(JsonWriter jsonWriter, Object value)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Formatters.NewtonsoftJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.&lt;InvokeNextResultFilterAsync&gt;g__Awaited|30_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.&lt;InvokeNextResourceFilter&gt;g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.&lt;InvokeFilterPipelineAsync&gt;g__Awaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.&lt;InvokeAsync&gt;g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.&lt;InvokeAsync&gt;g__Logged|17_1(ResourceInvoker invoker)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.&lt;Invoke&gt;g__AwaitRequestTask|7_0(Endpoint endpoint, Task requestTask, ILogger logger)
   at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
   at Abp.AspNetZeroCore.Web.Authentication.JwtBearer.JwtTokenMiddleware.&lt;&gt;c__DisplayClass0_0.L4EGlrIeXkvSNw1rxp9.MoveNext()
--- End of stack trace from previous location ---
   at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

The request is initiated by Kendo Grid (Telerik Kendo UI for ASP.NET Core) How can this be solved? It would be appreciated if there is an option to use the dbContext without using the extra things like IDbContextProvider.

This is already posted in GitHub too (#5487).


5 Answer(s)
  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi

    You can use IDbContextProvider instead of directly injecting the YourDbContext. This allows ABP to manage the lifecycle of the DB context for you. Here's an example:

    public class EstProductSectionAppService : ABMAppServiceBase, IEstProductSectionAppService
    {
        private readonly IDbContextProvider< YourDbContext > _dbContextProvider;
    
        public EstProductSectionAppService(IDbContextProvider< YourDbContext > dbContextProvider)
        {
            _dbContextProvider = dbContextProvider;
        }
    
        public IEnumerable EstProductSections_Read(bool onlyActive = false)
        {
            var estproductsections =_dbContextProvider.GetDbContext().EstProductSections.Select(c => new EstProductSectionDto
            {
                Id = c.Id,
                SectionName = c.SectionName,
                IsDefault = c.IsDefault,
                IsActive = c.IsActive,
                CreationTime = c.CreationTime,
                CreatorUserId = c.CreatorUserId
            }).AsEnumerable();
    
            if (onlyActive)
                estproductsections = estproductsections.Where(x => (bool)x.IsActive);
    
            return estproductsections;
        }
    }
    

    If you are experiencing a scope problem here, it would be healthier to create an intermediate class, inherit from the YourProjectNameRepositoryBase class, and then pass it to the IDbContextProvider< YourDbContext > base class. Using the YourProjectNameRepositoryBase class will make your basic operations easier.

  • User Avatar
    0
    [email protected] created

    Yeah.. but it still will not work if the controller action and appservice method have the same name. How can we set a global route to include the area name in the URL.Action() call without affecting the other navigations? Because the call initiates from the Kendo Grid. As we are migrating a large project to NetZero, changing the URL in each grid is not practical. This will be a typical call from the grid. .DataSource(dataSource => dataSource .Ajax() .ServerOperation(false) .Model(model => { model.Id(p => p.Id); model.Field(s => s.CreationTime).Editable(false); }) .Read(read => read.Action("EstProductSections_Read", "EstProductSection")) .Create(create => create.Action("EstProductSections_Create", "EstProductSection")) .Update(update => update.Action("EstProductSections_Update", "EstProductSection")) .Destroy(destroy => destroy.Action("EstProductSections_Destroy", "EstProductSection")) .Events(events => events.Error("error_handler").RequestEnd("onRequestEnd")) )

    <br>

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    After thinking on this, we don't suggest using for example Action("EstProductSections_Create", "EstProductSection") without area attribute. We suggest using find/replace to add area to all these usages in cshtml files.

    Changing the default behaviour might cause unexpected and hard to find problems.

  • User Avatar
    0
    [email protected] created

    Please update the status in the thread #5487.

  • User Avatar
    0
    oguzhanagir created
    Support Team

    Hi

    You can find the answer to your problem here.