I'm seeing this a lot as well. We see it a lot in this space as well. This happens a lot with switching accounts through the manage linked accounts bit or with the impersonation function.
Agree with alexanderpilhar we have only started seeing this since the upgrade to 8.2.1. Also this is happening in our production environment.
at System.Threading.CancellationToken.ThrowOperationCanceledException()
at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 20
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.FirstOrDefaultAsync(TPrimaryKey id)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task`1 task)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
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[TResult](Task`1 task)
at Nito.AsyncEx.AsyncContext.Run[TResult](Func`1 action)
at XXXX.Friendships.Cache.UserFriendsCache.GetUserFriendsCacheItemInternal(UserIdentifier userIdentifier) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\Cache\UserFriendsCache.cs:line 195
at Castle.Proxies.UserFriendsCacheProxy.GetUserFriendsCacheItemInternal_callback(UserIdentifier userIdentifier)
at Castle.Proxies.Invocations.UserFriendsCache_GetUserFriendsCacheItemInternal.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.InterceptSynchronous(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.UserFriendsCacheProxy.GetUserFriendsCacheItemInternal(UserIdentifier userIdentifier)
at XXXX.Friendships.Cache.UserFriendsCache.<>c__DisplayClass8_0.<GetCacheItem>b__0(String f) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\Cache\UserFriendsCache.cs:line 46
at Abp.Runtime.Caching.CacheExtensions.<>c__DisplayClass5_0`2.<Get>b__0(String k)
at Abp.Runtime.Caching.AbpCacheBase`2.Get(TKey key, Func`2 factory)
at Abp.Runtime.Caching.CacheExtensions.Get[TKey,TValue](ICache cache, TKey key, Func`2 factory)
at Castle.Proxies.Invocations.UserFriendsCache_GetCacheItem.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.InterceptSynchronous(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.UserFriendsCacheProxy.GetCacheItem(UserIdentifier userIdentifier)
at XXXX.Friendships.ChatUserStateWatcher.NotifyUserConnectionStateChange(UserIdentifier user, Boolean isConnected) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\ChatUserStateWatcher.cs:line 45
at XXXX.Friendships.ChatUserStateWatcher.OnlineClientManager_UserDisconnected(Object sender, OnlineUserEventArgs e) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\ChatUserStateWatcher.cs:line 41
at Abp.RealTime.OnlineClientManager.Remove(String connectionId)
at Abp.AspNetCore.SignalR.Hubs.OnlineClientHubBase.OnDisconnectedAsync(Exception exception)
System.OperationCanceledException: The operation was canceled.
at System.Threading.CancellationToken.ThrowOperationCanceledException()
at MySqlConnector.Core.CommandExecutor.ExecuteReaderAsync(IReadOnlyList`1 commands, ICommandPayloadCreator payloadCreator, CommandBehavior behavior, IOBehavior ioBehavior, CancellationToken cancellationToken) in C:\projects\mysqlconnector\src\MySqlConnector\Core\CommandExecutor.cs:line 20
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(DbContext _, Boolean result, CancellationToken cancellationToken)
at Pomelo.EntityFrameworkCore.MySql.Storage.Internal.MySqlExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
at Abp.EntityFrameworkCore.Repositories.EfCoreRepositoryBase`3.FirstOrDefaultAsync(TPrimaryKey id)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Abp.Domain.Uow.UnitOfWorkInterceptor.InternalInterceptAsynchronous[TResult](IInvocation invocation)
at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task`1 task)
at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
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[TResult](Task`1 task)
at Nito.AsyncEx.AsyncContext.Run[TResult](Func`1 action)
at XXXX.Friendships.Cache.UserFriendsCache.GetUserFriendsCacheItemInternal(UserIdentifier userIdentifier) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\Cache\UserFriendsCache.cs:line 195
at Castle.Proxies.UserFriendsCacheProxy.GetUserFriendsCacheItemInternal_callback(UserIdentifier userIdentifier)
at Castle.Proxies.Invocations.UserFriendsCache_GetUserFriendsCacheItemInternal.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.InterceptSynchronous(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.UserFriendsCacheProxy.GetUserFriendsCacheItemInternal(UserIdentifier userIdentifier)
at XXXX.Friendships.Cache.UserFriendsCache.<>c__DisplayClass8_0.<GetCacheItem>b__0(String f) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\Cache\UserFriendsCache.cs:line 46
at Abp.Runtime.Caching.CacheExtensions.<>c__DisplayClass5_0`2.<Get>b__0(String k)
at Abp.Runtime.Caching.AbpCacheBase`2.Get(TKey key, Func`2 factory)
at Abp.Runtime.Caching.CacheExtensions.Get[TKey,TValue](ICache cache, TKey key, Func`2 factory)
at Castle.Proxies.Invocations.UserFriendsCache_GetCacheItem.InvokeMethodOnTarget()
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Abp.Domain.Uow.UnitOfWorkInterceptor.InterceptSynchronous(IInvocation invocation)
at Castle.DynamicProxy.AbstractInvocation.Proceed()
at Castle.Proxies.UserFriendsCacheProxy.GetCacheItem(UserIdentifier userIdentifier)
at XXXX.Friendships.ChatUserStateWatcher.NotifyUserConnectionStateChange(UserIdentifier user, Boolean isConnected) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\ChatUserStateWatcher.cs:line 45
at XXXX.Friendships.ChatUserStateWatcher.OnlineClientManager_UserDisconnected(Object sender, OnlineUserEventArgs e) in D:\a\1\s\aspnet-core\src\XXXX.Core\Friendships\ChatUserStateWatcher.cs:line 41
at Abp.RealTime.OnlineClientManager.Remove(String connectionId)
at Abp.AspNetCore.SignalR.Hubs.OnlineClientHubBase.OnDisconnectedAsync(Exception exception)
Thank you for saving me hours of work :)
I am currently running it all on an Azure App Service Linux setup with .Net Core 3.1
The only issue I've encountered so far is where images are uploaded (profile picture). The current code uses system.drawing.common and this depends on libgdiplus.
I cannot actually get libgdiplus to work even after installing into the host through SSH (for testing purposes). In prod version in my startup I detect if I'm running on Linux and run a custom install.sh script which installs a bunch of apt-get packages needed for other third party libraries I'm using. They all work fine. libgdiplus will not.
Also based on this link https://www.hanselman.com/blog/HowDoYouUseSystemDrawingInNETCore.aspx
I suspect ASP Zero should probably move away from using system.drawing.common if they can :)
So you should really have no problems running this on the Linux App Service.
Cheers
Hi,
I have a situation where I need to disable the tenant filters and then optionally manually add a filter on the tenant ID.
I do it as follows.
Wrap my code in using (UnitOfWorkManager.Current.DisableFilter(AbpDataFilters.MustHaveTenant, AbpDataFilters.MayHaveTenant)) {
Then do a var query = repo.GetAll() .Include(a bunch of related tables). etc
Further down in my logic with the IQueryable I will add in the following.
query.Where(_ => _.TenantId == AbpSession.TenantId.Value)
When I execute that query the TenantID filter is NOT enforced as I expect it to be.
The DisableFilter appears to overrule any manually added TenantId filter.
Is this expected? How do I get around this?
I feel like I'm missing something here.
Most email clients don't display external images by default these days. One approach is to not link to an external image and base64 encode the image directly into the template.
I'm about to make the same change to my templates as well.
Looking at the code that should also work as eventually it will get to this part of the code.
The tenantId would be null in this case and thus it will set the current tenantid in the filter to null and in affect be the host account. Same as just doing the settenantid call yourself really before publishing.
[UnitOfWork]
protected virtual async Task<List<NotificationSubscriptionInfo>> GetSubscriptionsAsync(int? tenantId, string notificationName, string entityTypeName, string entityId)
{
using (_unitOfWorkManager.Current.SetTenantId(tenantId))
{
return await _notificationSubscriptionRepository.GetAllListAsync(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
);
}
}
Ok thanks for that hint. I wasn't but I will.
I have found the cause of the issue. Complex and I'm not entirely sure it is intended behaviour but I understand it now.
The notificationpublisher code has these lines in it. So even if you pass null or empty for the tenant Id's in your notification the publisher will add in the current logged in session one (which in my case is an actual tenant and not the host account).
if (tenantIds.IsNullOrEmpty() && userIds.IsNullOrEmpty())
{
tenantIds = new[] { AbpSession.TenantId };
}
Then there is this code in the DefaultNotificationDistributor, before the call to the _notificationStore.GetSubscriptionsAsync. If this check passes then it will call the GetSubscriptionsAsync that has the disabling of the filters. If this check DOESN'T pass then it will use the tenant ID passed into it and not disable the filter. if (tenantIds.IsNullOrEmpty() || (tenantIds.Length == 1 && tenantIds[0] == NotificationInfo.AllTenantIds.To<int>())) {
Solutions:
If you want to send a notification from a tenant to the HOST only then switch to the host context before publishing the notification (using (_unitOfWorkManager.Current.SetTenantId(null))
If you are publishing a notification from a tenant and want to send it to any tentant or host subscribed to that particular notification name then set the tenantID to NotificationInfo.AllTenantIds (which is 0).
Got love digging through the ABP Code :)
Cheers to anyone else who comes across this.
Rick
Hi,
I'm trying to create and send a notification from a tenant to the host account.
I'm using the following code to publish the notification from within the context of my tenant account. await _notificationPublisher.PublishAsync(AppNotificationNames.MyNotification, notificationData);
I've noticed that it get's inserted into AbpNotifications correctly and then the Hangfire job runs to distribute it.
I've traced through the Abp code and found https://github.com/aspnetboilerplate/aspnetboilerplate/blob/c0604b9b1347a3b9581bf97b4cae22db5b6bab1b/src/Abp/Notifications/DefaultNotificationDistributer.cs
My issue is this section I believe (line 187 in GetUsers method)
if (tenantIds.IsNullOrEmpty() ||
(tenantIds.Length == 1 && tenantIds[0] == NotificationInfo.AllTenantIds.To<int>()))
{
//Get all subscribed users of all tenants
subscriptions = _notificationStore.GetSubscriptions(
notificationInfo.NotificationName,
notificationInfo.EntityTypeName,
notificationInfo.EntityId
);
}
When I trace the DB call here I can see that the GetSubscriptions call is made in the context of the tenant that originally created the notification. Thus even though my host users are subscribed to that NotificationName it will never receive it. This is also strange because the GetSubscriptions code has this.
[UnitOfWork]
public virtual List<NotificationSubscriptionInfo> GetSubscriptions(string notificationName, string entityTypeName, string entityId)
{
using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
{
return _notificationSubscriptionRepository.GetAllList(s =>
s.NotificationName == notificationName &&
s.EntityTypeName == entityTypeName &&
s.EntityId == entityId
);
}
}
So it should disable the filter. However this is my DB log (I've sanitized and cleaned it up a little).
@__ef_filter__p_0='False',
@__ef_filter__CurrentTenantId_1='2' (Nullable = true),
@__notificationName_0='App.MyNotifications' (Size = 96)], CommandType='Text', CommandTimeout='60']
SELECT a
.Id
, a
.CreationTime
, a
.CreatorUserId
, a
.EntityId
, a
.EntityTypeAssemblyQualifiedName
, a
.EntityTypeName
, a
.NotificationName
, a
.TenantId
, a
.UserId
FROM AbpNotificationSubscriptions
AS a
WHERE (@__ef_filter__p_0 OR (a
.TenantId
= @__ef_filter__CurrentTenantId_1)) AND
(((a
.NotificationName
= @__notificationName_0) AND a
.EntityTypeName
IS NULL) AND a
.EntityId
IS NULL)
You can see that the first paramater is false which means it is checking for the TenantId.
The distributer essentially cannot find any users subscribed to that notification and thus just delete's my abpnotifications row.
Is there any way around this. Is this expected behaviour.
I'm not sure why I'm seeing this behaviour.
Cheers Rick
I agree you can upgrade, just wanted people to know that it broke lots of my code.
The workaround is to install entityframework pre-release nuget packges into the web.host project.
I don't use a lot of automapper and make use of a lot of LINQ to map to my models.
Eg lots of this style of code.
repo.GetAll() .Include( => .SomeFK) .Where( => .Name == "Name") .Select( => new ModelIWantToReturn { Prop1 = _.Name, Prop2 = _.Description Prop3 = _.SomeFk.Any(x => x.IsActive) );
That kind of code above pretty much broken in EF Core 3.0 and you need the pre-release version to make it work again.
I had about 3 or 4 failures that worked in EF 2.0 that broke in EF Core 3.0 and worked straight away once I got the pre-release version in.
So it was more a warning to people who have bigger projects than I. If you have lots of LINQ style code be prepared it may not work in EF Core 3.0 without the 3.1 pre-release.
Thanks
All,
After upgrading to .Net Core 3.0 version yesterday I have to say that Entity Framework for .Net Core 3.0 is not ready and I'd advise holding off on upgrading.
Here are a few of the issues I've encountered with my upgrade.
https://github.com/aspnet/EntityFrameworkCore/issues/18090 https://github.com/aspnet/EntityFrameworkCore/issues/18510
They are really basic issues that appear to be fixed in pre-release versions.
I have managed to fix it up by upgrading the Host project to the pre-release Entity Framwork Core version but it's not a great solution.
It looks like everyone is holding off at the moment for 3.1 of the Entity Framework Core version.
If anyone else has better lucky would love to hear it.
Be great to see if Abp an upgrade to a pre-release version to get around these issues.
Cheers Rick