DbContext instance System.ObjectDisposedException in .Net Web app - c#

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

Somewhere in your code you have disposed your datacontext.
Try using a new instance of it.
ienumerable<object> categoryFromDb;
using (DataClasses1DataContext _db = new DataClasses1DataContext())
{
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();

I think that the problem is that you return categoryFromDb :
return View( categoryFromDb );
The categoryFromDb in fact is not a collection of elements, but it is simply a query definition:
categoryFromDb = _db.Categories1.Where(j => j.MaterialNumber == nameobj);
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 the ActionResult 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 or ToList, so that the query is executed and the results are loaded in the variable:
categoryFromDb = _db.Categories1.Where(j => j.MaterialNumber == nameobj).ToList();

Related

JWT: 'System.String' has three segments but is not in proper JWS format

I have an idToken string that is returned by google-sign-in use in mobile app with flutter and firebase:
Code in flutter
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/cupertino.dart';
import 'package:google_sign_in/google_sign_in.dart';
class Authentication {
static GoogleSignIn googleSignIn;
static Future<User> signInWithGoogle(BuildContext context) async {
FirebaseAuth auth = FirebaseAuth.instance;
User user;
googleSignIn = GoogleSignIn();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await auth.signInWithCredential(credential);
user = userCredential.user;
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
// handle the error here
} else if (e.code == 'invalid-credential') {
// handle the error here
}
} catch (e) {
// handle the error here
}
print("Credential token: ${credential.token}");
print("Credential provider id: ${credential.providerId}");
print("AccessToken: ${googleSignInAuthentication.accessToken}");
print("ID Token: ${googleSignInAuthentication.idToken}");
print("AccessToken.length: ${googleSignInAuthentication.accessToken.length}");
print("IdToken.length: ${googleSignInAuthentication.idToken.length}");
}
return user;
}
static Future signOut() async {
await googleSignIn.signOut();
FirebaseAuth.instance.signOut();
}
}
ID token is returned.
And I use this code to decode it:
public JwtPayload PayloadInfo(string idToken)
{
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
It works fine in the console app but with the .net 5 web API it fail with error:
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
I research that my idToken is not in JWS type... and I don't know how to solve this.
Weirdly, the function PayloadInfo works fine in C# console app but in the web API, it doesn't.
Controller
[HttpPost("login-google")]
[MapToApiVersion("1.0")]
public async Task<IActionResult> GoogleLoginAsync(
[FromBody] ExternalAuthModel model)
{
if (ModelState.IsValid)
{
var result = await
_userService.GoogleExternalLoginAsync(model);
if (result.IsSuccess)
{
return Ok(result);
}
return BadRequest(result);
}
return BadRequest("Somethings going wrong...");
}
ExternalAuthModel
public class ExternalAuthModel
{
public string Provider { get; set; }
public string IdToken { get; set; }
}
GoogleExternalLoginAsync function in my Service
public async Task<UserManagerResponse> GoogleExternalLoginAsync(ExternalAuthModel model)
{
var payload = _jwtHandler.PayloadInfo(model.IdToken);
if (payload is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var info = new UserLoginInfo(model.Provider, payload.Sub, model.Provider);
var user = await _userManager.FindByLoginAsync(info.LoginProvider, info.ProviderKey);
if (user is null)
{
user = await _userManager.FindByEmailAsync(payload["email"].ToString());
await _userManager.CreateAsync(user);
if (!await _roleManager.RoleExistsAsync(UserRoles.User))
await _roleManager.CreateAsync(new IdentityRole(UserRoles.User));
await _userManager.AddToRoleAsync(user, UserRoles.User);
await _userManager.AddLoginAsync(user, info);
}
else
{
await _userManager.AddLoginAsync(user, info);
}
if (user is null)
{
return new UserManagerResponse
{
Message = "Invalid google authentication.",
IsSuccess = false
};
}
var token = await _jwtHandler.GenerateToken(user);
return new UserManagerResponse
{
Message = token[0],
IsSuccess = true,
ExpireDate = DateTime.Parse(token[1])
};
}
PayloadInfo function
public JwtPayload PayloadInfo(string idToken)
{
// Exception when excute this line... it says my idToken is not in
// JWS compact format....
var jwtToken = new JwtSecurityToken(idToken);
JwtPayload payload = jwtToken.Payload;
return payload;
}
Log...
2021-07-04T16:10:30.3810628+07:00 [ERR] An unhandled exception has occurred while executing the request. (48a46595)
System.ArgumentException: IDX12739: JWT: 'System.String' has three segments but is not in proper JWS format.
at System.IdentityModel.Tokens.Jwt.JwtSecurityToken..ctor(String jwtEncodedString)
at FTask.AuthServices.Helpers.JwtHandler.PayloadInfo(String idToken) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Helpers\JwtHandler.cs:line 83
at FTask.AuthServices.Services.UserService.GoogleExternalLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.AuthServices\Services\UserService.cs:line 163
at FTask.Api.Controllers.AuthController.GoogleLoginAsync(ExternalAuthModel model) in D:\cn7\Project\hao\ftask\FTask.Api\Controllers\AuthController.cs:line 109
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()
--- End of stack trace from previous location ---
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Please test this:
public JwtPayload GetPayload()
{
var token = "<your token>";
var handler = new JwtSecurityTokenHandler();
var tokenData = handler.ReadJwtToken(token);
return tokenData.Payload;
}
i tested your token in .Net 5 Web API and got this result:

Many To Many Database with EF Core5 Error

Plaase help!!!: I created 2 entities and added DbSets to ApplicationDbContext.
public class ApplicationUser : IdentityUser
{
public string Adi { get; set; }
public ICollection<Firma> Firmalar {get; set;}
}
public class Firma
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<ApplicationUser> ApplicationUser { get; set; }
}
onPost Method I want to add List to ApplicationUser Table with relation. I can see ApplicationUserFirma table has automatically created
public async Task<IActionResult> OnPostAddFirmaToUser(UserFirmaVM vm, ServisHaritasi.DataService.Models.Firma firma)
{
var dbuser = await _userManager.FindByIdAsync(vm.ApplicationUser.Id);
var dbfirma = await _db.Firmalar.FirstOrDefaultAsync(m => m.Id == firma.Id);
if (dbuser != null && dbfirma != null)
{
dbuser.Firmalar.Add(dbfirma); **///I GET EXCEPTION HERE!!!!!!!!!!!!!!**
await _db.SaveChangesAsync();
return RedirectToPage("./Duzenle", new {id = dbuser.Id});
}
return Page();
}
enter image description here
I assure you there is no null for dbuser and dbfirma. they are coming normally on debug.
Plase help!!!
Stack trace is here:
NullReferenceException: Object reference not set to an instance of an object.
webUI.Pages.Users.DuzenleModel.OnPostAddFirmaToUser(UserFirmaVM vm, Firma firma) in Duzenle.cshtml.cs
+
dbuser.Firmalar.Add(dbfirma);
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Convert<T>(object taskAsObject)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory+GenericTaskHandlerMethod.Execute(object receiver, object[] arguments)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)
Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_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>g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, object state, bool isCompleted)
Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>g__Logged|17_1(ResourceInvoker invoker)
Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore.MigrationsEndPointMiddleware.Invoke(HttpContext context)
Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Try to use include Firma for ApplicationUser:
public async Task<IActionResult> OnPostAddFirmaToUser(UserFirmaVM vm, ServisHaritasi.DataService.Models.Firma firma)
{
var dbuser = await _db.Set<ApplicationUser>()
.Include(i=>i.Firmalar)
.Where(m => m.Id == vm.ApplicationUser.Id)
.FirstOrDefaultAsync();
var dbfirma = await _db.Firmalar.FirstOrDefaultAsync(m => m.Id == firma.Id);
if (dbuser != null && dbfirma != null)
{
if(dbuser.Firmalar==null) dbuser.Firmalar= new List<Firmalar>();
dbuser.Firmalar.Add(dbfirma);
await _db.SaveChangesAsync();
return RedirectToPage("./Duzenle", new {id = dbuser.Id});
}
return Page();
}
When you are fetching the user as -
var dbuser = await _userManager.FindByIdAsync(vm.ApplicationUser.Id);
the related Firmalar list is not included. So it remains null. Then You are trying to add to this null list -
dbuser.Firmalar.Add(dbfirma);
That's where the issue is.
Try to fetch the user including the Firmalar list, like -
var dbuser = await _db.ApplicationUser
.Include(p=> p.Firmalar)
.FirstOrDefaultAsync(p=> p.Id == vm.ApplicationUser.Id);
That should solve the issue.

