Base solution for your next web application

Activities of "zokho"

Hi, I have already included the code in my last post. By here it is again:

public class ShouldSerializeContractResolver : DefaultContractResolver
    {
        public new static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);

            if (property.PropertyName == "CreatorUserId")
            {
                property.ShouldSerialize =
                    instance =>
                    {
                        JobLocationDto e = (JobLocationDto)instance;
                        if (e.CreatorUserId.Value != GetCurrentUser().Id) 
                        {
                            return false;
                        }
                        return true;
                    };
            }
            return property;
        }
    }

Please note that I have not injected the UserManager to the ShouldSerializeContractResolver class yet to use the GetCurrentUser, but the whole idea is dropping the Audited fields from the the response if the caller is not Admin or the owner of the entity

public async Task<ListResultDto<JobLocationDto>> GetJobLocationList(GetJobLocationListInput input)
        {
            if (AbpSession.UserId != null)
            {
                if (await UserManager.IsGrantedAsync(GetCurrentUser().Id, AppPermissions.Pages_Administration_Jobs_Locations))
                {
                    var jobLocationsManage = await _jobLocationRepository.GetAll().Where(jobLocation => input.State == Common.VisibilityState.All ? (jobLocation.IsActive || !jobLocation.IsActive) :
                                                                                                  input.State == Common.VisibilityState.Active ? jobLocation.IsActive : !jobLocation.IsActive).ToListAsync();
                    return new ListResultDto<JobLocationDto>(ObjectMapper.Map<List<JobLocationDto>>(jobLocationsManage));
                }
            }
            var jobLocations = await _jobLocationRepository.GetAll().Where(jobLocation => jobLocation.IsActive).ToListAsync();
            foreach (var jobLocation in jobLocations)
            {
                //this jb would be one jobLocation in string format, and the method returns Task<ListResultDto<JobLocationDto>>!!!!
                var jb = JsonConvert.SerializeObject(ObjectMapper.Map<JobLocationDto>(jobLocation), new JsonSerializerSettings { ContractResolver = new ShouldSerializeContractResolver() });
            }
            return new ListResultDto<JobLocationDto>(ObjectMapper.Map<List<JobLocationDto>>(jobLocations));
        }

I have also tried to conditionally ignore the property in the CustomeDtoMapper class like below:

configuration.CreateMap<JobLocation, JobLocationDto>()
               .ForMember(jl => jl.CreationTime, option => option.Condition(jl => jl.CreatorUserId == ADMIN_USER_ID));

but there are 2 problems with this approach:

  1. The option.Condition does not drop the property altogether and it just simply not setting its value if the condition met, which would not be a big deal!
  2. I can't use the UserManager in there to check the caller's userId against the entity's userId. Please kindly guide me on how I can if it is possible to use UserManager within the CustomDtoMapper class.

Today is my licence expires and I assume I no longer can post any comment on this thread. So I really appreciate a response ASAP, so I could reply back if is needed. I wish I could afford to renew my licence :cry:

Thank you very much guys ;)

Any comment on this? :roll:

I managed to hit the breakpoint and its is ignoring the property that I want. The problem however is that it returns a JSON in string format but I need to have my API return the DTO class so I could easily use it in the Angular project!

Any thought?

Hey Aaron,

  1. No, the breakpoint does not get hit! I have change the code and removed the UserManager for now:
public class ShouldSerializeContractResolver : DefaultContractResolver
    {
        public new static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);

            if (property.DeclaringType == typeof(JobLocationDto) && property.PropertyName == "CreatorUserId")
            {
                property.ShouldSerialize =
                    instance =>
                    {
                        JobLocationDto e = (JobLocationDto)instance;
                        if (true) {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    };
            }
            return property;
        }
    }

and this is the AppService API method:

public async Task<ListResultDto<JobLocationDto>> GetJobLocationList(GetJobLocationListInput input)
        {
            var jobLocations = await _jobLocationRepository.GetAll().Where(jobLocation => jobLocation.IsActive).ToListAsync();
            
            return new ListResultDto<JobLocationDto>(ObjectMapper.Map<List<JobLocationDto>>(jobLocations));
        }

As you can see I am not using the JsonConvert.SerializeObject to serialize it as the method is supposed to return Task<ListResultDto<JobLocationDto>> not a JSON result. I am pretty sure I am missing something in my code! but what?!

