WebApiClient Documentation

repository·master·Indexed 24 days ago

https://github.com/dotnetcore/webapiclient

A high-performance REST API client library for .NET that uses C# interface declarations to simplify API consumption. It offers two versions: WebApiClientCore for .NET Standard 2.1 (recommended) and a legacy version for .NET Standard 2.0. Key features include optimizations for .NET 8 AOT and trimming, JSON-RPC support via WebApiClientCore.Extensions.JsonRpc, Newtonsoft.Json integration, OAuth token management, and an OpenAPI source generator for automatic interface creation.

Tokens
25.3K
Snippets
73
Records
101
Agent score
80%

What's inside WebApiClient

  1. Overview of WebApiClient

    master
    WebApiClient is a high-performance REST API library for .NET designed to provide better functionality, performance, and scalability compared to Refit. It allows developers to define API clients using semantic C# interface declarations and supports advanced features like AOT publishing, diverse serialization, and aspect-oriented programming.
  2. Understand the WebApiClient App structure

    master

    The App project serves as a demonstration of how to implement both a server and a client within a single process. It demonstrates the following architectural roles:

    Server Side (服务端)

    • Controllers: Act as the server endpoints.
    • TokensController: Simulates a token issuance service.
    • UsersController: Simulates a user resource server.

    Client Side (客户端)

    • ApiClients.IUserApi: A declarative interface defined using WebApiClientCore features.
    • ApiClients.UserService: A wrapper service that encapsulates the logic and has the IUserApi interface injected into it.
    • ApiClients.UserHostedService: A background service (IHostedService) that retrieves an instance of UserService upon startup to execute tasks.
  3. Choose between WebApiClientCore and WebApiClient

    master

    WebApiClient provides two distinct versions depending on your target framework and architectural needs:

    • WebApiClientCore: The modern version based on .NET Standard 2.1. It is designed to integrate seamlessly with modern .NET abstractions, including Dependency Injection, Configuration, Options, and Logging. This is the recommended version for new projects.
    • WebApiClient (WebApiClient.JIT, WebApiClient.AOT): The legacy version based on .NET Standard 2.0. It supports .NET Core 2.0+ and .NET Framework 4.5+. Note that this version is no longer receiving active updates.
  4. Key Features of WebApiClient

    master

    WebApiClient provides several core capabilities for building REST clients:

    • Semantic Declarations: Define clients by simply declaring interfaces.
    • Diverse Serialization: Supports JSON, XML, Form, and custom serialization methods.
    • AOT & Trimming: Fully supports .NET 8 code trimming and Ahead-of-Time (AOT) compilation.
    • Aspect-Oriented Programming (AOP): Supports interceptors, filters, logging, retries, and custom caching.
    • Syntax Analysis: Provides syntax analysis and hints for interface declarations to prevent incorrect usage.
    • Authentication Support: Includes extension packages for OAuth2 and token management to simplify identity authentication and authorization.
    • Automatic Code Generation: A dotnet tool can parse local or remote OpenAPI documents to automatically generate WebApiClientCore interface code.
    • High Performance: Benchmarked to be up to 2.X times faster than Refit in various request scenarios.
  5. Use WebApiClientCore.OpenApi.SourceGenerator to generate interface code

    master

    WebApiClientCore.OpenApi.SourceGenerator is a tool that parses local or remote OpenAPI (Swagger) JSON documents and generates declarative WebApiClientCore interface definition code files.

    It follows a workflow of parsing the OpenAPI document via NSwag, processing it through RazorEngine templates, and extracting the resulting code using XDocument to produce formatted C# interface files.

  6. Use ITask for retries and error handling

    master

    While Task<T> is suitable for simple requests, use ITask<T> when you need conditional retries or specialized error handling.

    Retry Strategies

    • Basic: task.Retry(count)
    • Fixed Delay: task.Retry(count, TimeSpan)
    • Dynamic/Exponential Backoff: task.Retry(count, index => TimeSpan)

    Error and Result Handling

    • WhenCatch<TException>: Catch specific exceptions to trigger retries or log errors.
    • WhenResult: Trigger retries based on the success/failure of the returned result.
    • HandleAsDefaultWhenException: Return a default value if an exception occurs.
    • Handle: Provide a fallback mechanism using WhenCatch.
    using WebApiClientCore;
    
    // Basic retry
    ITask<T> task = api.GetAsync(id);
    await task.Retry(3);
    
    // Fixed delay
    await api.GetAsync(id).Retry(3, TimeSpan.FromSeconds(1));
    
    // Dynamic delay (exponential backoff)
    await api.GetAsync(id).Retry(3, i => TimeSpan.FromSeconds(Math.Pow(2, i)));
    
    // Catching exceptions
    await api.GetAsync(id)
        .Retry(3)
        .WhenCatch<HttpRequestException>()                               // Catch and retry
        .WhenCatch<HttpRequestException>(ex => logger.LogWarning(ex))    // Catch and log
        .WhenCatch<HttpRequestException>(ex => ex.InnerException is SocketException);  // Conditional catch
    
    // Result-based retry
    await api.GetAsync(id)
        .Retry(3)
        .WhenResult(r => r.Success == false)
        .WhenResultAsync(async r => await cacheService.IsStaleAsync(r.Version));
    
    // Handling exceptions with defaults
    var user = await api.GetAsync(id).HandleAsDefaultWhenException();
    
    var result = await api.GetAsync(id)
        .Handle()
        .WhenCatch<HttpRequestException>(() => new User { Id = "error" });
  7. Critical rules for WebApiClientCore API declarations

    master

    When defining your API interfaces, you must adhere to these rules to avoid runtime errors or incorrect path concatenation:

    1. HttpHost Suffix: The [HttpHost] attribute value must end with a / (e.g., [HttpHost("https://api.example.com/")]). Failure to do so will cause path concatenation errors.
    2. HTTP Method Attributes: Every method in your interface must have an HTTP method attribute (e.g., [HttpGet], [HttpPost]).
    3. Uri Parameter Position: If using the [Uri] attribute, it must be the first parameter of the method.
    4. Inheritance: Interfaces do not need to inherit from IHttpApi.
    5. Serialization: The library uses System.Text.Json by default (Newtonsoft.Json is no longer a dependency).
  8. Understand the execution order of WebApiClient attributes

    master

    WebApiClient uses attributes to define request and response behavior. Attributes are executed in a specific sequence depending on whether they are applied before or after the request/response cycle.

    Execution Order (Before Request):

    1. Parameter value validation
    2. IApiActionAttribute
    3. IApiParameterAttribute
    4. IApiReturnAttribute
    5. IApiFilterAttribute

    Execution Order (After Response):

    1. IApiReturnAttribute
    2. Return value validation
    3. IApiFilterAttribute

    Attributes can be applied to an entire interface (affecting all methods) or to specific methods and parameters.

  9. Share a TokenProvider across multiple interfaces

    master

    You can share a single ITokenProvider across multiple API interfaces by using interface inheritance. Define a base interface with the [OAuthToken] attribute, and have your specific API interfaces inherit from it.

    [OAuthToken]
    public interface IBaidu
    {
    }
    
    public interface IBaidu_XXX_Api : IBaidu
    {
        [HttpGet]
        Task xxxAsync();
    }
    
    public interface IBaidu_YYY_Api : IBaidu
    {
        [HttpGet]
        Task yyyAsync();
    }
    
    // Register the provider for the base interface
    services.AddPasswordCredentialsTokenProvider<IBaidu>(o =>
    {
        o.Endpoint = new Uri("http://localhost:5000/api/tokens");
        o.Credentials.Client_id = "clientId";
        o.Credentials.Client_secret = "xxyyzz";
        o.Credentials.Username = "username";
        o.Credentials.Password = "password";
    });
  10. Configure Return attributes for response handling

    master

    Return attributes define how the response content is mapped to .NET data models.

    Rules for Return Attributes:

    1. Content-Type Matching: If EnsureMatchAcceptContentType is true (default), the attribute only applies if the response Content-Type matches the attribute's AcceptContentType.
    2. Error Handling: If no Return attribute matches the response Content-Type, an ApiReturnNotSupportedException is thrown.
    3. Status Code Validation: If EnsureSuccessStatusCode is true (default), an ApiResponseStatusException is thrown if the status code is not in the 200-299 range.
    4. Priority: If multiple attributes have the same AcceptContentType, the one with the highest AcceptQuality is used.

    Implicit Defaults: Every interface has implicit Return attributes with AcceptQuality = 0.1. To override them, declare a new attribute of the same type with a higher AcceptQuality.

    Available Return Attributes:

    • [RawReturn]: Supports string, byte[], Stream, and HttpResponseMessage.
    • [JsonReturn]: Uses System.Text.Json for serialization/deserialization.
    • [XmlReturn]: Uses System.Xml.Serialization for serialization/deserialization.
    • [NoneReturn]: If the response status is 204, returns the default value of the return type.
    [Json] // .AcceptQuality = 1.0, .EnsureSuccessStatusCode = true, .EnsureMatchAcceptContentType = false
    Task<SpecialResultClass> DemoApiMethod();