我想在C#中编写一个REST客户端,它可以从配置文件中读取API调用,处理JSON响应并相应地生成csv文件。 将有另一个配置文件包含每个API调用返回的属性。此客户端应阅读此模板配置文件并处理响应。
客户端应该可以与生成JSON响应的所有第三方休息api一起使用。唯一的区别是每个数据源会有不同的配置文件和模板文件。
有没有其他方法可以实现上述功能? 是否有任何第三方库可以帮助实现这一目标? 什么应该是一个很好的设计方法来实现这一目标?
非常感谢任何帮助
答案 0 :(得分:0)
是的。有一种方法可以实现此功能,但听起来好像您在这里询问多个问题。您可能应该将问题分成多个部分。
如果您有一个配置文件可以从多个Rest源中提取数据,则可以使用基于HttpClient的简单Rest客户端,如下所示:
此处的图书馆:https://github.com/MelbourneDeveloper/RestClient.Net
public class RestClient
{
#region Fields
private readonly HttpClient _HttpClient = new HttpClient();
#endregion
#region Public Properties
public Uri BaseUri => _HttpClient.BaseAddress;
public Dictionary<string, string> Headers { get; private set; } = new Dictionary<string, string>();
public AuthenticationHeaderValue Authorization { get; set; }
public Dictionary<HttpStatusCode, Func<byte[], object>> HttpStatusCodeFuncs = new Dictionary<HttpStatusCode, Func<byte[], object>>();
public IZip Zip;
public ISerializationAdapter SerializationAdapter { get; }
#endregion
#region Constructor
public RestClient(ISerializationAdapter serializationAdapter, Uri baseUri)
{
_HttpClient.BaseAddress = baseUri;
_HttpClient.Timeout = new TimeSpan(0, 3, 0);
SerializationAdapter = serializationAdapter;
}
#endregion
#region Private Methods
private async Task<T> Call<T>(string queryString, HttpVerb httpVerb, string contentType, object body = null)
{
_HttpClient.DefaultRequestHeaders.Clear();
if (Authorization != null)
{
_HttpClient.DefaultRequestHeaders.Authorization = Authorization;
}
HttpResponseMessage result = null;
var isPost = httpVerb == HttpVerb.Post;
if (!isPost)
{
_HttpClient.DefaultRequestHeaders.Clear();
foreach (var key in Headers.Keys)
{
_HttpClient.DefaultRequestHeaders.Add(key, Headers[key]);
}
}
string bodyString = null;
StringContent stringContent = null;
byte[] data = null;
switch (httpVerb)
{
case HttpVerb.Post:
if (body is string bodyAsString)
{
bodyString = bodyAsString;
}
else
{
if (body != null)
{
data = await SerializationAdapter.SerializeAsync(body);
bodyString = SerializationAdapter.Encoding.GetString(data);
}
else
{
bodyString = string.Empty;
}
}
stringContent = new StringContent(bodyString, Encoding.UTF8, contentType);
//Don't know why but this has to be set again, otherwise more text is added on to the Content-Type header...
stringContent.Headers.ContentType = new MediaTypeHeaderValue(contentType);
stringContent.Headers.ContentLength = bodyString.Length;
foreach (var key in Headers.Keys)
{
stringContent.Headers.Add(key, Headers[key]);
}
result = await _HttpClient.PostAsync(queryString, stringContent);
break;
case HttpVerb.Get:
result = await _HttpClient.GetAsync(queryString);
break;
case HttpVerb.Delete:
result = await _HttpClient.DeleteAsync(queryString);
break;
case HttpVerb.Put:
case HttpVerb.Patch:
data = await SerializationAdapter.SerializeAsync(body);
bodyString = SerializationAdapter.Encoding.GetString(data);
var length = bodyString.Length;
stringContent = new StringContent(bodyString, SerializationAdapter.Encoding, contentType);
if (httpVerb == HttpVerb.Put)
{
result = await _HttpClient.PutAsync(queryString, stringContent);
}
else
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, queryString)
{
Content = stringContent
};
result = await _HttpClient.SendAsync(request);
}
break;
}
if (result.IsSuccessStatusCode)
{
var gzipHeader = result.Content.Headers.ContentEncoding.FirstOrDefault(h => !string.IsNullOrEmpty(h) && h.Equals("gzip", StringComparison.InvariantCultureIgnoreCase));
if (gzipHeader != null && Zip != null)
{
var bytes = await result.Content.ReadAsByteArrayAsync();
data = Zip.Unzip(bytes);
}
else
{
data = await result.Content.ReadAsByteArrayAsync();
}
return await SerializationAdapter.DeserializeAsync<T>(data);
}
var errorData = await result.Content.ReadAsByteArrayAsync();
if (HttpStatusCodeFuncs.ContainsKey(result.StatusCode))
{
return (T)HttpStatusCodeFuncs[result.StatusCode].Invoke(errorData);
}
throw new HttpStatusException($"{result.StatusCode}.\r\nBase Uri: {_HttpClient.BaseAddress}. Full Uri: {_HttpClient.BaseAddress + queryString}", result.StatusCode, errorData);
}
#endregion
#region Public Methods
public async Task<T> GetAsync<T>()
{
return await GetAsync<T>(null);
}
public async Task<T> GetAsync<T>(string queryString, string contentType = "application/json")
{
return await Call<T>(queryString, HttpVerb.Get, contentType);
}
public async Task<TReturn> PostAsync<TReturn, TBody>(TBody body, string queryString, string contentType = "application/json")
{
return await Call<TReturn>(queryString, HttpVerb.Post, contentType, body);
}
public async Task<TReturn> PutAsync<TReturn, TBody>(TBody body, string queryString, string contentType = "application/json")
{
return await Call<TReturn>(queryString, HttpVerb.Put, contentType, body);
}
public async Task DeleteAsync(string queryString, string contentType = "application/json")
{
await Call<object>(queryString, HttpVerb.Delete, contentType, null);
}
public async Task<TReturn> PatchAsync<TReturn, TBody>(TBody body, string queryString, string contentType = "application/json")
{
return await Call<TReturn>(queryString, HttpVerb.Patch, contentType, body);
}
#endregion
}
用法:
var countryCodeClient = new RestClientDotNet.RestClient(new NewtonsoftSerializationAdapter(), new Uri("http://services.groupkt.com/country/get/all"));
var countryData = await countryCodeClient.GetAsync<groupktResult<CountriesResult>>();