skip to Main Content

I am trying to impelement a streamign API in Azure Web App application.
I was able to build a Proof of Concept in a regular application (Blazor Wasm and Azure Function) but not configured as SWA. It worked just fine. When copying the same code to the SWA, it is not working (i.e. streaming is not working, the value comes ones at the completion rather than stream as we go).

Any suggestions whay might be going on?

Here is the code I have for the Azure function

        [Function("GetItems")]
        public static async Task<HttpResponseData> Run(
              [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequestData req,
              FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("GetItemsFunction");
            logger.LogInformation("C# HTTP trigger function processed a request.");

            // Create a response
            var response = req.CreateResponse(System.Net.HttpStatusCode.OK);
            response.Headers.Add("Content-Type", "text/event-stream");
            // Add CORS headers
            response.Headers.Add("Access-Control-Allow-Origin", "*");
            response.Headers.Add("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
            response.Headers.Add("Access-Control-Allow-Headers", "Content-Type");

            // Start the stream
            await using (var writer = new StreamWriter(response.Body))
            {
                var items = new[] { "Item 1", "Item 2", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 4", "Item 3", "Item 2", "Item 1" };

                foreach (var item in items)
                {
                    await writer.WriteLineAsync($"data: {item}");
                    await writer.FlushAsync();
                    await Task.Delay(1000); // Simulate delay
                }
            }

            return response;
        }

And Here is the code in the Blazor wasm Razor page

@page "/items"
@inject StreamingApiService StreamingApiService

<h3>Streaming Data</h3>

@if (streamedData == null)
{
    <p><em>Loading...</em></p>
}
else
{
    <ul>
        @foreach (var item in streamedData)
        {
            <li>@item</li>
        }
    </ul>
}

@code {
    private List<string> streamedData;

    protected override async Task OnInitializedAsync()
    {
        streamedData = new List<string>();

        await foreach (var item in StreamingApiService.GetStreamedData())
        {
            streamedData.Add(item);
            StateHasChanged();
        }
    }
}

And this is a helper class I am using

using Microsoft.AspNetCore.Components.WebAssembly.Http;
using System.Text.Json;

namespace ClientApp;

public class StreamingApiService
{
    private readonly HttpClient _httpClient;

    public StreamingApiService(HttpClient httpClient)
    {
        _httpClient = httpClient;
    }

    public async IAsyncEnumerable<string> GetStreamedData()
    {
        using var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost:7181/api/GetChat");
        request.SetBrowserResponseStreamingEnabled(true);

        using var response = await _httpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
        response.EnsureSuccessStatusCode();

        using var stream = await response.Content.ReadAsStreamAsync();
        using var reader = new StreamReader(stream);

        string line;
        while ((line = await reader.ReadLineAsync()) != null)
        {
            // Deserialize the line into a MyDataItem object
            yield return line;
        }
    }
}

2

Answers


  1. Chosen as BEST ANSWER

    I found the fix to simply use .ConfigureFunctionsWebApplication() in the program.cs of the API project instead of ConfigureFunctionsWorkerDefaults() to make it use ASP.NET Core Integration


  2. Below are the steps to create a Stream API in Azure Static Web Apps using an Azure Function App.

    I followed this link to build Blazor and C# APIs in Azure Static Web Apps.

    App.js:

    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <RouteView RouteData="routeData" DefaultLayout="typeof(MainLayout)" />
            <FocusOnNavigate RouteData="routeData" Selector="h1" />
        </Found>
        <NotFound>
            <LayoutView Layout="typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
    
    @code {
        protected override async Task OnInitializedAsync()
        {
         
        }
    }
    

    Program.cs:
    I have registered and configured the StreamingApiService class using the AddScoped method in Program.cs

     builder.Services.AddScoped(abc => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });
     builder.Services.AddScoped<StreamingApiService>();
     await builder.Build().RunAsync();
    
    • I have added the Azure Function App Git folder structure according to this link.
    • You can configure CORS in the local.settings.json of Function App :
     "Host": { "CORS": "*" }
    

    enter image description here

    Change the Git yml according to your folder structure:

     app_location to  "./BlazorApp" 
     api_location to  "./FunctionApp1"
     output_location to  "wwwroot" 
    

    Refer to this Stack Overflow post for the YAML workflow file of Static Web App.
    Deployment Status in git:

    enter image description here

    Azure Static Output:
    enter image description here

    Azure Functions app Output in Azure Static:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search