0

I'm trying to call an injected HttpClient during operations within a Razor Component. When I do so during OnInitialized, the return is as expected. When I do so on an event like an input change, the client call doesn't respond. I'm using a mix of MVC Controllers/Views with Razor Components in .Net Core 3.1.

Startup.cs

services.AddControllersWithViews()...
services.AddRazorPages()...

services.AddHttpClient<IJiraService, JiraService>("jira", c =>
            {
                c.BaseAddress = new Uri(Configuration.GetSection("ApplicationSettings:Jira:Url").Value);
                var auth =
                    $"{Configuration.GetSection("ApplicationSettings:Jira:UserName").Value}:{Configuration.GetSection("ApplicationSettings:Jira:Password").Value}";
                var authHeaderValue = Convert.ToBase64String(Encoding.UTF8.GetBytes(auth));

                c.DefaultRequestHeaders.AddAuthorization("Basic", authHeaderValue);
                c.Timeout = TimeSpan.FromSeconds(20);
                c.DefaultRequestHeaders.CacheControl = new CacheControlHeaderValue
                {
                    NoCache = true
                };
            });

ChildComponent.razor

@inject IJiraService JiraService

@code {
    public int SelectedReleaseId
    {
        get => ReleaseModel.SelectedReleaseId;
        set
        {
            ReleaseModel.SelectedReleaseId = value;
            ReleaseChanged().Wait();
        }
    }
}

@functions
{
    private async Task ReleaseChanged()
    {
        if (ReleaseModel.SelectedReleaseId > 0)
        {
            var url = "...";

            await JiraService.GetResponseAsync(url);
        }
    }

JiraService.cs

public async Task<string> GetResponseAsync(string url)
        {
            var resp = await httpClient.GetAsync(url); // <--- this is the call that never returns when invoked from an input control event
            var respContentString = await resp.Content.ReadAsStringAsync();
            if (resp.StatusCode != HttpStatusCode.OK)
            {
                throw new HttpOperationException(
                    $"Invalid response from Jira service: {resp.StatusCode}: {respContentString}");
            }

            return respContentString;
        }

There's actually a bit of service classing in between, but this is the jist. I've abstracted the call up to a parent component and implemented EventCallbacks all with the same result. The underlying call in the JiraService gets hit and i see a breakpoint stop on the await httpClient.GetAsync(url); but then execution just goes into the ether. There's not even an exception thrown or timeout.

ajamrozek
  • 160
  • 10
  • what are you expecting to happen when you call "await httpClient.GetAsync(url); " the resulting string does not seem to get allocated to anything – David Masterson Mar 02 '21 at 20:38
  • also why does your example have an code block And an functions block you should only need one the code block. functions is the old name for the code block before Blazor was officially released the functions block was changed to the code block, it still works for backward compatibility but is not the norm – David Masterson Mar 02 '21 at 20:43
  • @DavidMasterson, the GetAsync() will return a json string from it's content. See the subsequent line that reads it's Content `resp.Content.ReadAsStringAsync();` Why I used functions & code, no reason than ignorance. I've found examples of both and haven't seen a material difference in outcome. – ajamrozek Mar 02 '21 at 21:06

1 Answers1

0

It all seems so obvious now. The problem was a deadlock. This old post helped me realize that my property based @bind attribute was synchronously calling into an async/await graph. I refactored this into an @onchange function that enabled appropriate async/await behavior through the call stack and viola, await httpClient.GetAsync() behaved just like it should.

A little annoyed at the @bind behavior that takes the onchange event functionality in addition to the property value.

ajamrozek
  • 160
  • 10