在WPF应用程序中使用IHttpClientFactory创建HttpClient时如何访问ProgressMessageHandler?

问题描述 投票:0回答:1

这里我有

HttpClient
报告进度:

var handler = new HttpClientHandler() { AllowAutoRedirect = true };
var ph = new ProgressMessageHandler(handler);

ph.HttpReceiveProgress += (_, args) =>
{
    //Do stuff that I would also like to do with the DI approach.
};

var client = new HttpClient(ph);
client.BaseAddress = new Uri("https://localhost:7145/");
HttpRequestMessage requestMessage = new(HttpMethod.Get, "DownloadFile");
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", _tokenConfig.AccessToken);
var response = await client.SendAsync(requestMessage);

这段代码工作正常,我可以读取下载进度,但现在我想从我的类中删除

HttpClient
初始化,而是注入 Microsoft 的好人提供的
IHttpClientFactory
。到目前为止,我发现我可以在我的启动类中这样配置它:

services.AddTransient<ProgressMessageHandler>();
services.AddHttpClient("api", opt =>
{
    opt.BaseAddress = new Uri(configuration.GetValue<string>("HttpClientConfig:BaseUrl"));
})
.AddHttpMessageHandler<ProgressMessageHandler>()
.ConfigurePrimaryHttpMessageHandler(() =>
{
    return new HttpClientHandler()
    {
        AllowAutoRedirect = false,
        UseDefaultCredentials = true
    };
});

然后注射到我想要的任何地方。现在我的问题是,既然我使用 DI 方法,我如何以及在哪里可以访问

HttpReceiveProgress

var client = _httpClientFactory.CreateClient("api"); 

而不是第一种更传统的方法?

c# dotnet-httpclient
1个回答
0
投票

如果我理解正确,您手动创建了

