我如何与.net Maui中的IhttpClientFactory正确使用DI

发布于 2025-01-29 21:05:13 字数 3246 浏览 1 评论 0 原文

我在.net Maui中还没有发现有关HTTPCLIENT的任何信息。

有人知道该服务是否: builder.services.addhttpclient< imyservice,myService>(); 在毛伊岛的启动Mauipragram.cs中可以吗?然后将HTTPClient注入将要使用的位置。我已经尝试了所有事情,但它似乎不起作用。仅添加httpclient的Singleton对我有效,但似乎并不最佳。

ps。:我必须安装nuget软件包microsoft.extensions.http,以便使用AddHttpClient服务。

更新

工作代码:

mauipragram.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") });

videosviewmodel.cs使用服务的示例

[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");
    }
}

不工作代码:

mauipragram.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 与上述工作代码相同。

具体不起作用的是,我在orderby(x =&gt; x.id)上获得对象参考异常,特别是在ViewModel中突出显示X.ID。删除Orderby方法不再例外,但是视图没有显示一个随机空帧以外的数据。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

星星的轨迹 2025-02-05 21:05:13

请勿使用Builder.Services.AddhttpClient在MAUI中。
使用一个实例。

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

悟红尘 2025-02-05 21:05:13

Builder.Services.AddhttpClient为我工作。这是我设置矿山的方式:在主程序中,我添加了.addhttpclient()

public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder.Services.AddHttpClient();
    builder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
        });

 #if DEBUG
    builder.Logging.AddDebug();
 #endif

    return builder.Build();
}
}

和appshell.xaml,我删除了DataTemplate的定义,使其像这样:

<Shell
    x:Class="MAUIMultiPage.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MAUIMultiPage"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
        x:Name="homepage"
        Title="Home"
         />
        <ShellContent
        x:Name="specialOpsPage"
        Title="Special Ops"
         />

    </TabBar>

</Shell>

请注意,请注意我给ShellContents的X:名称。 DataTemplates在AppShell.xAML背后的代码中定义了,我可以将Func对象与IHTTPCLIENTFACTORY作为DI参数,看起来像这样:

public partial class AppShell : Shell
{
    public AppShell(IHttpClientFactory httpClientFactory)
    {
        InitializeComponent();

        homepage.ContentTemplate = new DataTemplate(() => new MainPage(httpClientFactory));
        specialOpsPage.ContentTemplate = new DataTemplate(() => new SpecialOps(httpClientFactory));
    }
}

对于App类,我们可以注入IHTTPCLIENTFACTORY,它可以将其传递给Appshell:

public partial class App : Application
{
    public App(IHttpClientFactory httpClientFactory)
    {
        InitializeComponent();

        MainPage = new AppShell(httpClientFactory);
    }
}

以及每个人。页面我将在我的github存储库中获得IHTTPCLIENTFACTORY

  public partial class SpecialOps : ContentPage
   {
    private readonly IHttpClientFactory _httpClientFactory;

        public SpecialOps(IHttpClientFactory httpClientFactory)
        {
            InitializeComponent();
            this._httpClientFactory = httpClientFactory;
        }
    
        private async void Button_Clicked(object sender, EventArgs e)
        {
            var httpClient = _httpClientFactory.CreateClient();
            var result = await httpClient.GetAsync("https://dummy.restapiexample.com/api/v1/employees");
            txtResult.Text = await result.Content.ReadAsStringAsync();
        }
    }

一个完整的解决方案:

builder.Services.AddHttpClient works for me. Here is how I setup mine: in the main program, I added .AddHttpClient()

public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
    var builder = MauiApp.CreateBuilder();
    builder.Services.AddHttpClient();
    builder
        .UseMauiApp<App>()
        .ConfigureFonts(fonts =>
        {
            fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
            fonts.AddFont("OpenSans-Semibold.ttf", "OpenSansSemibold");
        });

 #if DEBUG
    builder.Logging.AddDebug();
 #endif

    return builder.Build();
}
}

And in AppShell.xaml I removed the DataTemplate definition, made it barebone like this:

<Shell
    x:Class="MAUIMultiPage.AppShell"
    xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:local="clr-namespace:MAUIMultiPage"
    Shell.FlyoutBehavior="Disabled">

    <TabBar>
        <ShellContent
        x:Name="homepage"
        Title="Home"
         />
        <ShellContent
        x:Name="specialOpsPage"
        Title="Special Ops"
         />

    </TabBar>

</Shell>

Notice that I gave an x:Name to the ShellContents. The DataTemplates are defined in the code behind of AppShell.xaml where I can pass a Func object with IHttpClientFactory as a DI parameter, which looks like this:

public partial class AppShell : Shell
{
    public AppShell(IHttpClientFactory httpClientFactory)
    {
        InitializeComponent();

        homepage.ContentTemplate = new DataTemplate(() => new MainPage(httpClientFactory));
        specialOpsPage.ContentTemplate = new DataTemplate(() => new SpecialOps(httpClientFactory));
    }
}

For the App class we can inject IHttpClientFactory, which is passed to AppShell:

public partial class App : Application
{
    public App(IHttpClientFactory httpClientFactory)
    {
        InitializeComponent();

        MainPage = new AppShell(httpClientFactory);
    }
}

And in each individual page I would have iHttpClientFactory available from the Func DI parameter

  public partial class SpecialOps : ContentPage
   {
    private readonly IHttpClientFactory _httpClientFactory;

        public SpecialOps(IHttpClientFactory httpClientFactory)
        {
            InitializeComponent();
            this._httpClientFactory = httpClientFactory;
        }
    
        private async void Button_Clicked(object sender, EventArgs e)
        {
            var httpClient = _httpClientFactory.CreateClient();
            var result = await httpClient.GetAsync("https://dummy.restapiexample.com/api/v1/employees");
            txtResult.Text = await result.Content.ReadAsStringAsync();
        }
    }

A complete solution for this example is in my GitHub repository: https://github.com/yogigrantz/MAUIWithHttpClientFactory

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文