Search code examples
httpclientmaui.net-maui

How do I properly use DI with IHttpClientFactory in .NET MAUI


I haven't found anything about HttpClient in .NET MAUI.

Does anyone know if the service: builder.Services.AddHttpClient<IMyService, MyService>(); is possible in MAUI's startup MauiProgram.cs? And then inject HttpClient to where it's going to be used. I have tried everything and it does not seem to work. Only AddSingleton of HttpClient works for me, but it doesn't seem optimal.

PS.: I had to install nuget package Microsoft.Extensions.Http in order to use the AddHttpClient service.

UPDATES:

WORKING CODE:

MauiProgram.cs

builder.Services.AddTransient<Service<Display>, DisplayService>();
builder.Services.AddTransient<Service<Video>, VideoService>();
builder.Services.AddTransient<Service<Image>, ImageService>();
builder.Services.AddTransient<Service<Log>, LogService>();

builder.Services.AddSingleton(sp => new HttpClient() { BaseAddress = new Uri("https://api.myapi.com") });

Example of VideosViewModel.cs using a service

[INotifyPropertyChanged]
public partial class VideosViewModel
{
    readonly Service<Video> videoService;
    
    [ObservableProperty]
    ObservableCollection<Video> videos;

    [ObservableProperty]
    bool isEmpty;
    
    [ObservableProperty]
    bool isRefreshing;
    
    public VideosViewModel(Service<Video> videoService)
    {
        this.videoService = videoService;
    }

    [ICommand]
    internal async Task LoadVideosAsync()
    {
#if ANDROID || IOS || tvOS || Tizen
        UserDialogs.Instance.ShowLoading("Henter videoer fra databasen...");
#endif
        await Task.Delay(2000);
        
        Videos = new();

        try
        {
            await foreach (Video video in videoService.GetAllAsync().OrderBy(x => x.Id))
            {
                Videos.Add(video);
            }
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
        finally
        {
            IsRefreshing = false;
#if ANDROID || IOS || tvOS
            UserDialogs.Instance.HideLoading();
#endif

            if (Videos.Count is 0)
            {
                IsEmpty = true;
            }
            else
            {
                IsEmpty = false;
            }
        }
    }
    
    [ICommand]
    async Task UploadVideoAsync()
    {
        await Shell.Current.DisplayAlert("Upload en video", "Under opbygning - kommer senere!", "OK");
    }
}

NOT WORKING CODE:

MauiProgram.cs

builder.Services.AddHttpClient<Service<Display>, DisplayService>(sp => sp.BaseAddress = new Uri("https://api.myapi.com"));
builder.Services.AddHttpClient<Service<Video>, VideoService>(sp => sp.BaseAddress = new Uri("https://api.myapi.com"));
builder.Services.AddHttpClient<Service<Image>, ImageService>(sp => sp.BaseAddress = new Uri("https://api.myapi.com"));
builder.Services.AddHttpClient<Service<Log>, LogService>(sp => sp.BaseAddress = new Uri("https://api.myapi.com"));

VideosViewModel.cs Same as above working code.

What specifically doesn't work is that I get object reference exception on OrderBy(x => x.Id), specifically highlighted x.Id in ViewModel. Removing OrderBy method gives no longer exceptions, but the view shows no data except one random empty Frame.


Solution

  • Do not use builder.Services.AddHttpClient in MAUI. Use one instance.