我需要在Winforms应用程序中进行CRUD调用。为此,我想为发布,放置,删除和获取创建帮助方法。此方法需要将数据返回给我。
对于张贴和放置,我可能要传递List,myobject,string,int,bool等。我的返回类型可能与我放入的模型不同。
要实现上述目标,我正在考虑遵循以下原则...
返回给呼叫者的课程
public class ApiCallResult<X> where X: class
{
public HttpStatusCode StatusCode { get; set; }
public string ReasonPhrase { get; set; }
public bool IsError { get; set; }
public bool IsException { get; set; }
public string Message { get; set; }
public X Response { get; set; } //deserialized object, could be List, int string or just a single object
}
然后按照以下几行创建方法
public static async Task<ApiCallResult<X>> Post<T, X>(T data, X returnModel, string apiUrl)
{
var apiCallResult = new ApiCallResult<X> {IsError = true, Message = "No run"};
try
{
//json string
var jsonString = JsonConvert.SerializeObject(data);
using (var client = new HttpClient())
{
var httpContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await client.PostAsync(apiUrl, httpContent);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
if (response.IsSuccessStatusCode)
{
//deserialize
if (typeof(X).GetGenericTypeDefinition() == typeof(List<>))
{
// X is a generic list
apiCallResult.Response = JsonConvert.DeserializeObject<List<X>>(jsonResponseString).ToList();
}
else
{
//single object
apiCallResult.Message = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
apiCallResult.IsError = false;
}
else
{
//error response
apiCallResult.Message = jsonResponseString;
}
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}
但是显然这有多个问题
异步可以返回一个任务,我想返回apiCallResult
var apiCallResult = new ApiCallResult<T> {IsError = true, Message = "No run"};
行导致The type 'T' must be a reference type in order to use it as parameter 'T'
apiCallResult.Response = JsonConvert.DeserializeObject<List<X>>(jsonResponseString).ToList();
行导致Cannot convert source type 'System.Collections.Generic.List<X>' to target type 'T'
我该如何最好地做这样的事情?不想编写多种方法来执行此操作。
更新1:这是有效的示例代码及其用法,虽然有些粗糙,但是可以正常工作...
CRUD方法
public static class ApiCrudCallHelper
{
/// <summary>
/// Performs Post and returns ApiCallResult
/// </summary>
/// <typeparam name="T">model to Post, could be null, T, List T</typeparam>
/// <typeparam name="X">return model by API, could be X, List X, string </typeparam>
/// <param name="data">data to post of type T, List T</param>
/// <param name="apiUrl">api full URL like http://localhost:65152/API/Test if executing custom action, provide that as well at the end </param>
/// <returns>
/// ApiCallResult
/// StatusCode: status code returned by the API
/// ReasonPhrase: reason phrase returned by the API
/// IsError: true/false
/// IsException: true/false
/// Message: error message, exception message, or result of OK etc results by API
/// X ResponseObject: model returned by the API, it might not be available in all cases. Could be X, List X or string as provided by X above
/// </returns>
public static async Task<ApiCallResult<X>> Post<T, X>(T data, string apiUrl) where X : class
{
var apiCallResult = new ApiCallResult<X> { IsError = true, Message = "No run" };
try
{
//json string
var jsonString = JsonConvert.SerializeObject(data);
using (var client = new HttpClient())
{
var httpContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await client.PostAsync(apiUrl, httpContent);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
if (response.IsSuccessStatusCode)
{
//deserialize
if (!typeof(X).Equals(typeof(string)))
{
apiCallResult.ResponseObject = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
apiCallResult.IsError = false;
}
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
apiCallResult.Message = jsonResponseString;
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}
/// <summary>
/// Performs Put and returns ApiCallResult
/// </summary>
/// <typeparam name="T">model to Post, could be null, T, List T</typeparam>
/// <typeparam name="X">return model by API, could be X, List X, string </typeparam>
/// <param name="data">data to post of type T, List T</param>
/// <param name="apiUrl">api full URL including the Id like http://localhost:65152/API/Test/12345 if executing custom action, provide that as well </param>
/// <returns>
/// ApiCallResult
/// HttpStatusCode StatusCode: status code returned by the API
/// string ReasonPhrase: reason phrase returned by the API
/// bool IsError: true/false
/// bool IsException: true/false
/// string Message: error message, exception message, or result of OK etc results by API
/// X ResponseObject: model returned by the API, it might not be available in all cases. Could be X, List X or string as provided by X above
/// </returns>
public static async Task<ApiCallResult<X>> Put<T, X>(T data, string apiUrl) where X : class
{
var apiCallResult = new ApiCallResult<X> { IsError = true, Message = "No run" };
try
{
//json string
var jsonString = JsonConvert.SerializeObject(data);
using (var client = new HttpClient())
{
var httpContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await client.PutAsync(apiUrl, httpContent);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
if (response.IsSuccessStatusCode)
{
//deserialize
if (!typeof(X).Equals(typeof(string)))
{
apiCallResult.ResponseObject = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
apiCallResult.IsError = false;
}
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
apiCallResult.Message = jsonResponseString;
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}
/// <summary>
/// Performs Delete and returns ApiCallResult
/// </summary>
/// <typeparam name="X">return model by API, could be X, List X, string. Usually you'll only get Ok result etc for delete, so specify string </typeparam>
/// <param name="apiUrl">api full URL including the Id like http://localhost:65152/API/Test/12345 if executing custom action, provide that as well </param>
/// <returns>
/// ApiCallResult
/// HttpStatusCode StatusCode: status code returned by the API
/// string ReasonPhrase: reason phrase returned by the API
/// bool IsError: true/false
/// bool IsException: true/false
/// string Message: error message, exception message, or result of OK etc results by API
/// X ResponseObject: will only be available if api is returning a model (should not), in most cases it will not be available. Could be X, List X or string as provided by X above
/// </returns>
public static async Task<ApiCallResult<X>> Delete<X>(string apiUrl) where X : class
{
var apiCallResult = new ApiCallResult<X> { IsError = true, Message = "No run" };
try
{
using (var client = new HttpClient())
{
var response = await client.DeleteAsync(apiUrl);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
if (response.IsSuccessStatusCode)
{
//deserialize
if (!typeof(X).Equals(typeof(string)))
{
apiCallResult.ResponseObject = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
apiCallResult.IsError = false;
}
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
apiCallResult.Message = jsonResponseString;
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}
/// <summary>
/// Performs Get and returns ApiCallResult
/// </summary>
/// <typeparam name="X">return model by API, could be X, List X, string. </typeparam>
/// <param name="apiUrl">api full URL </param>
/// <returns>
/// ApiCallResult
/// HttpStatusCode StatusCode: status code returned by the API
/// string ReasonPhrase: reason phrase returned by the API
/// bool IsError: true/false
/// bool IsException: true/false
/// string Message: error message, exception message, or result of OK etc results by API
/// X ResponseObject: Could be X, List X or string as provided by X above
/// </returns>
public static async Task<ApiCallResult<X>> Get<X>(string apiUrl) where X : class
{
var apiCallResult = new ApiCallResult<X> { IsError = true, Message = "No run" };
try
{
using (var client = new HttpClient())
{
var response = await client.GetAsync(apiUrl);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
if (response.IsSuccessStatusCode)
{
//deserialize
if (!typeof(X).Equals(typeof(string)))
{
apiCallResult.ResponseObject = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
apiCallResult.IsError = false;
}
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
apiCallResult.Message = jsonResponseString;
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}
}
并致电(WinForms)
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void btnClear_Click(object sender, EventArgs e)
{
txtResults.Text = "";
}
//standard post
private void btnTestApiPost_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoPost();
}
private async void DoPost()
{
var dp = new DummyPost { Id = 12345, Name = "XYZ" };
//we might be posting one model and getting back another model. Here the same model is getting posted. So .Post<inputModel Type, returnModel Type>
var apiCallResult = await ApiCrudCallHelper.Post<DummyPost, DummyPost>(dp, ApiUrls.TestApiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//post to custom action
private void btnTestApiPostExtra_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoPostExtra();
}
private async void DoPostExtra()
{
var dp = new DummyPost { Id = 12345, Name = "XYZ" };
//we might be posting one model and getting back another model. Here the same model is getting posted. So .Post<inputModel Type, returnModel Type>
var apiUrl = string.Format("{0}/ExtraPost", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Post<DummyPost, DummyPost>(dp, apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//post to custom action and getting ok result back
private void btnTestApiPostExtraOkResult_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoPostExtraOkResult();
}
private async void DoPostExtraOkResult()
{
var dp = new DummyPost { Id = 12345, Name = "XYZ" };
//we might be posting one model and getting back another model. Here the same model is getting posted. So .Post<inputModel Type, returnModel Type>
var apiUrl = string.Format("{0}/ExtraPostOk", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Post<DummyPost, string>(dp, apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//post with multiline model return
private void btnTestApiPostExtraMultiLine_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoPostExtraMultiLineReturn();
}
private async void DoPostExtraMultiLineReturn()
{
var dp = new DummyPost { Id = 12345, Name = "XYZ" };
//we might be posting one model and getting back another model. Here the same model is getting posted. So .Post<inputModel Type, returnModel Type>
var apiUrl = string.Format("{0}/ExtraPostMultiLineReturn", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Post<DummyPost, List<DummyPost>>(dp, apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//standard put
private void btnTestApiPut_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoPut();
}
private async void DoPut()
{
var dp = new DummyPost { Id = 12345, Name = "XYZ" };
//we might be posting one model and getting back another model. Here the same model is getting posted. So .Post<inputModel Type, returnModel Type>
//since this is a PUT call, append the id to the url as well
var apiUrl = string.Format("{0}/98745", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Put<DummyPost, DummyPost>(dp, apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//standard delete
private void btnTestApiDelete_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoDelete();
}
private async void DoDelete()
{
//not posting any model, should get back a string responce but we can get a model as well (why?)
//since this is a DELETE call, append the id to the url as well
var apiUrl = string.Format("{0}/98745", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Delete<string>(apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//standard get
private void btnTestApiGet_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoGet();
}
private async void DoGet()
{
var apiUrl = ApiUrls.TestApiUrl;
var apiCallResult = await ApiCrudCallHelper.Get<string>(apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//get by id
private void btnTestApiGetId_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
var apiUrl = string.Format("{0}/98745", ApiUrls.TestApiUrl);
DoGetId();
}
private async void DoGetId()
{
var apiUrl = string.Format("{0}/98745", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Get<string>(apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
//custom get action
private void btnTestApiGetAll_Click(object sender, EventArgs e)
{
btnClear.PerformClick();
DoGetAll();
}
private async void DoGetAll()
{
var apiUrl = string.Format("{0}/All", ApiUrls.TestApiUrl);
var apiCallResult = await ApiCrudCallHelper.Get<List<DummyPost>>(apiUrl);
txtResults.AppendText(apiCallResult.Message);
}
}
答案 0 :(得分:1)
也许是这样吗?
public static async Task<ApiCallResult<X>> Post<T, X>(T data, X returnModel, string apiUrl) where X: class
{
var apiCallResult = new ApiCallResult<X> { IsError = true, Message = "No run" };
try
{
//json string
var jsonString = JsonConvert.SerializeObject(data);
using (var client = new HttpClient())
{
var httpContent = new StringContent(jsonString, Encoding.UTF8, "application/json");
var response = await client.PostAsync(apiUrl, httpContent);
var jsonResponseString = await response.Content.ReadAsStringAsync();
//fill
apiCallResult.StatusCode = response.StatusCode;
apiCallResult.ReasonPhrase = response.ReasonPhrase;
if (response.IsSuccessStatusCode)
{
//deserialize
if (typeof(X).GetGenericTypeDefinition() == typeof(List<>))
{
// X is a generic list
apiCallResult.Response = JsonConvert.DeserializeObject<X>(jsonResponseString);
}
else
{
//single object
apiCallResult.Message = JsonConvert.DeserializeObject<X>(jsonResponseString).ToString();
}
apiCallResult.IsError = false;
}
else
{
//error response
apiCallResult.Message = jsonResponseString;
}
}
}
catch (Exception ex)
{
apiCallResult.IsException = true;
apiCallResult.Message = ex.Message;
}
return apiCallResult;
}