Base solution for your next web application
Starts in:
01 DAYS
01 HRS
01 MIN
01 SEC

Activities of "marble68"

Resolved - the DoWork method must be a [UnitOfWork]

As per https://aspnetboilerplate.com/Pages/Documents/Background-Jobs-And-Workers

Using the SubscriptionExpireEmailNotifierWorker as a template, I've created a worker.

When it runs, it tries to call GetAll from a repository and I get an ObjectDisposedException error.

This is my worker:

  public class MyWorker : PeriodicBackgroundWorkerBase, ISingletonDependency
    {

        private const int CheckPeriodAsMilliseconds = 1000 * 1 * 60 * 30; // 30 minutes

        private readonly IWebUrlService _webUrlService;
        private readonly IRepository<Employee, Guid> _employeeRepository;

        public MyWorker(
                AbpTimer timer,
                IRepository<Employee, Guid> employeeRepository
                ) : base(timer)
        {

            _employeeRepository = employeeRepository;

            Timer.Period = CheckPeriodAsMilliseconds;
            Timer.RunOnStart = true;

        }

        protected override void DoWork()
        {
            List<Employee> e = _employeeRepository.GetAll().ToList();

            int c = e.Count();
        }
    }

This is the error I get:

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: 'workDbContext'.'

This in the MVC startup, I register the worker like this:

workManager.Add(IocManager.Resolve<MyWorker>());

What am I missing?

Thanks!

Do we do it in both MVC and Host?

They are registered in both - or is it if we're only running the API do it there, and if we're doing it in MVC do it there?

Thanks

I think this is working, but not without my setting the TenantID to null and clearing the MayHaveTenant filter.

I'll keep working with it - but I have something working at the moment. Probably needs refinement.

I created my DomainService in Core project, right next to the entity.

I exposed GetAsync, injecting the repo and inheriting from workDomainServiceBase

I injected the domain service into the Controller, and updated the service in Application to inject the Domain service as well.

Then, in the GetAsync function in the service in application, I called the getAsync in the domain service.

In the public controller, I had to create a unit of work method that called the getAync in the domain service, but it would fair if I didn't set TenantID to null and clear the MayHaveTenant filter.

Based on this: https://support.aspnetzero.com/QA/Questions/9108/Update-an-Entity-from-the-public-website#answer-8ace2a6c-a66e-3758-43c5-39f57cb830ef

Do I need to, in effect, take any methods I'd call in the normal application service, and move them to this DomainService?

using only get:

In an app service, for example, I'd take the method: GetEmployeeForView

And instead of calling employeeRepository.GetAsync(id); to get an employee entity, i'd instead call employeeDomainService.GetAysnc(id); and return it to the app service from the domain service (referencing the domain service).

THen, in my controller, I'd reference the domain service, and get my entity directly.

Correct?

  1. If I create a domain service, do I put that class in the Application project? If not, where? Core, Core.Shared? Application.Shared?

  2. If I need this domain service to be usable by the Public website (for getting and updating entities), is that still the correct location? If not, where? Web.Core?

  3. If the public website needs to update an entity based on input from a browing user that is NOT logged in, will a simple unit of work allow that to happen?

  4. Does this unit of work need to exist in the Public controller or in the domain service?

Thanks!

My MVC dev environment is pointed at https://mvc. My Public dev environment is pointed at https://public

I did this to avoid cookie authentication cross contamination.

In dev, I'm doing this, and it works. However, this does NOT work in production.

using Abp.Domain.Repositories;
using okto.work.Survey;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Abp.Domain.Uow;
using Hangfire.Annotations;

namespace okto.work.Web.Survey
{
    public class EmployeeTakeManager : workDomainServiceBase, IEmployeeTakeManager
    {
        private readonly IRepository<Employee, Guid> _employeeRepository;
        private readonly IRepository<Department, Guid> _departmentRepository;
        private readonly IRepository<SurveyScript, Guid> _surveryscriptRepository;

        public EmployeeTakeManager(
            IRepository<Employee, Guid> employeeRepository, 
            IRepository<Department, Guid> departmentRepository,
            IRepository<SurveyScript, Guid> surveryscriptRepository
            )
        {
            _employeeRepository = employeeRepository;
            _departmentRepository = departmentRepository;
            _surveryscriptRepository = surveryscriptRepository;
        }

        [UnitOfWork]
        public async Task<Employee> GetEmployeeForTakeAsync(Guid id)
        {
            Logger.Debug($"TakeManager GetEmployeeForTakeAsync {id}");

            Employee employee;
            using (var uow = UnitOfWorkManager.Begin())
            {
                using (CurrentUnitOfWork.SetTenantId(null))
                {
                    using (CurrentUnitOfWork.DisableFilter(AbpDataFilters.MayHaveTenant))
                    {

                        try
                        {
                            Logger.Debug($"TakeManager _employeeRepository.GetAsync(id) {id}");

                            employee = await _employeeRepository.GetAsync(id);
                        }
                        catch (Exception ex)
                        {

                            throw ex;
                        }


                        uow.Complete();
                    }
                }
            }
            return employee;
        }
    }
}

Connections all work - everything is connecting.

I have my environment variable set to Production.

In my TakeController, I'm doing:

                Employee employee;
                employee = (await _employeeTakeManager.GetEmployeeForTakeAsync(_id));

Any ideas?

I think my issue is related to trying to get an entity across tenants from the public website.

Because they have differnet URLs, it was breaking in production (admin.domain.com vs domain.com).

In dev, they were both localhost.

To recreate, I added two host entries for localhost (mvc & public) - and modified settings to use those urls in development.

The result allowed me to recreate the problem in dev.

I've now made a Take Manager, and from there, call the original service

The only way I've gotten this to work is by modifying my EmployeeTakeService to expose custom methods, and set Tenant id to null and to clear the filter of MayHaveTenant.

Only in this circumstance am I able to get to an entity, regardless of Tenant.

But per your answer, I should not do this, correct?

Showing 181 to 190 of 238 entries