我正在使用xamarin并尝试使用一种方法来使用所有服务。为此我写了一个TaskExtension。因此,从应用程序的每个页面我都可以调用该扩展方法。这是为了禁用按钮,显示加载屏幕,响应处理以及从一点开始处理异常处理。我在下面附上我的代码。需要您对此解决方案的专家意见
这是我的扩展类
public static class TaskExtensions
{
public static async Task<ResultViewModel<U>> ExecuteAsyncOperation<U>(this Task<HttpResponseMessage> operation, object sender = null)
{
ResultViewModel<U> resultModel = new ResultViewModel<U>();
Button button = BeforeAsyncCall(sender);
try
{
await BackgroundOperation(operation, resultModel);
}
catch (Exception ex)
{
resultModel.Status = HttpStatusCode.InternalServerError;
resultModel.Errors = new List<string>() { "Some error occurred. Please try again." };
}
finally
{
AfterAsyncCall(button);
}
return resultModel;
}
static async Task BackgroundOperation<U>(Task<HttpResponseMessage> operation, ResultViewModel<U> resultModel)
{
HttpResponseMessage RawResult = await operation;
var Response = await RawResult.Content.ReadAsStringAsync();
resultModel.Status = RawResult.StatusCode;
if (RawResult.IsSuccessStatusCode)
{
var responseObj = await Task.Run(() => JsonConvert.DeserializeObject<U>(Response));
resultModel.Result = responseObj;
}
else
{
var responseErrorObj = await Task.Run(() => JsonConvert.DeserializeObject<ErrorModel>(Response));
resultModel.Errors = new List<string>();
foreach (var modelState in responseErrorObj.ModelState)
{
foreach (var error in modelState.Value)
{
resultModel.Errors.Add(error.ToString());
}
}
}
}
static Button BeforeAsyncCall(object sender)
{
Button button = null;
if (sender != null)
button = (Button)sender;
if (button != null)
button.IsEnabled = false;
UserDialogs.Instance.ShowLoading("Loading", MaskType.Black);
return button;
}
static void AfterAsyncCall(Button button)
{
UserDialogs.Instance.HideLoading();
if (button != null)
button.IsEnabled = true;
}
}
这是对我的扩展方法的调用
ResultViewModel<TokenModel> response = await new Service(Settings.BaseUrl).Login(loginModel).ExecuteAsyncOperation<TokenModel>(sender);
ResultViewModel
public class ResultViewModel<T>
{
public HttpStatusCode Status { get; set; }
public T Result { get; set; }
public List<string> Errors { get; set; }
}
异步方法
public async Task<HttpResponseMessage> Login(LoginViewModel loginModel)
{
try
{
var dataList = new List<KeyValuePair<string, string>>();
dataList.Add(new KeyValuePair<string, string>("grant_type", "password"));
dataList.Add(new KeyValuePair<string, string>("username", loginModel.Email));
dataList.Add(new KeyValuePair<string, string>("password", loginModel.Password));
var request = new HttpRequestMessage()
{
RequestUri = new Uri(this.BaseUrl + "token"),
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(dataList)
};
var authenticateResponse = await Client.SendAsync(request);
return authenticateResponse;
}
catch (Exception ex)
{
return null;
}
}
我的问题是
1)这是一个好方法吗?
2)我们可以在性能方面进行改进吗?
3)我是否正确使用Async?
答案 0 :(得分:1)
1)这是一个好方法吗?
这种方法没有错。
2)我们可以在性能方面进行改进吗?
使用扩展方法不应该有任何性能问题,但您可以测量为100%确定。您正在使用object
到button
投射创建装箱和拆箱情况。你能用Button
吗?如果要支持多种元素类型,请使用ViewElement
。此外,使用async await
会受到惩罚,但它们是最小的,不必阻止UI。您可以通过向任务添加.ConfigureAwait(false)
来消除重新捕获上下文的需要,从而提高性能,但在您的情况下,您需要上下文来重新启用按钮。使用dynamic
似乎是不必要的,并且确实有一些开销。
3)我是否正确使用Async?
如果方法只返回await
,则您不必Task
Task
。您可以通过调用方法await
它。这将减少编译器的开销,并可能提高性能。尽管如此,我还没有对此进行过测试。
<强>扩展强>
public static async Task<ResultViewModel<T>> ExecuteAsyncOperation<T>(this Task<HttpResponseMessage> operation, Button button)
{
ResultViewModel<T> resultModel = new ResultViewModel<T>();
try
{
if (button != null)
button.IsEnabled = false;
HttpResponseMessage RawResult = await operation;
string Response = await RawResult.Content.ReadAsStringAsync();
resultModel.Status = RawResult.StatusCode;
if (RawResult.IsSuccessStatusCode)
{
var responseObj = JsonConvert.DeserializeObject<T>(Response);
resultModel.Result = responseObj;
}
else
{
//create an error model instead of using dynamic I am guessing modelstate here
List<ModelState> responseObj = JsonConvert.DeserializeObject<List<ModelState>>(Response);
resultModel.Errors = new List<string>();
foreach (ModelState modelState in responseObj)
{
foreach (var error in modelState.Errors)
{
resultModel.Errors.Add(error.ToString());
}
}
}
}
catch (Exception ex)
{
resultModel.Status = HttpStatusCode.InternalServerError;
resultModel.Errors = new List<string>() { "Some error occurred. Please try again." };
}
finally
{
if (button != null)
button.IsEnabled = true;
}
return resultModel;
}
<强>调用强>
var button = sender as Button;
if (button != null)
{
ResultViewModel<TokenModel> response = await new Service(Settings.BaseUrl).Login(loginModel).ExecuteAsyncOperation<TokenModel>(sender);
}
请求强>
public Task<HttpResponseMessage> Login(LoginViewModel loginModel)
{
var dataList = new List<KeyValuePair<string, string>>();
dataList.Add(new KeyValuePair<string, string>("grant_type", "password"));
dataList.Add(new KeyValuePair<string, string>("username", loginModel.Email));
dataList.Add(new KeyValuePair<string, string>("password", loginModel.Password));
var request = new HttpRequestMessage()
{
RequestUri = new Uri(this.BaseUrl + "token"),
Method = HttpMethod.Post,
Content = new FormUrlEncodedContent(dataList)
};
return Client.SendAsync(request);
}