1. .NET C#可以使用的網絡傳輸方法類庫有很多,比如:System.Net.Http.HttpClient、System.Net.WebClient、System.Net.HttpWebRequest和System.Net.HttpWebResponse。
相關官方文檔鏈接:
https://docs.microsoft.com/en-us/dotnet/api/system.net.http.httpclient?view=net-5.0
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.webclient?redirectedfrom=MSDN&view=net-5.0
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.httpwebrequest?view=net-5.0
https://docs.microsoft.com/zh-cn/dotnet/api/system.net.httpwebresponse?view=net-5.0
現在微軟官方比較推薦的是使用System.Net.Http.HttpClient來執行網絡傳輸任務。
2. httpClient異步網絡請求工具方法 示例代碼如下:
public static class HttpClientExtensions
{
public static Task<HttpResponseMessage> PatchAsync(this HttpClient client, Uri uri, HttpContent content)
{
var method = new HttpMethod("PATCH");
var request = new HttpRequestMessage(method, uri)
{
Content = content
};
return client.SendAsync(request);
}
}
public static class ApiHttpUtils
{
private static HttpClient _client;
static ApiHttpUtils()
{
//TODO 后續調整為先讀取緩存,沒有則新建之
_client = new HttpClient();
}
/// <summary>
/// 執行http的請求
/// </summary>
/// <param name="uri">執行的uri</param>
/// <param name="methodType">http方法類型</param>
/// <param name="bodyParam">POST\PUT\Patch方式時,傳值參數</param>
/// <param name="inputMediaType">輸入格式,即header里面的Content-Type的內容</param>
/// <param name="outputMediaType">輸出格式,即header里面的Accept的內容</param>
/// <returns>執行結果</returns>
public static async Task<string> ExecuteHttpClientAsync(
Uri uri,
Enums.HttpMethodEnum methodType,
string bodyParam,
string inputMediaType = "json",
string outputMediaType = "json")
{
HttpResponseMessage result = null;
try
{
HttpClient client = CreateHttpClient(outputMediaType);
HttpContent content = null;
if (!string.IsNullOrWhiteSpace(bodyParam))
content = new StringContent(bodyParam, Encoding.UTF8, $"application/{inputMediaType}");
switch (methodType)
{
case Enums.HttpMethodEnum.Post:
result = await client.PostAsync(uri, content);
break;
case Enums.HttpMethodEnum.Put:
result = await client.PutAsync(uri, content);
break;
case Enums.HttpMethodEnum.Get:
result = await client.GetAsync(uri);
break;
case Enums.HttpMethodEnum.Delete:
result = await client.DeleteAsync(uri);
break;
case Enums.HttpMethodEnum.Patch:
result = await client.PatchAsync(uri, content);
break;
}
}
catch (AggregateException ex)
{
#region 獲取線程異常信息
Exception firstException = null;
if (ex.InnerExceptions != null && ex.InnerExceptions.Any())
{
firstException = ex.InnerExceptions.First();
if (firstException.InnerException != null)
firstException = firstException.InnerException;
}
//Logger.LogException(firstException);//Nlog日志記錄
#endregion 獲取線程異常信息
result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content =
new StringContent(firstException != null
? firstException.ToString()
: "Encountered an AggreggateException without any inner exceptions")
};
}
catch (Exception ex)
{
//Logger.LogException(ex);//Nlog日志記錄
result = new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content =
new StringContent("Encountered an AggreggateException without any inner exceptions")
};
}
return await result.Content.ReadAsStringAsync();
}
/// <summary>
/// 創建http的客戶端
/// </summary>
/// <param name="outputMediaType">輸出格式,即header里面的Accept的內容</param>
public static HttpClient CreateHttpClient(string outputMediaType = "json")
{
HttpClient client = _client;
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue($"application/{outputMediaType}"));
return client;
}
}
3.Client調用方式如下,以WinForm窗體程序舉例,某按鈕點擊事件后台方法:
public class InspectContentExtractReturnInputModel
{
public List<string> Datas { get; set; }
}
public static class SystemConfig
{
/// <summary>
/// 測試調用異步耗時webAPI不等待其返回值
/// </summary>
public static string TestTimeConsumWebApiUrl { get; set; }
public static void LoadSettings()
{
try
{
TestTimeConsumWebApiUrl = ConfigUtils.GetAppSetting("TestTimeConsumWebApiUrl");
}
catch (Exception ex)
{
}
}
}
public enum ResponseStatusEnum
{
/// <summary>
/// 程序執行正常,code 200
/// </summary>
Ok = 200,
/// <summary>
/// 參數為null或為空,code 201
/// </summary>
ArgumentsIsNull = 201,
/// <summary>
/// 程序執行發生異常,code 202
/// </summary>
ProgramExecuteOccurException = 202
}
[Description("響應信息")]
public class Response<T>
{
/// <summary>
/// 錯誤碼,默認200
/// 200正常,201參數為空,202程序執行異常
/// </summary>
[Description("錯誤碼")]
public string ErrorCode { get; set; } = ((int)ResponseStatusEnum.Ok).ToString();
[Description("錯誤信息")]
public string ErrorMsg { get; set; } = "";
[Description("響應結果是否成功")]
public bool IsSuccess
{
get { return string.IsNullOrWhiteSpace(this.ErrorMsg); }
}
[Description("結果集合")]
public T Data { get; set; }
}
public class InspectSwitchViewModel<T>
{
public T Result { get; set; }
}
public partial class Form2 : Form
{
//Api input model
private InspectContentExtractReturnInputModel _inputModel = new InspectContentExtractReturnInputModel();
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
_inputModel = new InspectContentExtractReturnInputModel()
{
Datas = new List<string>()
{
"params1","params2","params3"
}
};
Task.Run(async () =>
{
var r = await ApiHttpUtils.ExecuteHttpClientAsync(
new Uri(SystemConfig.TestTimeConsumWebApiUrl),//server api url
HttpMethodEnum.Post, //http method type
DataTransferExtensions.SetTransferDataJson(_inputModel), //input model 序列為json
"json",//input params type:json
"json"//return params type:json
);
//以下是與服務端預定好的返回值數據結構,將json反序列化為Model
var response = DataTransferExtensions.GetTransferData<Response<InspectSwitchViewModel<object>>>(r);
if (response.IsSuccess &&
response.ErrorCode == ((int) ResponseStatusEnum.Ok).ToString())//判斷服務端響應結果
{
this.Invoke(new Action(() =>
{
this.label1.Text = response.Data.Result.ToString();//更新winform 界面UI提示信息
}));
}
else
{
this.Invoke(new Action(() =>
{
this.label1.Text = response.ErrorMsg;//更新winform 界面UI提示信息
}));
}
});
}
}
4.Server是使用的ASP.NET WebAPI,示例代碼如下:
public class InspectSwitchControllerService
{
public async Task<Response<InspectSwitchViewModel<object>>> InspectContentExtractReturn(List<string> datas)
{
Response<InspectSwitchViewModel<object>> r = new Response<InspectSwitchViewModel<object>>();
try
{
//await Task.Delay(1000000);//此處編寫業務實現代碼
}
catch (Exception ex)
{
r.ErrorCode = ((int) ResponseStatusEnum.ProgramExecuteOccurException).ToString();
r.ErrorMsg = ex.Message;
}
return r;
}
}
public class InspectSwitchController : ApiController
{
private readonly InspectSwitchControllerService _inspectSwitchControllerService = new InspectSwitchControllerService();
[HttpPost]
public IHttpActionResult InspectContentExtractReturn([FromBody] InspectContentExtractReturnInputModel model)
{
var response = new Response<InspectSwitchViewModel<object>>()
{
ErrorCode = ((int)ResponseStatusEnum.Ok).ToString(),
ErrorMsg = string.Empty,
Data = new InspectSwitchViewModel<object>(){Result= "調用成功,直接返回結果,不等待耗時任務完成即返回" }
};
Task.Run(async () =>
{
await _inspectSwitchControllerService.InspectContentExtractReturn(model.Datas);
});
return Ok(response);
}
}