Polymorphic model binding for generic type parameter

I'm sending a partial object along with a file.
var formData = new FormData();
formData.append('model', JSON.stringify({ ... }));
formData.append('file', file, file.name)
// send formData to backend
My controller method is using Delta<T> from OData.
[HttpPatch("{id}")]
public async Task<IActionResult> Patch(
[FromRoute] Guid id,
[ModelBinder(BinderType = typeof(FormDataJsonBinder))] Delta<AbstractModel> model,
IFormFile file = null
)
However I'm not sending Delta<AbstractModel> as AbstractModel is an abstract class. So I'm really sending Delta<DerivedModel> or Delta<AnotherDerivedModel> etc...
My problem is that ASP.NET keeps throwing saying that it cannot cast to Delta<DerivedModel>
System.InvalidCastException: Unable to cast object of type 'Microsoft.AspNet.OData.Delta`1[DerivedModel]' to type 'Microsoft.AspNet.OData.Delta`1[AbstractModel]'.
at lambda_method308(Closure , Object , Object[] )
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>g__Awaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResourceFilter>g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
Here's my FormDataJsonBinder
public class FormDataJsonBinder : IModelBinder
{
public async Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException(nameof(bindingContext));
// Fetch the value of the argument by name and set it to the model state
string fieldName = bindingContext.FieldName;
var valueProviderResult = bindingContext.ValueProvider.GetValue(fieldName);
if (valueProviderResult == ValueProviderResult.None) return Task.CompletedTask;
else bindingContext.ModelState.SetModelValue(fieldName, valueProviderResult);
// Do nothing if the value is null or empty
string value = valueProviderResult.FirstValue;
if (string.IsNullOrEmpty(value)) return Task.CompletedTask;
try
{
// Delta is a special case
if (bindingContext.ModelType.IsAssignableTo(typeof(Delta)))
{
var jsonObject = JObject.Parse(value);
// This extracts type T from Delta<T>
var innerModelType = bindingContext.ModelType.GenericTypeArguments.First();
if (jsonObject["#odata.type"] is not null)
{
var odataType = jsonObject["#odata.type"].Value<string>();
innerModelType = Type.GetType(odataType);
}
var innerModel = JsonConvert.DeserializeObject(value, innerModelType);
var deltaType = typeof(Delta<>).MakeGenericType(innerModelType);
var delta = Activator.CreateInstance(deltaType) as IDelta;
foreach (var property in jsonObject.Properties())
{
delta.TrySetPropertyValue(property.Name, innerModel.GetType().GetProperty(property.Name)?.GetValue(innerModel));
}
bindingContext.Result = ModelBindingResult.Success(delta);
}
else
{
// Deserialize the provided value and set the binding result
var result = JsonConvert.DeserializeObject(value, bindingContext.ModelType);
bindingContext.Result = ModelBindingResult.Success(result);
}
}
catch (JsonException)
{
bindingContext.Result = ModelBindingResult.Failed();
}
return Task.CompletedTask;
}
}
I also tried using a IModelBinderProvider as recommended here, but that also just throws "cannot cast to Delta<DerivedModel>"
The solution was to create the Delta object the right way.
var delta = Activator.CreateInstance(bindingContext.ModelType, innerModelType) as IDelta;