Hi Champs! Well at first I was looking for the second one but now that you have raised it, both! With the second one however, I have found it a bit hard to implement it with the current project structure. I assume that I need to define the ShouldSerializeManager by where the Dto classes are (Application.Shared). But the Application.Shared does not have a reference to the UserManager so I could check the caller's permission and roles to decide whether or not serialize the property. I have also tried the second approach by defining the ShouldSerializeContractResolver in the Application project by one of the AppServices implementation but it does work! In the below code I was expecting that the GetJobLocationList() in the JobLocationAppService not returning the CreatoUserId for the callers who have nnot been granted the required permission but it does!

public class JobLocationAppService : AgbizCareersDemoAppServiceBase, IJobLocationAppService
    {
public async Task<ListResultDto<JobLocationDto>> GetJobLocationList(GetJobLocationListInput input)
        {
            var jobLocations = await _jobLocationRepository.GetAll().Where(jobLocation => jobLocation.IsActive).ToListAsync();
            return new ListResultDto<JobLocationDto>(ObjectMapper.Map<List<JobLocationDto>>(jobLocations));
        }
}
public class ShouldSerializeContractResolver : DefaultContractResolver
    {
        public new static readonly ShouldSerializeContractResolver Instance = new ShouldSerializeContractResolver();
        protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
        {
            JsonProperty property = base.CreateProperty(member, memberSerialization);
            UserManager userManager = new UserManager();

            if (property.DeclaringType == typeof(JobLocationDto) && property.PropertyName == "CreatorUserId")
            {
                property.ShouldSerialize =
                    instance =>
                    {
                        JobLocationDto e = (JobLocationDto)instance;
                        if (userManager.UserManager.IsGrantedAsync(userManager.UserManager.AbpSession.UserId.Value, AppPermissions.Pages_Administration_Jobs_Locations).Result) {
                            return true;
                        }
                        else
                        {
                            return false;
                        }
                    };
            }
            return property;
        }
        protected class UserManager : AgbizCareersDemoAppServiceBase { }
    }

Thanks for your input in advance :)

Well done! Thanks for that Aaron, but would you please tell me why I could do it without that inheritance? And why the UserLinkManager does not inherit the ITransientDependency? Does the documentation have any reference to the ITransientDependency?

Cheers,

Hi Aaron, Thanks for your comment. Well, the problem is I can't distinguish the business logic and the requested application functionalities. For instance in the UserAppService>CreateUserAsync, almost all the business logic of creating a user is located in the method body itself rather than the UserManager in the Domain layer.

thanks

Answer

Hi Alper, After spending some time over the issue I have finally found out that the issue is in the side-bar-menu.component.html file. I made some changes and have got it worked. The Accordion menu item works fine now but if in the "Visual Settings" page the Submenu toggle mode changes to Dropdown from Accordion, there wont be any pop up for the nested submenu item. How can I report the issue and my half way solution to your team to have it fully fixed?

Answer

Hey Apler, Perhaps my bad explanation. I am trying to load nested menu items in Angular solution. The code sample you have shared however was for MVC. Here is my Angular manu structure:

getMenu(): AppMenu {
        return new AppMenu('MainMenu', 'MainMenu', [
            new AppMenuItem('Dashboard', 'Pages.Administration.Host.Dashboard', 'flaticon-line-graph', '/app/admin/hostDashboard'),
            new AppMenuItem('Administration', '', 'flaticon-interface-8', '', [
                new AppMenuItem('Jobs', 'Pages.Administration.Jobs', 'fa fa-tachometer', '', [
                    new AppMenuItem('JobLocations', 'Pages.Administration.Jobs.Locations', 'fa fa-map-marker', '/app/admin/job-locations'),
                    new AppMenuItem('JobClassifications', 'Pages.Administration.Jobs.Classifications', 'fa fa-object-group', '/app/admin/job-classifications'),
                ]),
                new AppMenuItem('OrganizationUnits', 'Pages.Administration.OrganizationUnits', 'flaticon-map', '/app/admin/organization-units'),
            ])
        ]);
    }

The JobLocation and JobClassification appear under the Job menu item but without indention and the Job menu item does not collapse like its own parent (Administration) menu item.

Answer

<cite>alper: </cite> I've added some sub menu items to the Metronic theme. It seems to be supporting many sub levels.

Hey alper, Would you please share the code you have used to generate the nested menu items? I can't see any specific issue in my own code that shared earlier!

Cheers,

Showing 1 to 10 of 34 entries