背景:
我们已经构建了一个与ASP.NET Web API 2后端。NET Framework 4.6.1
通信的React SPA。在初始加载时,我们将发出两个单独的请求以加载数据。当加载大量数据时,我们注意到与在Postman中单独尝试请求相比,在应用程序中创建API请求的速度都慢得多。
原始
:示例结构,提取当然使用我们的API:
fetch('http://example.com/movies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
fetch('http://example.com/otherMovies.json')
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(JSON.stringify(myJson));
});
示例C#API方法:
[HttpGet]
[Route("{bsid}/{caseId}")]
public IHttpActionResult GetRenewalCycleForCustomer(string bsid, int caseId)
{
var customerNumbers = GetCustomerNumbers();
var userId = HttpContext.Current.User.Identity.GetUserId<int>();
var user = identityDb.Users.Find(userId);
var customerNumbers = user.ApplicationUserCustomerNumbers.Select(x => new CustomerNumberKey() { bsid = x.CustomerNumber.bsid, NameNo = x.CustomerNumber.NameNo }).ToList();
var db = new DbContext();
var caseService = new CaseService(db);
var portfolioTabViewModel = caseService.GetPortfolioTabViewModelForCustomer(bsid, caseId, customerNumbers);
return Ok(portfolioTabViewModel);
}
操作系统是Windows 10 Pro,根据Internet,IIS应该能够处理10个并发连接。没关系,因为我们将其作为Windows Server托管在Azure上,并且那里的响应时间相同。也尝试了App Service,结果是相同的。
与Postman Runner同步测试响应时间
两个Postman Runner实例同时运行:
其他说明:
似乎与硬件无关,因为无论是否同时发出请求,CPU,内存和磁盘都不会受到明显影响。
该如何解决?
似乎异步运行的非异步方法:
https://stackoverflow.com/a/26737847/3850405
某些线程建议使用会话状态,但是在Web.config
中找不到对此的任何引用,并且我没有启用任何引用。搜索HttpContext.Current.SetSessionStateBehavior
得到0个结果。
https://stackoverflow.com/a/26172317/3850405
Windows 10资源:
https://serverfault.com/a/800518/293367
https://forums.asp.net/t/2100558.aspx?concurrent+connections+on+windows+pro+10+IIS
更新异步和IIS:
它似乎与异步或IIS不相关,已通过以下方法测试了并发请求。并发的慢速请求似乎还取决于其他因素。
异步:
[HttpGet]
[Route("{bsid}/{caseId}")]
public async Task<IHttpActionResult> Get(string bsid, int caseId)
{
await Task.Delay(3000);
return Ok();
}
同步:
[HttpGet]
[Route("{bsid}/{caseId}")]
public IHttpActionResult Get(string bsid, int caseId)
{
Thread.Sleep(3000);
return Ok();
}
更新2:具有异步和同步调用的数据库:
似乎也不是数据库调用。使用Include
进行的测试在速度上相似,尽管异步调用的速度相当慢。
异步:
[HttpGet]
[Route("{bsid}/{caseId}/async")]
public async Task<IHttpActionResult> GetAsync(string bsid, int caseId)
{
var db = new DbContext();
var deviations = await db.RenewalCycles.Where(x => x.Deviations.Any())
.Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPName))
.Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPNameType))
.Include(cycle => cycle.TPCase.GoodsAndServicesDescriptions)
.Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCaseRelation))
.Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCountry))
.ToListAsync();
return Ok();
}
同步:
[HttpGet]
[Route("{bsid}/{caseId}")]
public IHttpActionResult Get(string bsid, int caseId)
{
var db = new DbContext();
var deviations = db.RenewalCycles.Where(x => x.Deviations.Any())
.Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPName))
.Include(cycle => cycle.TPCase.CaseNames.Select(caseName => caseName.TPNameType))
.Include(cycle => cycle.TPCase.GoodsAndServicesDescriptions)
.Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCaseRelation))
.Include(cycle => cycle.TPCase.RelatedCases.Select(relatedCase => relatedCase.TPCountry))
.ToList();
return Ok();
}
答案 0 :(得分:0)
毕竟市长的开销部分与数据库有关。一种方法使用db.Cases.Find(bsid, caseId)
,然后将模型转换为视图模型。 Cases
模型又有很多关系,由于模型具有标记为virtual
的属性,所有这些关系都需要发出单独的数据库调用,例如public virtual TPRenewalCycle TPRenewalCycle { get; set; }
这样就可以进行延迟加载。通过查看Visual Studio输出窗口(调试-> Windows->输出)并按如下所示设置ApplicationDbContext来找到它。
public class ApplicationDbContext : DbContext
{
protected const string ConnectionStringName = "defaultConnection";
public ApplicationDbContext() : base(ConnectionStringName)
{
Database.Log = s => System.Diagnostics.Debug.WriteLine(s);
Database.CommandTimeout = 300;
}