Async transaction Entity Framework 6.2

Good morning!
I have long running async transcation with fails with some different errors.
THere is method with run the transaction
public T PerformInTransaction<T>(Func<ITransaction> beginTransaction, Func<ITransaction, T> func)
{
try
{
AzureDbConfiguration.SuspendExecutionStrategy = true;
using (var transaction = beginTransaction())
{
return func(transaction);
}
}
finally
{
AzureDbConfiguration.SuspendExecutionStrategy = false;
}
}
The ITranscation interface is implemented as default of EF DbContextTransaction class as below:
public class Transaction : ITransaction
{
private readonly DbContextTransaction _transaction;
public Transaction(DbContextTransaction transaction)
{
_transaction = transaction;
}
public Task CommitAsync()
{
this.Commit();
return Task.CompletedTask;
}
.... more methods
}
I have preety long operation running in transcation where inside I have loop with another async methods and each method might call SaveChanges(). Snippet basically looks like
await _unitOfWork.PerformInTransaction(async transaction =>
{
foreach()
{
if(await Action())
_unitOfWork.SaveChanges()
else
transaction.Rollback()
}
transaction.Commit()
})
The errors I have
System.InvalidOperationException: Invalid attempt to call IsDBNull
when reader is closed. at
System.Data.SqlClient.SqlDataReader.CheckHeaderIsReady(Int32
columnIndex, Boolean permitAsync, String methodName) at
System.Data.SqlClient.SqlDataReader.IsDBNull(Int32 i) at
lambda_method(Closure , Shaper ) at
System.Data.Entity.Core.Common.Internal.Materialization.Coordinator1.ReadNextElement(Shaper
shaper) at
System.Data.Entity.Core.Common.Internal.Materialization.Shaper1.SimpleEnumerator.d__4.MoveNext()
or another
System.Data.Entity.Core.EntityException: The underlying provider
failed on Commit. ---> System.ArgumentNullException: Value cannot be
null. Parameter name: connection at
System.Data.Entity.Utilities.Check.NotNull[T](T value, String
parameterName) at
System.Data.Entity.Infrastructure.Interception.DbTransactionInterceptionContext.WithConnection(DbConnection
connection)
Do I do something wrong with async transcations? Is it related to some timouts ?
Thanks in advance

