After some more investigation and testing I don't think it's due to the background workers, we will probably open a new thread regarding the idle connections issue. Would still be nice to know the best practice for UoW in background jobs though :-)
Hi, Sorry for digging this up, but I have a similar issue with Postgres and idle connections not freeing/closing (leading to PostgresException 53300), and I suspect background workers after reading this thread.
So I understand that using [UnitOfWork] there is bad (which we did use), correct? We're still using version 8.1 of Zero (.net core).
Our background worker has to check many records for all tenants, like so:
public class XVerificationWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
{
private readonly IRepository<Tenant> _tenantRepository;
private readonly IUserEmailer _userEmailer;
private readonly XService _xService;
private readonly IUnitOfWorkManager _unitOfWorkManager;
DateTime lastCheck = DateTime.UtcNow.Date.AddDays(-1);
public XVerificationWorker(AbpTimer timer,
XService xService,
IRepository<Tenant> tenantRepository,
IUserEmailer userEmailer,
IUnitOfWorkManager unitOfWorkManager)
: base(timer)
{
_tenantRepository = tenantRepository;
_userEmailer = userEmailer;
_xService = xService;
//Timer.Period = 3600000;
Timer.Period = 60;
_unitOfWorkManager = unitOfWorkManager;
}
//[UnitOfWork] //Bad?!
protected override void DoWork()
{
if (lastCheck == DateTime.UtcNow.Date || DateTime.UtcNow.Hour < 1)
return;
lastCheck = DateTime.UtcNow.Date;
List<Tenant> affectedTenants = new List<Tenant>();
using (var unitOfWork = _unitOfWorkManager.Begin())
{
affectedTenants = _tenantRepository.GetAll().ToList();
unitOfWork.Dispose();
}
foreach (Tenant t in affectedTenants)
{
try
{
using (var unitOfWork = _unitOfWorkManager.Begin())
{
//using (CurrentUnitOfWork.SetTenantId(t.Id))
using (_unitOfWorkManager.Current.SetTenantId(t.Id))
{
if (t.Id != 0)
try
{
Task.WaitAll(_xService.FullXVerification());
}
catch (Exception ex)
{
Logger.Error(ex.Message, ex);
Task.WaitAll(_userEmailer.TryToSendXVerificationFailedMail(ex.Message));
}
}
Task.WaitAll(unitOfWork.CompleteAsync());
}
}
catch (Exception ex)
{
Logger.Error(ex.Message, ex);
}
}
}
}
-> Is that good code now?
Before, we were using it like so:
[UnitOfWork]
protected override void DoWork()
{
[...]
foreach (Tenant t in affectedTenants)
{
[...]
using (CurrentUnitOfWork.SetTenantId(t.Id))
{
if (t.Id != 0)
try
{
Task.WaitAll(_xService.FullXVerification());
}
catch (Exception ex)
{
Logger.Error(ex.Message, ex);
Task.WaitAll(_userEmailer.TryToSendXVerificationFailedMail(ex.Message));
}
}
}
}
Thank you!
Hi, We added some binary fields to our data model which may contain pdf files and are passed into the frontend as base64 like so:
this._xxxServiceProxy.getFileBytes(result.objekt.id)
.subscribe(result => {
if (result) {
this.display = this._sanitizer.bypassSecurityTrustResourceUrl('data:application/pdf;base64,' + result);
}
});
<div class="form-group" *ngIf="display">
<object [(data)]="display" *ngIf="objekte?.extension?.toLowerCase() === 'pdf'" style="width:100%;height:600px" type="application/pdf">
</object>
</div>
So far so good (except there are issues with bigger pdf files, but inserting them as iframe with another approach in the front-end works fine also.
Now the question is, as some browsers offer to comment pdfs in their embedded views, is there a possibility to access the updated pdf/base64 data (this.display
here) to pass the update back to the server side?
this.display
seems to keep the old value without the comment. With an iframe approach it seems even harder to access the updated data from the browser...
Thanks for any ideas!
Thanks, we'll give that a try and see how performant it is. At least it should only affect the performance of filtered users.
Well, it might be a list length somewhere between 10 and max. 10000 docket Ids, so not always that small.
Is it possible to create a claim or field in AbpSession of type List<string>
? Can you maybe give an example?
We'd do some performance testing with this approach then.
Thank you for your quick answer and pointing to the possibility of storing a field in AbpSession! I will give a quick example of our current data structure and the goal.
Users properties (existing entity)
Docket properties (existing entity)
Other entities (e. g. correspondence, existing entity)
<br> A new "sharing" entity to manage client access would mainly consist of rows containing:
So the filter would always (if user has client flag) have to check through a docket Id if access is allowed. The filter may have to read the corresponding docket row to get the client address number and look for an allowing rule in mentioned new sharing entity.
This approach would save us from having to add fields in all entities and having to update all of them when changes in the client access happen (WAL archive might get really big in that case). The price will certainly be less performance for filtered users due to the filter, but hopefully acceptable.
Another idea is to create a new claim with a list of allowed docket Ids first and do something like this Expression<Func<TEntity, bool>> mayHaveClientFilter = e => ClientAccessAllowedDocketIds().Contains(EF.Property<string>(e, "ID_AKTE"))
in protected override Expression<Func<TEntity, bool>> CreateFilterExpression<TEntity>()
. The docket Ids list should be refreshed at user login at least.
Please answer the following questions before submitting an issue. YOU MAY DELETE THE PREREQUISITES SECTION.
Hi,
We have an app running for offices with entities like dockets, correspondence, activity recordings, invoices, addresses and so on. We're hosting as cloud provider and use multi tenancy to separate different offices. So far, so good. Now we need to add client access for those offices, let's call it sub-tenants: An office wants to share the dockets related to the address of a certain client with this client. And (maybe) all related rows like correspondence etc. belonging to this client's dockets.
The idea is to provide those clients an account in Zero with a special role for customers. Then there will be a new "sharing" entity with rows containing e.g. docket ids. So we'd need a filter that checks:
I hope I cloud make clear what we need to realize - an optional filter for certain users only, and the filter has to lookup in a new "sharing" entity for allowed dockets. And all entities referring to dockets (i.e. they have a docketId property) have to be filtered with the same rule.
We started with this approach https://aspnetboilerplate.com/Pages/Documents/Articles\How-To\add-custom-data-filter-ef-core, but still fail to implement the filter condition. We can't simply add a property to filter like in IMayHaveOrganizationUnit, we need a filter that looks up another entity and sort of joins them. If we're wrong with this approach and there's a better solution, we'd also be happy to learn about it.
Thanks very much!
I think I found the answer here https://github.com/Napster2210/ngx-spinner/issues/74 - the parent div needs to have relative position property set!
Hi, Has this ever been solved? I'm having the same issue here (still on Zero 8.4) with entities generated by the Power Tool. Curious thing is that the spinner loads correctly on some divs, like here around the quick filter input:
<div class="form-group m-form__group align-items-center" [busyIf]="test">
<div class="input-group">
<input [(ngModel)]="filterText" name="filterText" autoFocus class="form-control m-input" [placeholder]="l('SearchWithThreeDot')" type="text">
<div class="input-group-append">
<button (click)="setFilter()" class="btn btn-outline-primary blue" type="submit"><i class="fa fa-search"></i>{{l("Search")}}</button>
</div>
</div>
</div>
...but not e.g. in the Primeng datatable's div <div class="primeng-datatable-container col-12" [busyIf]="test">
- then it appears fullscreen.
Any idea what to look at and how to solve that?
Thank you!
Thanks for your fast reply! Those packages should be all on Zero's 8.1 standard version (we're planning to upgrade Zero in the future, but due to the amount of work to update all our entities, this won't happen in the next few months). Please find screenshots below. Honestly I don't feel good with upgrading a bunch of packages and thus leaving 8.1 standards - this involves complete testing of everything before releasing a new version. If you suspect a specific package, that's something else though.
What we did in the meantime and would like to hear your opinion on that, too:
Thanks again for your support!