I have a Blazor WASM app deployed to an Azure Static Web app with a managed .NET 8 isolated Azure Function API. When calling the API directly from Postman using the auto-generated web app URL + the API route I receive the expected response and can see a log in Application Insights. However when I call the same endpoint from within the deployed WASM application I receive an net::ERR_CONNECTION_REFUSED
response and a request isn’t recorded in Application Insights. I have confirmed that this is functioning as expected locally.
The successful postman request:
The Log in application insights:
My appsettings.json
file that is packaged with the Blazor WASM app:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ApiBase": "http://localhost:7071"
}
The launchSettings.json
of the Azure Function App API:
{
"profiles": {
"Project.Api": {
"commandName": "Project",
"commandLineArgs": "--port 7071",
"launchBrowser": false
}
}
}
The Azure Function app is deployed to the Azure Static Web App and the SendContactEmailFunction
function is registered in Azure:
The error I receive in the console from the deployed Blazor WASM app:
How the HttpClient
is registered:
var apiBase = builder.Configuration["ApiBase"]
?? throw new ArgumentException("API base address not found in config.");
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(apiBase) });
The code that is calling the API function:
var response = await HttpClient.PostAsJsonAsync("/api/send-contact-email", sendEmailRequest);
The Azure function code:
public class SendContactEmailFunction(ILoggerFactory loggerFactory, ISender sender)
{
private readonly ILogger logger = loggerFactory.CreateLogger<SendContactEmailFunction>();
[Function(nameof(SendContactEmailFunction))]
public async Task<HttpResponseData> Run(
[HttpTrigger(AuthorizationLevel.Function, "post", Route = "send-contact-email")] HttpRequestData req,
FunctionContext executionContext, CancellationToken cancellationToken)
{
logger.LogInformation($"{nameof(SendContactEmailFunction)} function received a request.");
var requestBody = await new StreamReader(req.Body).ReadToEndAsync(cancellationToken);
var request = JsonConvert.DeserializeObject<SendContactEmailRequest>(requestBody);
HttpResponseData response;
try
{
if (request == null)
{
throw new ApplicationException("Unable to deserialize response.");
}
var emailCommand = new SendContactEmailCommand(
request.Name,
request.FromEmail,
request.Message,
request.RecaptchaResponse);
var sendEmailResult = await sender.Send(emailCommand, cancellationToken);
if (sendEmailResult.IsFailure)
{
logger.LogError("Send email command failed. Error: {Error}", sendEmailResult.Error.Message);
response = req.CreateResponse(HttpStatusCode.BadRequest);
var error = new ErrorResponse
{
Code = (int)HttpStatusCode.BadRequest,
Message = sendEmailResult.Error.Message
};
await response.WriteAsJsonAsync(error, cancellationToken);
}
else
{
response = req.CreateResponse(HttpStatusCode.OK);
await response.WriteAsJsonAsync("", cancellationToken: cancellationToken);
}
}
catch (Exception e)
{
logger.LogError(e, "Exception occured. Error: '{Message}'", e.Message);
response = req.CreateResponse(HttpStatusCode.InternalServerError);
await response.WriteAsJsonAsync(ErrorResponse.Generic, cancellationToken);
}
return response;
}
}
2
Answers
I was able to get this working but I'm not quite sure what solved this in the end out of the two things I tried:
I deleted and recreated the Azure Static Web App.
I added a conditional check for hosting environment in the
Program.cs
file for the API base address. If in development - user the Function App URI from theappsettings.json
. If not use the hosting environment base address:string apiBase; if (builder.HostEnvironment.IsDevelopment()) { apiBase = builder.Configuration["ApiBase"] ?? throw new ArgumentException("API base address not found in config."); } else { apiBase = builder.HostEnvironment.BaseAddress; }
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(apiBase) });
I’m just learning how to program with C#/Blazor so take this as you will. Why would the app be using the ApiBase of http://localhost:7071 when running as the Azure SWA? Shouldn’t that be relative such that the static web app url is substituted?