Base solution for your next web application

Activities of "roxybox"

Courses controller in the Training area

using System.Collections.Generic;
using System.Web.Mvc;
using Abp.Web.Mvc.Authorization;
using Roxybox.TrainingManager.Authorization;
using Roxybox.TrainingManager.Training;
using Roxybox.TrainingManager.Training.Dto;
using Roxybox.TrainingManager.Web.Controllers;
using Roxybox.TrainingManager.Web.Models;
using Roxybox.TrainingManager.Web.Models.Training;

namespace Roxybox.TrainingManager.Web.Areas.Training.Controllers
{

    [AbpMvcAuthorize(PermissionNames.Pages_Training_Courses)]
    public class CoursesController : TrainingManagerControllerBase
    {
        private readonly ICourseAppService _courseAppService;

        public CoursesController(ICourseAppService courseAppService)
        {
            _courseAppService = courseAppService;
        }

        public ActionResult Index()
        {
            //Run SUT
            var output = _courseAppService.GetCourses(new GetCoursesInput());

            var model = new CoursesViewModel
            {
                Courses = output.Courses,
                PageHeader = new PageHeaderViewModel("Training", "Courses", new List<BreadcrumbViewModel>()
                {
                    new BreadcrumbViewModel("Dashboard","/"),
                    new BreadcrumbViewModel("Training","/Training"),
                    new BreadcrumbViewModel("Courses")
                })
             };
            
            return View(model);
        }
    }
}

Base controller inherits from AbpController

public abstract class TrainingManagerControllerBase : AbpController

Hi

The app is mvc 5 and the app service worked previously when the controller was not in an area. I have created a new controller without any dependencies (in the constructor) an the controller works OK.

Do I need to register the app service within the area as well or will the auto registration be enough (when using the interfaces in the docs)?

I have created a new area called Training within my MVC application along with a controller called courses. If I go to the controller in a browser (/Training/Courses) I get the expected response (View rendered).

If I then add my appservice to be injected in the constructor the route is no longer able to find the controller resulting in a broken URL.

This controller was from the main controllers folder and was working OK before moving the controller to the area (updated the namespace).

Do I need to do any setup to make areas work with dependency injection?

Thanks for the help andmattia. I found that the issue was down to me missing the fact that the Entity was not in the DbContext.

After adding it everything started to work.

I have updated the CourseManager class based on the documentation and still get the error.

public abstract class CourseManager :  DomainService, ICourseManager
    {

        public ILocalizationManager LocalizationManager { get; set; }
         protected IRepository<Course> CourseRepository { get; set; }

        protected CourseManager(
           IRepository<Course> courseRepository)
        {
            CourseRepository = courseRepository;
            LocalizationManager = NullLocalizationManager.Instance;
        }
}
public interface ICourseManager : IDomainService
    {
}

I have created an app service but having difficulties with its dependencies.

Can't create component 'Roxybox.TrainingManager.Course.CourseAppService' as it has dependencies to be satisfied.

'Roxybox.TrainingManager.Course.CourseAppService' is waiting for the following dependencies:
- Service 'Roxybox.TrainingManager.Courses.Managers.ICourseManager' which was not registered.

The CourseManager appears to be the issue but not sure how to resolve it.

