5.1接口定义与请求方法

HTTP 声明式请求机制通过实现 IHttpDeclarative 接口,在程序运行时动态地构建实现类。该机制会智能地拦截符合特定规则的方法调用,并自动生成相应的 HTTP 远程请求代码。这种方法不仅极大地减轻了开发人员编写 HTTP 请求代码的负担,而且使得代码结构更加条理分明,更易于进行组织、维护和复用。

HTTP 声明式请求 ✨#

HTTP 声明式请求机制通过实现 IHttpDeclarative 接口,在程序运行时动态地构建实现类。该机制会智能地拦截符合特定规则的方法调用,并自动生成相应的 HTTP 远程请求代码。这种方法不仅极大地减轻了开发人员编写 HTTP 请求代码的负担,而且使得代码结构更加条理分明,更易于进行组织、维护和复用。

接口定义与使用#

在利用 HTTP 声明式请求之前,您需要定义一个接口,并确保它实现 IHttpDeclarative 接口:

cs
public interface IHttpService : IHttpDeclarative{}

随后,在 Startup.csProgram.cs 文件中,配置并注册 HttpRemote 服务,以启用 HTTP 声明式请求功能:

cs
services.AddHttpRemote(builder =>{    // 使用泛型方式注册 IHttpService 声明式接口    builder.AddHttpDeclarative<IHttpService>();    // 或者使用类型方式    // builder.AddHttpDeclarative(typeof(IHttpService));    // 若需注册多个接口,可使用以下方法(非示例中的数组语法)    // builder.AddHttpDeclaratives(new[] { typeof(IHttpService), typeof(IHttpService) });    // 推荐:从程序集中扫描并批量注册    // builder.AddHttpDeclarativesFromAssemblies([Assembly.GetEntryAssembly()]);    // 若使用 Furion 框架,可直接传入 App.Assemblies    // builder.AddHttpDeclarativesFromAssemblies(App.Assemblies);});

在服务中使用 IHttpService 声明式请求时,可通过构造函数注入:

cs
public class YourService{    private readonly IHttpService _httpService;    public YourService(IHttpService httpService)    {        _httpService = httpService;    }}

若您使用的是 .NET 8 及以上版本时,可利用主构造函数注入进一步简化代码:

cs
public class YourService(IHttpService httpService){    // 使用 httpService 变量}

某些场景下,您也可以仅在特定方法中注入,通过在参数前添加 [FromServices] 特性实现:

cs
public class YourService{    public Task<string> GetResource([FromServices] IHttpService httpService)    {        // 您的业务逻辑    }}

此外,如果您希望动态解析声明式服务,可以先注入 IHttpRemoteService,再调用其 For<T>() 方法获取实例:

cs
public class YourService(IHttpRemoteService httpRemoteService){    public async Task InvokeAsync()    {        var httpService = httpRemoteService.For<IHttpService>();    }}

开放泛型接口#

HTTP 声明式接口同样支持开放泛型定义,例如:

cs
public interface IHttpService<T> : IHttpDeclarative{}

需要注意的是,使用程序集扫描方式(如 builder.AddHttpDeclarativesFromAssemblies(assemblies))时会默认跳过开放泛型接口,因为它要求提供运行时的具体类型(即封闭泛型类型)。此时,应显式注册封闭泛型版本:

cs
services.AddHttpRemote(builder =>{    // 注册封闭泛型类型,如 IHttpService<string>    builder.AddHttpDeclarative<IHttpService<string>>();    // 或者使用类型方式    // builder.AddHttpDeclarative(typeof(IHttpService<string>));});

在业务中使用时,可直接通过依赖注入获取指定封闭类型(如 IHttpService<string>),或调用 IHttpRemoteService.For<IHttpService<string>>() 动态解析服务实例。

无需实现 IHttpDeclarative 接口#

某些情况下,您可能希望直接为普通接口生成声明式代理,而不强制要求该接口实现 IHttpDeclarative。例如,定义一个普通的 IMyApi 接口:

cs
public interface IMyApi{    [Get("https://api.furion.net/users/{id}")]    Task<User> GetUserAsync(int id);}

此时在注册时指定 requireIHttpDeclarative: false

cs
services.AddHttpRemote(builder =>{    builder.AddHttpDeclarative(typeof(IMyApi), requireIHttpDeclarative: false);});

注册后,该接口的使用方式与普通声明式接口完全一致,可通过构造函数注入、[FromServices] 特性注入或 IHttpRemoteService.For<T>() 动态解析。

定义请求方法#

IHttpService 声明式接口中,您可以定义各种 API 请求方法。这些方法需要标记有从 HttpMethodAttribute 派生的特性,以指明其对应的 HTTP 请求类型。系统预置了多种常见的 HTTP 请求方法特性,同时也支持自定义方法特性:

cs
public interface IHttpService : IHttpDeclarative{    // 定义 HTTP GET 请求    [Get("https://furion.net/")]    Task<string> GetMethodAsync();    // 定义 HTTP PUT 请求    [Put("https://furion.net/")]    Task<string> PutMethodAsync();    // 定义 HTTP POST 请求    [Post("https://furion.net/")]    Task<string> PostMethodAsync();    // 定义 HTTP DELETE 请求    [Delete("https://furion.net/")]    Task<string> DeleteMethodAsync();    // 定义 HTTP HEAD 请求    [Head("https://furion.net/")]    Task<string> HeadMethodAsync();    // 定义 HTTP OPTIONS 请求    [Options("https://furion.net/")]    Task<string> OptionsMethodAsync();    // 定义 HTTP TRACE 请求    [Trace("https://furion.net/")]    Task<string> TraceMethodAsync();    // 定义 HTTP PATCH 请求    [Patch("https://furion.net/")]    Task<string> PatchMethodAsync();    // 定义 HTTP QUERY 请求    [Query("https://furion.net/")]    Task<string> PatchMethodAsync();    // 自定义 HTTP 请求方法    [HttpMethod("Connect", "https://furion.net/")]    Task<string> ConnectMethodAsync();    // 定义泛型方法    [Get("https://furion.net/")]    Task<T> GenericMethodAsync<T>();}
cs
public interface IHttpService : IHttpDeclarative{    // 缺少 [HttpMethod] 特性,将导致异常    Task<string> UnknownMethodAsync();}

自定义请求方法#

除了直接利用 [HttpMethod("Connect", "https://furion.net/")] 来添加自定义的 HTTP 请求方法外,我们还可以创建一个具体的 ConnectAttribute 特性类,以提高代码的复用性和可读性。这个特性类将继承自 HttpMethodAttribute,并专门用于表示 Connect 请求。

cs
[AttributeUsage(AttributeTargets.Method)]public sealed class ConnectAttribute : HttpMethodAttribute{    public ConnectAttribute(string? requestUri = null)        : base("Connect", requestUri)    {    }}

现在,我们可以在 IHttpService 接口中使用自定义的 [Connect] 特性来替代之前的 [HttpMethod("Connect", ...)] 特性:

cs
public interface IHttpService : IHttpDeclarative{    // 使用自定义 Connect 特性    [Connect("https://furion.net/")]    Task<string> ConnectMethodAsync();}

这样的代码更加简洁明了,同时提升了代码的可维护性和复用性。