I have a Asp.Net web app that used for validation, a scanner is connected to it through serial port and whenever a qr code is scanned, It gets the data and the page is refreshed and uses the new data gotten from the qr code. My problem now is that whenever I scan, and data is received in my controller function, which is shown below.
public void mySerialPort_Data(object sender, SerialDataReceivedEventArgs e)
{
try
{
string data = _serialPort.ReadExisting();
barcode = data.Split(";");
codeValue = barcode[0].Substring(barcode[0].IndexOf(":") +1);
SelectedPN(pn_No);
}
catch (IOException ex)
{
Console.WriteLine(ex);
}
}
I call the controller function of the current page in the function above SelectedPN() and this function I think is supposed to load and refresh the data I got from the qr code, but I keep getting an error.
Below is the SelectedPN() function that is called in the function above
public ActionResult SelectedPN(String nameobj)
{
pn_No= nameobj;
_serialPort.WriteTimeout = 500;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_Data);
if (!_serialPort.IsOpen)
{
try
{
_serialPort.Open();
}
catch (IOException ex)
{
Console.WriteLine(ex);
}
}
ViewBag.check9 = codeValue;
List <double> newList = new List<double>();
var num = 0;
var bill = 4;
var categoryFromDb = _db.Categories1.Where(j => j.MaterialNumber == nameobj);
foreach (var obj in categoryFromDb) {
newList.Add(obj.ComponentNumber);
}
num = newList.Count;
var duplicates = newList.GroupBy(x => x)
.SelectMany(g => g.Skip(1))
.Distinct()
.ToList();
ViewBag.check1 = check;
//testlist.Add(Convert.ToDouble(data1.X2));
ViewBag.check1 = check;
ViewBag.check2 = "background-color: #00FF00;";
ViewBag.check3 = 3;
ViewBag.check4 = num;
//ViewBag.check5 = '';
ViewBag.update = num;
changeValue = num;
ViewBag.check6 = testlist;
ViewBag.check7 = duplicates;
return View( categoryFromDb );
}
The error is that it says the instance of my dbContext has been disposed and therefore i cannot use it.
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: 'ApplicationDbContext'.'
What I have tried
I found online in a post that ServiceLiftime of DbContext is set to Scoped by default, and it disposes the instance once it is used and I have to change it to ServiceLifetime.Transient to be able to resuse the instance, but this did not work. I still got the same error again
Below is where I set the ServiceLiftime
builder.Services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(
builder.Configuration.GetConnectionString("DefaultConnection")
), ServiceLifetime.Transient);
I would appreciate any help on how to solve this problem.
EDIT
This is my complete controller
namespace WA4.Controllers
{
public class CategoryController : Controller
{
static SerialPort _serialPort = new SerialPort("COM3", 115200, Parity.None, 8, StopBits.One);
public IEnumerable<Category> categoryFromDb;
public CategoryController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
getPorts();
IEnumerable<Category> objCategoryList = _db.Categories1;
return View(objCategoryList);
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SelectedPN(String nameobj)
{
pn_No= nameobj;
_serialPort.WriteTimeout = 500;
_serialPort.DataReceived += new SerialDataReceivedEventHandler(mySerialPort_Data);
if (!_serialPort.IsOpen)
{
try
{
_serialPort.Open();
}
catch (IOException ex)
{
Console.WriteLine(ex);
}
}
ViewBag.check9 = codeValue;
List <double> newList = new List<double>();
var num = 0;
var bill = 4;
categoryFromDb = _db.Categories1.Where(j => j.MaterialNumber == nameobj);
foreach (var obj in categoryFromDb) {
newList.Add(obj.ComponentNumber);
}
num = newList.Count;
var duplicates = newList.GroupBy(x => x)
.SelectMany(g => g.Skip(1))
.Distinct()
.ToList();
return View( categoryFromDb );
}
And below is my DbContext.cs content
using WA4.Models;
using Microsoft.EntityFrameworkCore;
namespace WA4.Data
{
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext()
{
}
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<Category> Categories1 { get; set; }
}
}
I tried using the solution @Walsharoo suggested but I got an error instead
using (ApplicationDbContext _db = new() )
{
categoryFromDb = _db.Categories1.Where(j => j.MaterialNumber == nameobj);
foreach (var obj in categoryFromDb) {
newList.Add(obj.ComponentNumber);
}
num = newList.Count;
var duplicates = newList.GroupBy(x => x)
.SelectMany(g => g.Skip(1))
.Distinct()
.ToList();
Error
InvalidOperationException: No database provider has been configured for this DbContext. A provider can be configured by overriding the 'DbContext.OnConfiguring' method or by using 'AddDbContext' on the application service provider. If 'AddDbContext' is used, then also ensure that your DbContext type accepts a DbContextOptions<TContext> object in its constructor and passes it to the base constructor for DbContext.
Microsoft.EntityFrameworkCore.Internal.DbContextServices.Initialize(IServiceProvider scopedProvider, DbContextOptions contextOptions, DbContext context)
Microsoft.EntityFrameworkCore.DbContext.get_ContextServices()
Microsoft.EntityFrameworkCore.DbContext.get_Model()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityType()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.get_EntityQueryable()
Microsoft.EntityFrameworkCore.Internal.InternalDbSet<TEntity>.System.Linq.IQueryable.get_Provider()
System.Linq.Queryable.Where<TSource>(IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate)
WA4.Controllers.CategoryController.SelectedPN(string nameobj)
lambda_method86(Closure , object , object[] )
Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+SyncActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|25_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeFilterPipelineAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
EDIT
This is the stack trace after following the suggestion of @Roberto Ferraris
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.DbContext.CheckDisposed() Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.DbContext.ContextServices.get() Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.DbContext.ChangeTracker.get() Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.CompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(System.Linq.Expressions.Expression query, bool async) Unknown
Microsoft.EntityFrameworkCore.Relational.dll!Microsoft.EntityFrameworkCore.Query.RelationalCompiledQueryCacheKeyGenerator.GenerateCacheKeyCore(System.Linq.Expressions.Expression query, bool async) Unknown
Microsoft.EntityFrameworkCore.SqlServer.dll!Microsoft.EntityFrameworkCore.SqlServer.Query.Internal.SqlServerCompiledQueryCacheKeyGenerator.GenerateCacheKey(System.Linq.Expressions.Expression query, bool async) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.Internal.QueryCompiler.Execute<System.Collections.Generic.IEnumerable<WA4.Models.Category>>(System.Linq.Expressions.Expression query) Unknown
Microsoft.EntityFrameworkCore.dll!Microsoft.EntityFrameworkCore.Query.Internal.EntityQueryable<WA4.Models.Category>.GetEnumerator() Unknown
System.Private.CoreLib.dll!System.Collections.Generic.List<WA4.Models.Category>.List(System.Collections.Generic.IEnumerable<WA4.Models.Category> collection) Unknown
System.Linq.dll!System.Linq.Enumerable.ToList<WA4.Models.Category>(System.Collections.Generic.IEnumerable<WA4.Models.Category> source) Unknown
> WA4.dll!WA4.Controllers.CategoryController.SelectedPN(string nameobj) Line 87 C#
WA4.dll!WA4.Controllers.CategoryController.mySerialPort_Data(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) Line 315 C#
System.IO.Ports.dll!System.IO.Ports.SerialPort.CatchReceivedEvents(object src, System.IO.Ports.SerialDataReceivedEventArgs e) Unknown
System.IO.Ports.dll!System.IO.Ports.SerialStream.EventLoopRunner.CallReceiveEvents(object state) Unknown
System.Private.CoreLib.dll!System.Threading.QueueUserWorkItemCallback..cctor.AnonymousMethod__6_0(System.Threading.QueueUserWorkItemCallback quwi) Unknown
System.Private.CoreLib.dll!System.Threading.ExecutionContext.RunForThreadPoolUnsafe<System.__Canon>(System.Threading.ExecutionContext executionContext, System.Action<System.__Canon> callback, System.__Canon state) Unknown
System.Private.CoreLib.dll!System.Threading.QueueUserWorkItemCallback.Execute() Unknown
System.Private.CoreLib.dll!System.Threading.ThreadPoolWorkQueue.Dispatch() Unknown
System.Private.CoreLib.dll!System.Threading.PortableThreadPool.WorkerThread.WorkerThreadStart() Unknown
System.Private.CoreLib.dll!System.Threading.Thread.StartCallback() Unknown
2
Answers
Somewhere in your code you have disposed your datacontext.
Try using a new instance of it.
I think that the problem is that you return
categoryFromDb
:The
categoryFromDb
in fact is not a collection of elements, but it is simply a query definition:Linq use a deferred execution (see Introduction to LINQ Queries (C#) | Microsoft Learn) so each time you use this variable a query is execute against the database.
Since you return the query with
View(categoryFromDb)
it will be resolved when theActionResult
is executed (and not at the return statement) and tipically at this time de db context was already disposed.I suggest to change your code to include something like
ToArray
orToList
, so that the query is executed and the results are loaded in the variable: