Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Many controllers in *.HttpApi take too long to load a project #3180

Closed
volethanh opened this issue Mar 18, 2020 · 11 comments · Fixed by #3348
Closed

Many controllers in *.HttpApi take too long to load a project #3180

volethanh opened this issue Mar 18, 2020 · 11 comments · Fixed by #3348
Assignees
Milestone

Comments

@volethanh
Copy link

Hi,

I'm facing a problem that when I define many many controllers (around 100 controllers), It takes too long to start project *.HttpApi.Host

How can I solve this issue ?

@maliming
Copy link
Member

Can you share the application's log?

Is the request slow after the application is started?

@volethanh
Copy link
Author

The request is normal, but when I start debug the application, it's very slow. I try to exclude about 90 controllers, and it's not slow anymore

@maliming
Copy link
Member

Is it possible to reproduce the problem if there are many empty controllers?

@volethanh
Copy link
Author

volethanh commented Mar 18, 2020

After I reproduce, I can start the project *.HttpApi.Host with many empty controllers normally. But when I try again with full actions in controller, The browser loading very long!

I attatched 2 logs for you to review. It stucks at "Starting web host"

2020-03-18 21:04:23.124 +07:00 [INF] Starting web host.
2020-03-18 21:10:08.538 +07:00 [INF] User profile is available. Using...
logs_1_controller.txt
logs_n_controllers.txt

This is my controller

using DDC.BackendService.DMS;
using DDC.BackendService.DMS.Dtos;
using DDC.BackendService.Dto;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Application.Dtos;

namespace DDC.BackendService.CustomerProduct
{
    [RemoteService]
    [Route("api/backendservice/CustomerProduct")]
	public class CustomerProductsController : BackendServiceController
    {
        private readonly ICustomerProductsAppService _customerProductsAppService;

        public CustomerProductsController(ICustomerProductsAppService customerProductsAppService)
        {
            _customerProductsAppService = customerProductsAppService;
        }

        [HttpGet]
        [Route("Get")]
        [Authorize]
        public async Task<CustomerProductDto> GetAsync(Guid id)
        {
            return await _customerProductsAppService.GetAsync(id);
        }

        [HttpGet]
        [Route("GetList")]
        [Authorize]
        public async Task<PagedResultDto<CustomerProductDto>> GetListAsync(PagedAndSortedResultRequestDto input)
        {
            return await _customerProductsAppService.GetListAsync(input);
        }

        [HttpPost]
        [Route("Create")]
        [Authorize]
        public async Task<CustomerProductDto> CreateAsync(CreateOrEditCustomerProductDto input)
        {
            return await _customerProductsAppService.CreateAsync(input);
        }

        [HttpPut]
        [Route("Update")]
        [Authorize]
        public async Task<CustomerProductDto> UpdateAsync(Guid id, CreateOrEditCustomerProductDto input)
        {
            return await _customerProductsAppService.UpdateAsync(id, input);
        }

        [HttpDelete]
        [Route("Delete")]
        [Authorize]
        public async Task DeleteAsync(Guid id)
        {
            await _customerProductsAppService.DeleteAsync(id);
        }

        [HttpGet]
        [Route("GetListToSync")]
        [Authorize]

        public async Task<List<CustomerProductDto>> GetListToSync(DateTime? lastSync, string salesOrgCode, string customerCode, string salesRouteCode, int daysToSync)
        {
            return await _customerProductsAppService.GetListToSync(lastSync, salesOrgCode, customerCode, salesRouteCode, daysToSync);
        }

        [HttpGet]
        [Route("GetSerializedListToSync")]
        [Authorize]
        public async Task<ListResultWithDataVersionDto> GetSerializedListToSync(byte[] dataVersion, string salesOrgCode, string customerCode, string salesRouteCode, int daysToSync, int pageIndex, int pageSize)
        {
            return await _customerProductsAppService.GetSerializedListToSync(dataVersion, salesOrgCode, customerCode, salesRouteCode, daysToSync, pageIndex, pageSize);
        }

        [HttpPost]
        [Route("CastFromObject")]
        [Authorize]
        public CustomerProductDto CastFromObject(object obj)
        {
            return _customerProductsAppService.CastFromObject(obj);
        }
    }
}

@volethanh volethanh changed the title Many controllers take too long to start Many controllers in *.HttpApi take too long to load a project Mar 19, 2020
@maliming
Copy link
Member

Did you configure the correct redis connection string?

image

@volethanh
Copy link
Author

volethanh commented Mar 19, 2020

Redis is not the problem, I've tried again and this is the log.
Can you try to reproduce with many controllers in project *.HttpApi ?

logs_n_controllers1.txt

@maliming maliming added this to the 2.4 milestone Mar 23, 2020
@maliming
Copy link
Member

hi @hikalkan

When I add 300 controllers, the project launch will be very slow. It may take a few minutes or even longer.

// 0-300
[Route("api/testapi/test0api")]
public class Test0Controller : MyProjectNameController
{
	[HttpGet]
	[Route("Get")]
	[Authorize]
	public string TestMethod()
	{
		return "test";
	}
}


[Route("api/testapi/test1api")]
public class Test1Controller : MyProjectNameController
{
	[HttpGet]
	[Route("Get")]
	[Authorize]
	public string TestMethod()
	{
		return "test";
	}
}

//... more

I debugged and found that it seems that the EnableClassInterceptors method will take a long time.

And the time is constantly increasing(foreach (var service in services)).

(registrationBuilder as IRegistrationBuilder<TLimit, ConcreteReflectionActivatorData, TRegistrationStyle>)?.EnableClassInterceptors();

@maliming
Copy link
Member

@maliming
Copy link
Member

Wait for issues below:
autofac/Autofac.Extras.DynamicProxy#36
castleproject/Core#486

@maliming
Copy link
Member

@hikalkan

One possible solution is not to create a class proxy for the controller. That is, don't add interceptors to the controller. Because the controller's base class has too many methods and properties. It's complicated. Use middleware or filters.

@maliming
Copy link
Member

The advice given by castle(castleproject/Core#486 (comment)) is to avoid enabling proxy classes for controllers.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants