I’m trying to figure out how Promises work with multiple HTTPS requests in Javascript, but I have a problem where the results seem out of order with the request sequence. I’m using an ASP.NET Controller API implementation for a simple calculator, and Javascript to access the API. I seem to have a synchronization issue, but I can’t for the life of me work out why.
The CalculatorController
:
using Microsoft.AspNetCore.Mvc;
namespace Wolflight.Calculator.Controllers
{
[ApiController]
[Route("[controller]")]
public class CalculatorController : Controller
{
private const string TotalName = "Total";
private decimal RetrieveTotal()
{
return ToDecimal(HttpContext.Session.GetString(TotalName));
}
private void StoreTotal(decimal value)
{
HttpContext.Session.SetString(TotalName, FromDecimal(value));
}
private static string FromDecimal(decimal value)
{
return value.ToString();
}
private static decimal ToDecimal(string? value)
{
if (value != null)
{
return Decimal.Parse(value);
}
else
{
return 0M;
}
}
[HttpGet()]
[Route("/api/Calculator/Total")]
public decimal? GetTotal()
{
return RetrieveTotal();
}
[HttpPut()]
[Route("/api/Calculator/Add")]
public void AddValue(decimal value)
{
StoreTotal(RetrieveTotal() + value);
}
[HttpPut()]
[Route("/api/Calculator/Subtract")]
public void SubtractValue(decimal value)
{
StoreTotal(RetrieveTotal() - value);
}
[HttpPut()]
[Route("/api/Calculator/Multiply")]
public void MultiplyValue(decimal value)
{
StoreTotal(RetrieveTotal() * value);
}
[HttpPut()]
[Route("/api/Calculator/Divide")]
public void DivideValue(decimal value)
{
StoreTotal(RetrieveTotal() / value);
}
}
}
The site.js
:
const uriBase = "/api/Calculator/";
const uriTotal = uriBase + "Total";
const uriAdd = uriBase + "Add";
let GetTotalValuePromise = function () {
return new Promise(function (myResolve, myReject) {
let total = fetch(uriTotal)
.then(response => response.text())
.catch(error => myReject('Unable to get total.', error));
myResolve(total);
})
};
let PutAddValuePromise = function (addValue) {
return new Promise(function (myResolve, myReject) {
fetch(uriAdd + '?value=' + addValue, { method: 'PUT' })
.catch(error => myReject('Unable to add value.', error));
myResolve();
}
)
};
function DisplayTotal(total) {
const tBody = document.getElementById('totalDisplay');
tBody.innerHTML = total;
}
function GetTotal() {
UpdateDisplay();
}
function AddValue() {
let value = document.getElementById('addValue').value;
PutAddValuePromise(value)
.then(function () {
UpdateDisplay();
});
}
function UpdateDisplay() {
GetTotalValuePromise()
.then(
function (total) { DisplayTotal(total); },
function (message, error) { console.error(message, error); }
)
}
When I call AddValue()
from a form button, the result is that sometimes the /Total
call returns the value before the /Add
occurs, and sometimes it returns the result after.
e.g.
Total
=0
- Call
AddValue
, with elementaddValue
as 5.
Network Requests:
/Add?value=5
(no response)/Total
– Response:0
.
OR
Network Requests:
/Add?value=5
(no response)/Total
– Response:5
.
Am I missing something in how Promises work, or is the problem on the server side?
If I call GetTotal
manually after the AddValue
, it always returns the correct value.
2
Answers
You could try this below code. The issue you’re facing this issue becaus new vlaue i snot being saved in the session and it is restyrning the old value before that.
To resolve this, add HttpContext.Session.CommitAsync().Wait() to ensure that the session state is persisted immediately after updating the total. use async/await in the clinetside code to execute the requests in the correct order, ensuring that the total is fetched only after the server has completed updating it.
Updated server-side code:
Client-side JavaScript:
Program.cs: