ASP.NET Boilerplate: ObjectDisposedException in EventHandler - aspnetboilerplate

I use ABP 5.1.0
.Net Core,
I have my class
ItemAsyncEventBaseHandler : IAsyncEventHandler<TEvent>, ITransientDependency
where TEvent : EventData {…}
Then i have class:
CustomHandler: ItemAsyncEventBaseHandler<EventData>
{
public CustomHandler(
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager)
{
_unitOfWorkManager = unitOfWorkManager;
_settingManager = settingManager;
}
}
public override async Task HandleInternallyAsync(ItemUpdatedEvent eventData)
{
await _settingManager.ChangeSettingForApplicationAsync("key", value.ToString());
}
At first glance, this works, but if I run the handler on two different items in quick succession, I get an error:
(On some machines it is enough to run the event on two items, on others it is necessary to run the event on the other two items in order for the same error to occur.)
System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context 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, or wrapping the context 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: 'MyDbContext'.
at Microsoft.EntityFrameworkCore.DbContext.CheckDisposed()
at Microsoft.EntityFrameworkCore.DbContext.get_DbContextDependencies()
at Microsoft.EntityFrameworkCore.DbContext.Set[TEntity]()
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.GetQueryable()
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.GetAllIncluding(Expression`1[] propertySelectors)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.FirstOrDefaultAsync(Expression`1 predicate)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task`1 actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Abp.Configuration.SettingStore.GetSettingOrNullAsync(Nullable`1 tenantId, Nullable`1 userId, String name)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinallyAndGetResult[T](Task`1 actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Abp.Configuration.SettingManager.InsertOrUpdateOrDeleteSettingValueAsync(String name, String value, Nullable`1 tenantId, Nullable`1 userId)
at Abp.Configuration.SettingManager.ChangeSettingForApplicationAsync(String name, String value)
at Abp.Threading.InternalAsyncHelper.AwaitTaskWithPostActionAndFinally(Task actualReturnValue, Func`1 postAction, Action`1 finalAction)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.<>c__DisplayClass15_0.<Run>b__0(Task t)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location where exception was thrown ---
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException(Task task)
at Nito.AsyncEx.AsyncContext.Run(Func`1 action)
And the value in the application settings is not updated.
I tried wrapping in uow but it doesn't help:
public override async Task HandleInternallyAsync(ItemUpdatedEvent eventData)
{
using (var uow = _unitOfWorkManager.Begin(TransactionScopeOption.RequiresNew))
{
await _settingManager.ChangeSettingForApplicationAsync("key", value.ToString());
await uow.CompleteAsync();
}
}

Related

EF 7 + Oracle DB - InvalidCastException: Specified cast is not valid

I am trying to query an Oracle database from .NET7.
I used database first approach to generate my model context. When querying, I get the following exception:
InvalidCastException: Specified cast is not valid.
Oracle.ManagedDataAccess.Client.OracleDataReader.GetInt16(int i)...
That's my (truncated) object class, and the property causing the exception (when I comment the property, select query is working):
public partial class Car
{
public string? Owner { get; set; }
[...]
}
Database looks like this:
CREATE TABLE "Car"
( "Owner" VARCHAR2(6 BYTE)
[...]
Generated context:
modelBuilder.Entity<Car>(entity =>
{
entity.Property(e => e.Owner)
.HasMaxLength(6)
.IsUnicode(false)
.HasColumnName("Owner")
[...]
}
Packages:
Oracle.EntityFrameworkCore 7.21.8
Microsoft.EntityFrameworkCore.Design 7.0.1
What's the problem? Is it because the column is nullable? I have no idea.
EDIT:
Seems like the problem is the stored data. Some rows must be corrupted / not like the column definition.
EDIT2:
That's the LINQ query:
return await _context.Cars.Take(10).ToListAsync();
Stacktrace:
System.InvalidCastException: Specified cast is not valid.
at Oracle.ManagedDataAccess.Client.OracleDataReader.GetInt16(Int32 i)
at lambda_method19(Closure, QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator)
at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync[TSource](IQueryable`1 source, CancellationToken cancellationToken)
at CarService.Controllers.CarController.GetCars(Int32 plate) in C:\GIT\webservices\car-service-dotnet\CarService\Controllers\CarController.cs:line 45
at lambda_method5(Closure, Object)
at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.AwaitableObjectResultExecutor.Execute(ActionContext actionContext, 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|20_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.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 Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddlewareImpl.Invoke(HttpContext context)

ASP.NET Core tries to cast an object to System.Int64 when using LINQ GroupBy

When trying to execute the following ASP.NET Core code:
public class Foo
{
public long A { get; set; }
public string B { get; set; }
}
[HttpGet]
[Route("Foos")]
public ActionResult<IEnumerable<IGrouping<long, Foo>>> Foos()
{
var foos = new List<Foo> { new Foo { A = 1, B = "Foo" }, new Foo { A = 2, B = "Bar" }, new Foo { A = 2, B = "Baz" } };
return new ActionResult<IEnumerable<IGrouping<long, Foo>>>(foos.GroupBy(f => f.A));
}
I get:
System.InvalidCastException: Unable to cast object of type 'Foo' to type 'System.Int64'.
at System.Text.Json.JsonPropertyInfoNotNullable`4.OnWriteEnumerable(WriteStackFrame& current, Utf8JsonWriter writer)
at System.Text.Json.JsonPropertyInfo.WriteEnumerable(WriteStack& state, Utf8JsonWriter writer)
at System.Text.Json.JsonSerializer.HandleEnumerable(JsonClassInfo elementClassInfo, JsonSerializerOptions options, Utf8JsonWriter writer, WriteStack& state)
at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer, Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state)
at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding)
at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextResultFilterAsync>g__Awaited|29_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 where exception was thrown ---
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__Logged|17_1(ResourceInvoker invoker)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
Why does it seem to be trying to serialize an object to an int64? How can I successfully return the result of a GroupBy from a web API endpoint?
New System.Text.Json serializer cannot serialize IEnumerable<IGrouping<long, Foo>>.
Solution
I would recommend switching to old Json.Net serializer in your ASP.Net Core project. I've tested it and it works fine with Json.Net.
See this article for information about switching to Json.Net.
It will be something as easy as that:
services.AddMvc()
.AddNewtonsoftJson();

AsyncTaskCodeActivity and lost context after await

AsyncTaskCodeActivity fails when the context parameter is accessed after the first await is performed. For example:
public class TestAsyncTaskCodeActivity : AsyncTaskCodeActivity<int>
{
protected async override Task<int> ExecuteAsync(AsyncCodeActivityContext context, CancellationToken cancellationToken)
{
await Task.Delay(50);
// context has already been disposed and the next line throws
// ObjectDisposedException with the message:
// An ActivityContext can only be accessed within the scope of the function it was passed into.
context.Track(new CustomTrackingRecord("test"));
// more awaits can happen here
return 3;
}
}
Is there any simple way to preserve the context so it can be used also after awaiting something?
Ah.
When I wrote AsyncTaskCodeActivity<T>, I assumed that the AsyncCodeActivityContext was in fact going to be the same instance at the beginning and end of the asynchronous method, and be available all the way through. This is not the case (which is a bit odd - not sure why the WF team made that decision).
Instead, the AsyncCodeActivityContext can only be accessed at the beginning and end of the activity. Awkward, indeed.
The updated code below will allow you to access the context at the beginning (e.g., reading In variables) and then access the context again at the end. I also introduce an optional TState, which can be used for storing activity state (which the activity can access throughout its execution). Let me know if this fits your needs; I haven't tested it.
public abstract class AsyncTaskCodeActivity<T, TState> : AsyncCodeActivity<T>
{
protected sealed override IAsyncResult BeginExecute(AsyncCodeActivityContext context, AsyncCallback callback, object state)
{
TState activityState = PreExecute(context);
context.UserState = activityState;
var task = ExecuteAsync(activityState);
return AsyncFactory<T>.ToBegin(task, callback, state);
}
protected sealed override T EndExecute(AsyncCodeActivityContext context, IAsyncResult asyncResult)
{
var result = AsyncFactory<T>.ToEnd(asyncResult);
return PostExecute(context, (TState)context.UserState, result);
}
protected virtual TState PreExecute(AsyncCodeActivityContext context)
{
return default(TState);
}
protected abstract Task<T> ExecuteAsync(TState activityState);
protected virtual T PostExecute(AsyncCodeActivityContext context, TState activityState, T result)
{
return result;
}
}
public abstract class AsyncTaskCodeActivity<T> : AsyncTaskCodeActivity<T, object>
{
}

Data deletion through WFC data service client applciation

I am self hosting a Odata WCF data service in a console application that is hooked up to an Oracle database through ADO.Net entity model. i am using Microsoft.Data.Services v5.5.0.I can read/write data through the client application but cannot delete. Here is the code:
Server code:
public class tos_host : DataService<Entities>
{
public static void InitializeService(DataServiceConfiguration config)
{
// TODO: set rules to indicate which entity sets and service operations are visible, updatable, etc.
// Examples:
config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
}
class Program
{
static void Main(string[] args)
{
Uri[] baseAddresses = new Uri[1];
baseAddresses[0] = new Uri("http://localhost:4444/tos_host");
using (DataServiceHost host = new DataServiceHost(typeof(tos_host), baseAddresses))
{
host.Open();
Console.WriteLine("TOS host up and running.....");
Console.ReadLine();
host.Close();
}
}
}
Client code:
static void Main(string[] args)
{
Entities context = new Entities(new Uri("http://localhost:4444/tos_host"));
context.MergeOption = MergeOption.OverwriteChanges;
context.IgnoreMissingProperties = true;
var container = new CONTAINERS();
container.CONTAINER_ID = "CONT";
container.TIMESTAMP=DateTime.UtcNow;
context.AddToCONTAINERS(container);
context.SaveChanges();
CONTAINERS container_2 = context.CONTAINERS.Where(c => c.CONTAINER_ID == "CONT").First();
context.DeleteObject(container_2);
context.SaveChanges(); //Here i get an exception
}
The exception is as follows:
System.Data.Services.Client.DataServiceRequestException was unhandled
HResult=-2146233079
Message=An error occurred while processing this request.
Source=Microsoft.Data.Services.Client
StackTrace:
at System.Data.Services.Client.SaveResult.HandleResponse()
at System.Data.Services.Client.BaseSaveResult.EndRequest()
at System.Data.Services.Client.DataServiceContext.SaveChanges(SaveChangesOptions options)
at System.Data.Services.Client.DataServiceContext.SaveChanges()
at client_test_lnew_libs.Program.Main(String[] args) in c:\Users\ITS\Desktop\rmcs_tests \client_test_lnew_libs\client_test_lnew_libs\Program.cs:line 27
at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart()
InnerException: System.Data.Services.Client.DataServiceClientException
HResult=-2146233079
Message=<?xml version="1.0" encoding="utf-8"?><m:error xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"><m:code /><m:message xml:lang="el-GR">Resource not found for the segment 'CONTAINERS'.</m:message></m:error>
StatusCode=404
InnerException:
What am i doing wrong? Any clues?
From my understanding, when you query and no results are returned, the dataservice will throw the exception you're seeing. To return an empty set instead, you need to set the IgnoreResourceNotFoundException property:
context.IgnoreResourceNotFoundException = true;
See the following blog post for more information:
http://blogs.msdn.com/b/peter_qian/archive/2009/03/20/safe-resource-not-found-404-exception-handling-in-ado-net-data-service-client.aspx?Redirected=true

AutoMapper throwing NullReferenceException when mapping nullable enum to null

I can't seem to figure out why AutoMapper is throwing an exception for this mapping:
public class MyDestinationType
{
public MyCustomEnum? PropName { get; set; }
}
public enum MyCustomEnum
{
Val1,
Val2
}
Mapper.CreateMap<MySourceType, MyDestinationType>()
.ForMember(d => d.PropName, o => o.ResolveUsing(s =>
{
if (s.Val1) return MyCustomEnum.Val1;
else if (s.Val2) return MyCustomEnum.Val2;
return null;
}))
;
The exception only occurs when the MyCustomEnum? PropName property gets mapped to a null value. Here is how I am doing the mapping:
var source = MethodToGetSourceObject();
var destination = Mapper.Map<MyDestinationType>(source);
The exception thrown is an AutoMapperMappingException which wraps 2 other AutoMapperMappingExceptions. The 4th and final InnerException is a NullReferenceException. The stack trace looks something like this:
[NullReferenceException: Object reference not set to an instance of an object.]
AutoMapper.Mappers.EnumMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) +198
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +447
[AutoMapperMappingException: Trying to map System.Object to System.Nullable`1[[MyProject.MyCustomEnum, MyProject, Version=2.0.4784.16259, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Destination property: PropName
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +519
AutoMapper.Mappers.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap) +592
[AutoMapperMappingException: Trying to map System.Object to System.Nullable`1[[MyProject.MyCustomEnum, MyProject, Version=2.0.4784.16259, Culture=neutral, PublicKeyToken=null]].
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Destination property: PropName
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.Mappers.PropertyMapMappingStrategy.MapPropertyValue(ResolutionContext context, IMappingEngineRunner mapper, Object mappedObject, PropertyMap propertyMap) +689
AutoMapper.Mappers.PropertyMapMappingStrategy.Map(ResolutionContext context, IMappingEngineRunner mapper) +275
AutoMapper.Mappers.TypeMapMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) +273
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +447
[AutoMapperMappingException: Trying to map MyProject.MySourceType to MyProject.MyDestinationType.
Using mapping configuration for MyProject.MySourceType to MyProject.MyDestinationType
Exception of type 'AutoMapper.AutoMapperMappingException' was thrown.]
AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) +519
AutoMapper.MappingEngine.Map(Object source, Type sourceType, Type destinationType, Action`1 opts) +192
AutoMapper.MappingEngine.Map(Object source, Type sourceType, Type destinationType) +196
AutoMapper.MappingEngine.Map(Object source) +169
AutoMapper.Mapper.Map(Object source) +107
[Here is where my code calls Mapper.Map<MyDestinationType>(source)]
Again, the exception only occurs when the resolution would have PropName == null (for example if both s.Val1 and s.Val2 were false). The exception does not occur when the mapping would resolve to the enum having some non-null value.
Is this another bug in AutoMapper?

Resources