Base solution for your next web application

Activities of "ipservant"

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!

  • What is your product version? -> 8.4
  • What is your product type (Angular or MVC)? -> Angular
  • What is product framework type (.net framework or .net core)? -> .net core

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)

  • Regular user: All tenant's data should be accessible
  • Special user for client access: Only filtered dockets and rows of other entities related to those dockets should be accessible

Docket properties (existing entity)

  • Id
  • Client address number
  • Title, byte arrays and more...

Other entities (e. g. correspondence, existing entity)

  • Docket Id (not a foreign key in all cases)
  • Subject, byte arrays and more...

<br> A new "sharing" entity to manage client access would mainly consist of rows containing:

  • User Id (or maybe role Id or OU Id)
  • List of allowed docket Ids for this user/role/OU
  • and/or list of allowed client address numbers (for above docket property) -> also resulting in a list of allowed docket Ids

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.

Prerequisites

Please answer the following questions before submitting an issue. YOU MAY DELETE THE PREREQUISITES SECTION.

  • What is your product version? -> 8.1
  • What is your product type (Angular or MVC)? -> Angular
  • What is product framework type (.net framework or .net core)? -> .net Core

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:

  1. Is entity affected by sub-tenant/client filtering? (not everything has to be filtered)
  2. If true, is logged in user sub-tenant/client? (e.g. by looking up if he has a certain role associated)
  3. If true, apply additional filter by looking up in the sharing entity if he is allowed to access a certain docket id
    1. If the entity is not a docket, but an entity which is related to dockets, it also has to be checked if access to this docket id is allowed

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:

  • Update aspnet:3.1-buster-slim from 3.1.9 to 3.1.22 (Docker/Portainer doesn't that automatically when creating a new app image)
  • Limit the container's memory to 5 GB (I read that such a limit should force .Net Core apps into some sort of garbage collection before the docker host stalls)

Thanks again for your support!

Showing 1 to 10 of 48 entries