How to capture EF exception

I want to capture the error from entity framework.
So i have the below code
return await _context.SaveChangesAsync(cancellationToken);
if something goes wrong in the above code i want it to be captured as a warning in database, but as of now it is automatically saving in the database as error which has to be warning actually.
below is the error that i get
An exception occurred in the database while saving changes for context
type 'ValuationsReporting.Models.ValuationsReportingContext'.
System.InvalidOperationException: The property 'TemplateTypeId' on
entity type 'ValuationFundTemplate' has a temporary value. Either set
a permanent value explicitly or ensure that the database is configured
to generate values for this property. at
Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.Validate(ModificationCommand
modificationCommand) at
Microsoft.EntityFrameworkCore.Update.Internal.CommandBatchPreparer.BatchCommands(IReadOnlyList1
entries)+MoveNext() at
Microsoft.EntityFrameworkCore.Update.Internal.BatchExecutor.ExecuteAsync(DbContext
_, ValueTuple2 parameters, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4
operation, Func4 verifySucceeded, TState state, CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.Storage.ExecutionStrategy.ExecuteImplementationAsync[TState,TResult](Func4
operation, Func4 verifySucceeded, TState state, CancellationToken
cancellationToken) at
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(IReadOnlyList`1
entriesToSave, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.SaveChangesAsync(Boolean
acceptAllChangesOnSuccess, CancellationToken cancellationToken) at
Microsoft.EntityFrameworkCore.DbContext.SaveChangesAsync(Boolean
acceptAllChangesOnSuccess, CancellationToken cancellationToken)
System.InvalidOperationException
Microsoft.EntityFrameworkCore.Update
I tried using try catch but as soon as it goes to that line the error is logged in database.
Actual code :
try
{
foreach (var template in snapshotDto.SnapshopFundTemplateDtos)
{
if (template.FundId != null)
{
foreach (var fundId in template.FundId)
{
var tempTemplate = allFundTemplates.Where(x => x.ValuationId == valuation.Id && x.FundId == fundId && x.TemplateTypeId == template.TemplateTypeId).FirstOrDefault();
//var tempTemplate = await _valuationFundTemplateRepository.GetOne(valuation.Id, fundId, template.TemplateTypeId, true, cancellationToken);
if (tempTemplate == null)
{
tempTemplate = new ValuationFundTemplate();
tempTemplate.CreatedBy = _userRepository.claimsPrincipal.Identity.Name;
tempTemplate.CreatedOn = DateTime.Now.ToUniversalTime();
isTemplateUpdate = false;
}
//tempTemplate.IsDeleted = false;
//if (template.IsDeleted)
//{
// _valuationFundTemplateRepository.Delete(tempTemplate);
//}
//else
//{
//tempTemplate.IsDeleted = template.IsDeleted;
tempTemplate.IsDeleted = false;
tempTemplate.IsDefaultFundTemplate = template.IsDefault;
tempTemplate.FundId = fundId;
tempTemplate.ValuationId = valuation.Id;
tempTemplate.TemplateTypeId = 0;
tempTemplate.TemplateId = template.TemplateId;
tempTemplate.ModifiedBy = _userRepository.claimsPrincipal.Identity.Name;
tempTemplate.ModifiedOn = DateTime.Now.ToUniversalTime();
tempTemplates.Add(tempTemplate);
if (isTemplateUpdate)
{
_valuationFundTemplateRepository.Update(tempTemplate);
}
else
{
await _valuationFundTemplateRepository.Insert(tempTemplate, cancellationToken);
}
// }
await _valuationFundTemplateRepository.SaveAsync(cancellationToken);//here is where the error occurs which i dont want to capture in database.
if (!isTemplateUpdate)
valuation.ValuationFundTemplate.Add(tempTemplate);
}
}
}
}catch(Exception e)
{
var z = e.Message;
}
public virtual async Task<int> SaveAsync(CancellationToken cancellationToken = default(CancellationToken))
{
return await _context.SaveChangesAsync(cancellationToken);
}
Agreed with the #PrashantPimpale you can simply use try catch.
But for the advanced approach, I would suggest you can use a Global Error Handling Middleware.
Through which you can capture any error occurred in the whole dotnet API/Application.
Just and Elaboration below:
// Extension method used to add the middleware to the HTTP request pipeline.
public static class ErrorHandlingMiddlewareExtensions
{
public static IApplicationBuilder UseErrorHandlingMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
Then add app.UseErrorHandlingMiddleware(); in the Startup's Configure() method.
You have to first create a ErrorHandlingMiddleware class.
public class ErrorHandlingMiddleware
{
private readonly RequestDelegate _next;
public ErrorHandlingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
try
{
await _next(httpContext);
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
private static async Task HandleExceptionAsync(HttpContext context, Exception exception)
{
// Implement how you want to handle the error.
}
}
Following on from my comment on the other answer - I have found a solution to this.
There are two things not immediately clear here, so to clarify:
There are legitimate reasons for wanting to suppress some DB errors and treat them as warnings (for instance) e.g. custom triggers checking data integrity
This is NOTHING to do with capturing an exception coming from EF Core, EF Core is DIRECTLY emitting error log lines for DbUpdateExceptions AS WELL AS throwing that exception to be caught by the application
So the solution here is to configure EF Core to change its behaviour and log failures to save changes as warnings instead of errors (could suppress completely - but I'm playing safe). I haven't found actual documentation on this, but with some experimentation have found configuring your context like this works correctly:
protected override void OnConfiguring(DbContextOptionsBuilder builder)
{
base.OnConfiguring(builder);
builder
.ConfigureWarnings(x => x
.Log(
(CoreEventId.SaveChangesFailed, LogLevel.Warning)
)
);
}

Categories

Resources