HttpClientHandler
和 [
ProgressMessageHandler
]'https://learn.microsoft.com/en-us/previous-versions/aspnet/hh995279(v=vs.118 ),并连接到
HttpReceiveProgress
事件来处理进度报告。

   +------------------------+        +---------------------+
   | HttpClientHandler      |        |  ProgressMessage    |
   | (AllowAutoRedirect)    |------->|  Handler(ph)        |
   +------------------------+        +----------+----------+
                                              |  HttpReceiveProgress Event
                                              v
                                       Your Event Handler
                                           (//Do stuff)

您正在启动类中定义一个具有特定配置的命名客户端“

api
”和一个
ProgressMessageHandler

您想要使用
HttpClient
 创建一个 
IHttpClientFactory
实例并从
HttpReceiveProgress
访问
ProgressMessageHandler
事件。

在阅读了 “.NET 中可用的原始 HttpClient 类的问题”之后,我看到了 Typed Client 的概念,它本质上是一个接受

HttpClient
对象(通过其构造函数注入)并使用它来与一些远程 HTTP 服务交互。

当您使用

IHttpClientFactory
注册和配置类型化客户端时,您正在设置一种更加结构化和可管理的方式来处理应用程序中的 HTTP 通信。该方法还允许您在类型化客户端类中封装任何附加逻辑,例如进度报告。

您可能会考虑采用类型化客户端模式来封装您的

ProgressMessageHandler
逻辑。
例如,您可以创建一个接受
HttpClient
和自定义进度处理程序的类型化客户端类。
这样,您就可以以结构化且 DI 友好的方式管理进度报告逻辑以及 HTTP 通信逻辑。

首先创建一个自定义进度处理程序类:

public class CustomProgressHandler : ProgressMessageHandler
{
    public CustomProgressHandler(HttpMessageHandler innerHandler) : base(innerHandler)
    {
    }

    public event EventHandler<HttpProgressEventArgs> ReceiveProgress
    {
        add { HttpReceiveProgress += value; }
        remove { HttpReceiveProgress -= value; }
    }
}

然后定义一个通过构造函数注入接受

HttpClient
CustomProgressHandler
的 Typed Client 类:

public class DownloadService : IDownloadService
{
    private readonly HttpClient _httpClient;
    private readonly CustomProgressHandler _progressHandler;

    public DownloadService(HttpClient httpClient, CustomProgressHandler progressHandler)
    {
        _httpClient = httpClient;
        _progressHandler = progressHandler;
        _progressHandler.ReceiveProgress += HandleProgress;
    }

    private void HandleProgress(object sender, HttpProgressEventArgs e)
    {
        // Do stuff
    }

    public async Task DownloadFileAsync()
    {
        HttpRequestMessage requestMessage = new(HttpMethod.Get, "DownloadFile");
        // your code
        var response = await _httpClient.SendAsync(requestMessage);
    }
}

// In Startup.cs or Program.cs
services.AddTransient<CustomProgressHandler>();
services.AddHttpClient<IDownloadService, DownloadService>()
    .AddHttpMessageHandler<CustomProgressHandler>();

CustomProgressHandler
封装了
ProgressMessageHandler
逻辑。
DownloadService
是一个类型化客户端,通过构造函数注入接受
HttpClient
CustomProgressHandler

您将
CustomProgressHandler
DownloadService
注册到
IHttpClientFactory
,将
CustomProgressHandler
链接为消息处理程序。


注意:在 Windows Presentation Foundation (WPF) 的上下文中,依赖项注入 (DI) 并未像 ASP.NET Core 中那样无缝集成。
您需要设置一个 DI 容器,例如Autofac,如在此处看到,或Unity,然后注册并解析依赖项。创建类型化客户端和自定义进度处理程序的核心思想仍然适用,但根据您为 WPF 应用程序选择的 DI 框架,注册和注入过程可能看起来有所不同。

使用 Autofac 作为 DI 容器 (

Install-Package Autofac
):

定义您的

CustomProgressHandler
DownloadService
类,如上例所示,并在 WPF 应用程序中设置 DI 容器:

public class Bootstrapper
{
    public IContainer Bootstrap()
    {
        var builder = new ContainerBuilder();

        // Register the custom progress handler
        builder.RegisterType<CustomProgressHandler>().AsSelf();

        // Register the typed client
        builder.Register(c =>
        {
            var handler = c.Resolve<CustomProgressHandler>();
            var httpClient = new HttpClient(handler)
            {
                BaseAddress = new Uri("https://localhost:7145/")
            };
            return new DownloadService(httpClient, handler);
        }).As<IDownloadService>();

        return builder.Build();
    }
}

在 WPF 应用程序启动时,初始化 DI 容器并解析您的类型化客户端:

public partial class App : Application
{
    private readonly IContainer _container;

    public App()
    {
        var bootstrapper = new Bootstrapper();
        _container = bootstrapper.Bootstrap();
    }

    protected override void OnStartup(StartupEventArgs e)
    {
        base.OnStartup(e);

        var downloadService = _container.Resolve<IDownloadService>();
        // your code
    }
}

这将给出:

+-----------------------+         +-----------------------+
|    Bootstrapper       |         |       App             |
| (Dependency Setup)    |         | (WPF Application)     |
+-----------+-----------+         +-----------+-----------+
            |                                 |
            |                                 |
            | Register Dependencies           | Resolve Dependencies
            |                                 |
            v                                 v
+-----------------------+         +-----------------------+
|  Autofac Container    |         |  IDownloadService     |
|                       |-------->|  (DownloadService)    |
+-----------+-----------+         +-----------+-----------+
            |                                 |
            |                                 |
            |                                 | Uses
            v                                 v
+-----------------------+         +-----------------------+
| CustomProgressHandler |         |     HttpClient        |
|                       |<--------|                       |
+-----------------------+         +-----------------------+
            |
            | HttpReceiveProgress Event
            v
    Your Event Handler (HandleProgress)
    (// Do stuff)

Bootstrapper
类在Autofac容器中设置依赖关系注册。
App
类(WPF 应用程序)解析
IDownloadService
,它获取
DownloadService
的实例。
DownloadService
是类型化客户端,它利用
HttpClient
实例和
CustomProgressHandler
来处理 HTTP 请求并报告进度。
CustomProgressHandler
连接到
HttpReceiveProgress
事件来报告进度,该进度在事件处理程序方法
HandleProgress
中处理。

© www.soinside.com 2019 - 2024. All rights reserved.