public class CourseAppService : TrainingManagerAppServiceBase, ICourseAppService
    {
        private readonly CourseManager _courseManager;

        public CourseAppService(
           CourseManager courseManager)
        {
            _courseManager = courseManager;
        }
public abstract class CourseManager :  IDomainService, ITransientDependency
    {

        public ILocalizationManager LocalizationManager { get; set; }
        protected IRepository<Course> CourseRepository { get; set; }

        protected CourseManager(
           IRepository<Course> courseRepository)
        {
            CourseRepository = courseRepository;
            LocalizationManager = NullLocalizationManager.Instance;
        }

Thanks for pointing that out.

One more question. If I wanted to use this class with IOC where should I register it (if I need to) and do I have to use the constructor approach or is there another way to use the class?

I have created a filter to retrieve the cached version of the Tenant using the domain. Alternatively, if I have to use the constructor approach I will have to put it in the in the base controller.

I have added a domain property to the Tenant class and have replicated the ITenantCache implementation to now have Get(string domain) instead of Get(string tenancyName).

After making all the changes so it looks up the tenant based on the domain instead of the tenancy name I am unable to get access to the new Domain property.

<ins>protected virtual TTenant GetTenantOrNull(string domain)
        {
            using (_unitOfWorkManager.Current.SetTenantId(null))
            {
                return _tenantRepository.FirstOrDefault(t => t.**[u]_Domain_</ins>**== domain);
            }
        }

I have the same issue for the below

protected virtual RbTenantCacheItem CreateRbTenantCacheItem(TTenant tenant)
        {
            return new RbTenantCacheItem
            {
                Id = tenant.Id,
                Name = tenant.Name,
                TenancyName =  tenant.TenancyName,
                Domain = tenant.<ins>_**Domain**_</ins>,
                EditionId = tenant.EditionId,
                ConnectionString = SimpleStringCipher.Instance.Decrypt(tenant.ConnectionString),
                IsActive = tenant.IsActive
            };
        }

Below is the full class

public class TenantCache<TTenant, TUser> : IRbTenantCache, IEventHandler<EntityChangedEventData<TTenant>>
        where TTenant : AbpTenant<TUser>
        where TUser : AbpUser<TUser>
    {
        private readonly ICacheManager _cacheManager;
        private readonly IRepository<TTenant> _tenantRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public TenantCache(
            ICacheManager cacheManager,
            IRepository<TTenant> tenantRepository,
            IUnitOfWorkManager unitOfWorkManager)
        {
            _cacheManager = cacheManager;
            _tenantRepository = tenantRepository;
            _unitOfWorkManager = unitOfWorkManager;
        }

        public virtual RbTenantCacheItem Get(int tenantId)
        {
            var cacheItem = GetOrNull(tenantId);

            if (cacheItem == null)
            {
                throw new AbpException("There is no tenant with given id: " + tenantId);
            }

            return cacheItem;
        }

        public virtual RbTenantCacheItem Get(string domain)
        {
            var cacheItem = GetOrNull(domain);

            if (cacheItem == null)
            {
                throw new AbpException("There is no tenant with given tenancy name: " + domain);
            }

            return cacheItem;
        }

        public virtual RbTenantCacheItem GetOrNull(string domain)
        {
            var tenantId = _cacheManager.GetTenantByNameCache()
                .Get(domain, () => GetTenantOrNull(domain)?.Id);

            if (tenantId == null)
            {
                return null;
            }

            return Get(tenantId.Value);
        }

        public RbTenantCacheItem GetOrNull(int tenantId)
        {
            return _cacheManager
                .GetTenantCache()
                .Get(
                    tenantId,
                    () =>
                    {
                        var tenant = GetTenantOrNull(tenantId);
                        if (tenant == null)
                        {
                            return null;
                        }

                        return CreateRbTenantCacheItem(tenant);
                    }
                );
        }

        protected virtual RbTenantCacheItem CreateRbTenantCacheItem(TTenant tenant)
        {
            return new RbTenantCacheItem
            {
                Id = tenant.Id,
                Name = tenant.Name,
                TenancyName =  tenant.TenancyName,
                Domain = tenant.Domain,
                EditionId = tenant.EditionId,
                ConnectionString = SimpleStringCipher.Instance.Decrypt(tenant.ConnectionString),
                IsActive = tenant.IsActive
            };
        }

        [UnitOfWork]
        protected virtual TTenant GetTenantOrNull(int tenantId)
        {
            using (_unitOfWorkManager.Current.SetTenantId(null))
            {
                return _tenantRepository.FirstOrDefault(tenantId);
            }
        }

        [UnitOfWork]
        protected virtual TTenant GetTenantOrNull(string domain)
        {
            using (_unitOfWorkManager.Current.SetTenantId(null))
            {
                return _tenantRepository.FirstOrDefault(t => t.Domain == domain);
            }
        }

        public void HandleEvent(EntityChangedEventData<TTenant> eventData)
        {
            var existingCacheItem = _cacheManager.GetTenantCache().GetOrDefault(eventData.Entity.Id);

            _cacheManager
                .GetTenantByNameCache()
                .Remove(
                    existingCacheItem != null
                        ? existingCacheItem.TenancyName
                        : eventData.Entity.TenancyName
                );

            _cacheManager
                .GetTenantCache()
                .Remove(eventData.Entity.Id);
        }
    }
Showing 1 to 8 of 8 entries