question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Error 503. The service is unavailable (blazor server side)

See original GitHub issue

Describe the bug

Using HttpClient multiple times in a row causes responses to start lagging and eventually return HTTP Error 503. The service is unavailable despite the api service reporting no issues at all and keeps responding to other calls. Asp.net core version: 3.0.100-preview4-011223

To Reproduce

Please note that the code is a bit messy due to troubleshooting. Here’s the code: The service that is injected into the .razor page

public async Task<PagedResult<ProductViewModels.Details>> GetProductsAsync(int? pageIndex, int itemsPerPage)
        {
            var url = $"{_baseUrl}/products/list/{pageIndex},{itemsPerPage}";
            try
            {
                var response = await _client.GetAsync(url);

                if (response.IsSuccessStatusCode)
                {
                    var jsonString = await response.Content.ReadAsStringAsync();
                    var jObj = (JObject) JsonConvert.DeserializeObject(jsonString);

                    var paged =
                        JsonConvert.DeserializeObject<PagedResult<ProductViewModels.Details>>(
                            jObj["payLoad"].ToString());

                    return paged;
                }
                else
                {
                    var msg =
                        $"Unsuccessful request to {url} {response.StatusCode} {await response.Content.ReadAsStringAsync()}";
                    _logger.LogError(
                        msg);
                    throw new Exception(msg);
                }
            }
            catch (Exception e)
            {
                _logger.LogError($"Exception when trying to get product records from {url}", e);
                throw;
            }
        }`

The .razor page:

@page "/products"
@using Kiss.Application.Features.Products.ViewModels
@using Microsoft.AspNetCore.Components

<DataTable Items="@_products" TItem="ProductViewModels.Details">
    <HeaderTemplate>
        <th>Name</th>
        <th>Description</th>
    </HeaderTemplate>
    <RowTemplate Context="Item">
        <td>@Item.Name</td>
        <td>@Item.Description</td>
    </RowTemplate>
    <FooterTemplate Context="Item">
        <td colspan="2">@_itemsTotal products found.</td>
    </FooterTemplate>
</DataTable>
<Paginator ref="_paginator" LastPageIndex="@_lastPageIndex" />

@functions {
    private int _itemsPerPage = 5;
    private int _lastPageIndex = 0;

    private IEnumerable<ProductViewModels.Details> _products = new List<ProductViewModels.Details>();
    private int _itemsTotal = 0;

    private Paginator _paginator = new Paginator();

    [Inject] IProductService ProductService { get; set; }

    protected override void OnAfterRender()
    {
        _paginator.PageChanged += PageChangedEvent;
    }

    public async void PageChangedEvent(int pageIndex)
    {
        await UpdateProducts(pageIndex, _itemsPerPage);
    }

    protected override async Task OnInitAsync()
    {
        await UpdateProducts(0, _itemsPerPage);
    }

    private async Task UpdateProducts(int pageIndex, int itemsPerPage)
    {
        if (ProductService != null)
        {
            var result = await ProductService.GetProductsAsync(pageIndex, itemsPerPage);
            if (result != null)
            {
                _products = result.Items;
                _itemsTotal = result.ItemsTotal;
                _itemsPerPage = result.ItemsPerPage;
                _lastPageIndex = result.TotalPages - 1;
                StateHasChanged();
            }
        }
    }
}

The paginator that triggers the api calls

@using Microsoft.AspNetCore.Components
<div class="dataTables_paginate paging_simple_numbers" id="DataTables_Table_0_paginate">
    <ul class="pagination">
        <li class="paginate_button page-item previous @Disabled(0)" id="DataTables_Table_0_previous">
            <a aria-controls="DataTables_Table_0" data-dt-idx="0" tabindex="0" class="page-link" onclick="@FirstPage">First</a>
        </li>
        <li class="paginate_button page-item previous @Disabled(0)" id="DataTables_Table_0_previous">
            <a aria-controls="DataTables_Table_0" data-dt-idx="1" tabindex="0" class="page-link" onclick="@PreviousPage">Previous</a>
        </li>

        <li class="paginate_button page-item next @Disabled(LastPageIndex)" id="DataTables_Table_0_next">
            <a aria-controls="DataTables_Table_0" data-dt-idx="2" tabindex="0" class="page-link" onclick="@NextPage">Next</a>
        </li>
        <li class="paginate_button page-item next @Disabled(LastPageIndex)" id="DataTables_Table_0_next">
            <a aria-controls="DataTables_Table_0" data-dt-idx="3" tabindex="0" class="page-link" onclick="@LastPage">Last</a>
        </li>
    </ul>
</div>

@functions
{
    private int _currentPageIndex = 0;

    [Parameter]
    private int LastPageIndex { get; set; }

    [Parameter]
    public Action<int> PageChanged { get; set; }

    void ChangeCurrentPageIndex(int pageIndex)
    {
        if (pageIndex != _currentPageIndex)
        {
            _currentPageIndex = pageIndex;
            PageChanged?.Invoke(_currentPageIndex);
        }
    }

    string Disabled(int pageIndex)
    {
        return _currentPageIndex == pageIndex ? "disabled" : "";
    }

    void FirstPage()
    {
        ChangeCurrentPageIndex(0);
    }

    void NextPage()
    {
        if (_currentPageIndex < LastPageIndex)
        {
            ChangeCurrentPageIndex(_currentPageIndex + 1);
        }
    }

    void PreviousPage()
    {
        if (_currentPageIndex > 0)
        {
            ChangeCurrentPageIndex(_currentPageIndex - 1);
        }
    }

    void LastPage()
    {
        ChangeCurrentPageIndex(LastPageIndex);
    }
}

Startup.cs:

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Log.Logger = new LoggerConfiguration().ReadFrom.Configuration(configuration).CreateLogger();
        }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddHttpClient();
            services.AddScoped<HttpClient>(s =>
            {
                // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
                var uriHelper = s.GetRequiredService<IUriHelper>();
                return new HttpClient
                {
                    BaseAddress = new Uri(uriHelper.GetBaseUri())
                };
            });
            services.AddScoped<IProductService, ProductService>();

            services.AddRazorPages();
            services.AddServerSideBlazor();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            loggerFactory.AddSerilog();
            app.UseHttpsRedirection();

            app.UseStaticFiles();

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }

Symptom

After the page loads the table of records loads correctly. When clicking on Next and Previous repeatedly to go back and forth (not particularly fast), it takes about 3 iterations for the response to start lagging and eventually stop with an error. I hard coded the api endpoint and tried it in isolation and it’s responding very quickly without any issues (hardcoded or not). I’ve searched a lot to see if my setup is incorrect but can’t find anything that would suggest so at this point. One minor thing to note is that the event handler in the products.razor page is async void, which I thought may be a reason.

Exceptions Thrown

[2019-05-06T20:23:43.734Z] Error: System.Exception: Unsuccessful request to http://localhost/kiss.api/products/list/0,5 ServiceUnavailable <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN""http://www.w3.org/TR/html4/strict.dtd">
<HTML><HEAD><TITLE>Service Unavailable</TITLE>
<META HTTP-EQUIV="Content-Type" Content="text/html; charset=us-ascii"></HEAD>
<BODY><h2>Service Unavailable</h2>
<hr><p>HTTP Error 503. The service is unavailable.</p>
</BODY></HTML>

   at Kiss.Web.Services.ProductService.GetProductsAsync(Nullable`1 pageIndex, Int32 itemsPerPage) in C:\dev\TVProjects\Kiss\Kiss.Web\Services\ProductService.cs:line 54
   at Kiss.Web.Pages.Products.UpdateProducts(Int32 pageIndex, Int32 itemsPerPage) in C:\dev\TVProjects\Kiss\Kiss.Web\Pages\Products.razor:line 50
   at Kiss.Web.Pages.Products.PageChangedEvent(Int32 pageIndex) in C:\dev\TVProjects\Kiss\Kiss.Web\Pages\Products.razor:line 38
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__139_0(Object state)
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteSynchronously(TaskCompletionSource`1 completion, SendOrPostCallback d, Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext.ExecuteBackground(WorkItem item)

and

blazor.server.js:1 Uncaught (in promise) Error: Cannot send data if the connection is not in the 'Connected' State.
    at e.send (blazor.server.js:1)
    at e.sendMessage (blazor.server.js:1)
    at e.send (blazor.server.js:1)
    at Object.beginInvokeDotNetFromJS (blazor.server.js:8)
    at c (blazor.server.js:8)
    at Object.s [as invokeMethodAsync] (blazor.server.js:8)
    at blazor.server.js:8
    at e.onEvent (blazor.server.js:8)
    at e.onGlobalEvent (blazor.server.js:8)

Expected behavior

Since the api service is working fine, the expectation is that I should be able to use the pagination to go back and forth without a degradation/lagging and eventually error that requires a page reload.

Screenshots

image

Additional context

This is the first time I post on GitHub, hope I did it right and hope for a solution. Apologies if I made a mistake here.

Thanks

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:24

github_iconTop GitHub Comments

2reactions
islandmanllccommented, May 6, 2019

Ok, problem resolved. My bad. The issue was with OnAfterRender. This is of course triggered multiple times. The solution to this problem is as follows:

Pass in the event handler as a param to the child:

<Paginator ref="@_paginator" OnPageChangeEvent="@PageChangedEventAsync" LastPageIndex="@_lastPageIndex" />

Remove the OnAfterRender override method.

`` Invoke the passed in event handler of the parent in the child:

    {
        if (pageIndex != _currentPageIndex)
        {
            _currentPageIndex = pageIndex;
            OnPageChangeEvent?.Invoke(_currentPageIndex);
        }
    }

Thanks! This can be closed.

0reactions
islandmanllccommented, May 6, 2019

Misuse by registering parent component event handler to child component in parent OnAfterRender instead of passing in the parent component event handler as a param to the child component.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Error 503. The service is unavailable (blazor server side)
The service is unavailable despite the api service reporting no issues at all and keeps responding to other calls.
Read more >
Blazor 503 The service is unavailable on IIS10 with ...
I am still unable to get my Blazor app to work. As suggested, I built a sample app to test with and see...
Read more >
How to fix HTTP Error 503 – The service is unavailable
The primary reason for this error is a stopped or disabled application pool. The application pool is the IIS component that initiates a...
Read more >
Can't deploy a Blazor server side app on Azure using ...
We see always the service " HTTP Error 503. The service is unavailable. " We installation the Extensions with the version ASP.
Read more >
Azure App service get 503 The service is unavailable.
This indicates that your application crashed, unexpectedly finished or didn't expose/listen to the correct TCP port. But I have a doubt about the...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found