聲明式RESTful客戶端在asp.net core中的應用


1 聲明式RESTful客戶端

聲明式服務調用的客戶端,常見有安卓的Retrofit、SpringCloud的Feign等,.net有Refit和WebApiClient,這些客戶端都是以java或.net某個語言來聲明接口,描述如何請求RESTful api。

1.1 WebApiClient

WebApiClient由c#開發,但適用於任意.net語言,包括c#、vb.net、f#等項目,其提供兩個nuget包:WebApiClient.JIT和WebApiClient.AOT,均支持.net framework4.5.NET Standard 1.3

WebApiClient.JIT

在運行時使用Emit創建Http請求接口的代理類,HttpApiClient.Create ()時,在新的程序集創建了TInterface的代理類,類名與TInterface相同,命名空間也相同,由於代理類和TInterface接口不在同一程序集,所以要求TInterface為public。

  • 可以在項目中直接引用WebApiClient.JIT.dll就能使用;
  • 不適用於不支持JIT技術的平台(IOS、UWP);
  • 接口要求為public;

WebApiClient.AOT

在編譯過程中使用Mono.Cecil修改編譯得到的程序集,向其插入Http請求接口的代理類IL指令,這一步是在AOT編譯階段之前完成。代理類型所在的程序集、模塊、命名空間與接口類型的一樣,其名稱為$前綴的接口類型名稱,使用反編譯工具查看項目編譯后的程序集可以看到這些代理類。

  • 項目必須使用nuget安裝WebApiClient.AOT才能正常使用;
  • 沒有JIT,支持的平台廣泛;
  • 接口不要求為public,可以嵌套在類里面;

1.2 Refit

Refit是一個開發很早的項目,在github有很高的人氣,由c#開發,目前僅支持c#語言項目,支持.NET Standard 1.4,.net framework需要4.6.1得以支持。

Refit的內部實現與WebApiClient.AOT有相似之處,都是在編譯階段向聲明接口項目插入接口實現類的代碼或IL指令,我們可以稱之為靜態代理的編譯時織入。Refit使用Microsoft.CodeAnalysis.CSharp來分析接口語法,編譯前補充生成接口的代理類代碼用來與項目代碼一起編譯。

2 WebApiClient的聲明式接口

WebApiClient支持GET/HEAD、PUT/POST/DELETE、PATCH請求方法,請求內容體支持json、xml、multipart/form-data、application/x-www-form-urlencoded和自定義無結構內容等,其聲明式接口風格與asp.net core的接口聲明非常相似。

2.1 接口聲明

遠程服務asp.net core接口示例

[Route("api/[controller]")]
[ApiController]
public class UsersController : ControllerBase
{
    // GET api/users
    [HttpGet]
    public UserInfo[] Get()
    {
        return new UserInfo[]
        {
            new UserInfo { Account="laojiu" },
            new UserInfo { Account="webapicleint" }
        };
    }

    // GET api/users/id001
    [HttpGet("{id}")]
    public UserInfo Get(string id)
    {
        return new UserInfo { Id = id, Account = "laojiu" };
    }

    // POST api/users
    [HttpPost]
    public bool Post([FromBody] UserInfo value)
    {
        return true;
    }

    // PUT api/users
    [HttpPut]
    public bool Put([FromBody] UserInfo value)
    {
        return true;
    }

    // PATCH api/users/id001
    [HttpPatch("{id}")]
    public bool Patch(string id, [FromBody] JsonPatchDocument<UserInfo> value)
    {
        var user = new UserInfo { Account = "laojiu" };
        value.ApplyTo(user);

        return true;
    }


    // DELETE api/users/id001
    [HttpDelete("{id}")]
    public bool Delete(string id)
    {
        return true;
    }
}

WebApiClient聲明式調用接口

[TraceFilter]
public interface IUsersApi : IHttpApi
{
    [HttpGet("api/users")]
    ITask<UserInfo[]> GetAsync();

    [HttpGet("api/users/{id}")]
    ITask<UserInfo> GetAsync(string id);

    [HttpPost("api/users")]
    ITask<bool> PostAsync([JsonContent] UserInfo value);

    [HttpPut("api/users")]
    ITask<bool> PutAsync([JsonContent] UserInfo value);

    [HttpPatch("api/users/{id}")]
    ITask<bool> PatchAsync(string id, JsonPatchDocument<UserInfo> value);

    [HttpDelete("api/users/{id}")]
    ITask<bool> DeleteAsync(string id);
}

3 WebApiClient與DI結合

asp.net core環境中,我們可以使用WebApiClient.Extensions項目簡單WebApiClient的DI的配置,目前有DependencyInjection和HttpClientFactory的擴展等。

3.1 WebApiClient.Extensions.DependencyInjection

引入nuget包

PM> install-package WebApiClient.Extensions.DependencyInjection 

Startup相關配置

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    services.AddHttpApi<IUsersApi>().ConfigureHttpApiConfig((c,p) =>
    {
        c.HttpHost = new Uri("https://localhost:5001/");
        c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
        c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
    });
    ...
}

Controller

public class HomeController : Controller
{
    public async Task<string> Index([FromServices]IUsersApi usersApi)
    {
        var u = new UserInfo { Id = "id001", Account = "webapiclient", Password = "123456" };
        var doc = new JsonPatchDocument<UserInfo>();
        doc.Replace(item => item.Password, "888888");

        var users = await usersApi.GetAsync();
        var user = await usersApi.GetAsync("id001");
        var postState = await usersApi.PostAsync(u);
        var putState = await usersApi.PutAsync(u);
        var patchState = await usersApi.PatchAsync("id001", doc);
        var deleteState = await usersApi.DeleteAsync("id001");
        return "ok";
    }
}

3.2 WebApiClient.Extensions.HttpClientFactory

引入nuget包

PM> install-package WebApiClient.Extensions.HttpClientFactory 

Startup相關配置

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{   
    services.AddHttpApiTypedClient<IUsersApi>((c, p) =>
    {
        c.HttpHost = new Uri("https://localhost:5001/");
        c.FormatOptions.DateTimeFormat = "yyyy-MM-dd HH:mm:ss.fff";
        c.LoggerFactory = p.GetRequiredService<ILoggerFactory>();
    });
    ...
}

4 總結

本文講解了聲明式客戶端的概念、列表幾個聲明式客戶端項目,同時講解聲明式客戶端WebApiClient在asp.net core項目中的簡單使用,有關更多高級的應用,可以到WebApiClient的github上查看相關wiki。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM