Портативная библиотека классов HttpClient
Для одного из моих проектов я хочу разработать библиотеку, которая может использоваться на разных платформах (Desktop, Mobile, Surface и т. Д.). Поэтому выбрали Porable Class Library.
Я разрабатываю класс для вызова различных вызовов API с использованием HttpClient. Я застрял с тем, как вызвать метод, ответ и обойти. Это мой код:-
public static async Task<JObject> ExecuteGet(string uri)
{
using (HttpClient client = new HttpClient())
{
// TODO - Send HTTP requests
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, uri);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
//response = await client.SendAsync(reqMsg);
//return response;
//if (response.IsSuccessStatusCode)
//{
string content = await response.Content.ReadAsStringAsync();
return (JObject.Parse(content));
//}
}
}
// Perform AGENT LOGIN Process
public static bool agentStatus() {
bool loginSuccess = false;
try
{
API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
// ACCESS Response, JObject ???
}
catch
{
}
finally
{
}
Как и ExecuteGet, я также создам для ExecutePost. Мой запрос от ExecuteGet, если (1) я передаю JObject при разборе только при IsSuccessStatusCode, то как я могу узнать о любых других ошибках или сообщениях, чтобы сообщить пользователю. (2) Если я передаю ответ, то как мне назначить его здесь?
response = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Wait();
это дает ошибку.
Каков наилучший подход к этой ситуации? И я должен вызвать несколько API, поэтому разные API будут иметь разные наборы результатов.
Кроме того, можете ли вы подтвердить, что проектируя этот способ и добавив ссылку на PCL, я смогу получить доступ к нескольким проектам.
ОБНОВЛЕНИЕ:- Как упомянуто ниже в 2 ответах, я обновил свой код. Как указано в приведенной ссылке, я звоню из другого проекта. Это мой код:-
Портативная библиотека классов:-
private static HttpRequestMessage getGetRequest(string url)
{
HttpRequestMessage reqMsg = new HttpRequestMessage(HttpMethod.Get, url);
reqMsg.Headers.Add(apiIdTag, apiIdKey);
reqMsg.Headers.Add(apiSecretTag, ApiSecret);
reqMsg.Headers.Add("Content-Type", "text/json");
reqMsg.Headers.Add("Accept", "application/json");
return reqMsg;
}
// Perform AGENT LOGIN Process
public static async Task<bool> agentStatus() {
bool loginSuccess = false;
HttpClient client = null;
HttpRequestMessage request = null;
try
{
client = new HttpClient();
request = getGetRequest("http://api.mintchat.com/agent/autoonline");
response = await client.SendAsync(request).ConfigureAwait(false);
if (response.IsSuccessStatusCode)
{
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
JObject o = JObject.Parse(content);
bool stat = bool.Parse(o["status"].ToString());
///[MainAppDataObject sharedAppDataObject].authLogin.chatStatus = str;
o = null;
}
loginSuccess = true;
}
catch
{
}
finally
{
request = null;
client = null;
response = null;
}
return loginSuccess;
}
Из другого проекта WPF в событии щелчка btn я вызываю это следующим образом:
private async void btnSignin_Click(object sender, RoutedEventArgs e)
{
/// Other code goes here
// ..........
agent = doLogin(emailid, encPswd);
if (agent != null)
{
//agent.OnlineStatus = getAgentStatus();
// Compile Error at this line
bool stat = await MintWinLib.Helpers.API_Utility.agentStatus();
...
Я получаю эти 4 ошибки:-
Error 1 Predefined type 'System.Runtime.CompilerServices.IAsyncStateMachine' is not defined or imported D:\...\MiveChat\CSC
Error 2 The type 'System.Threading.Tasks.Task`1<T0>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Threading.Tasks, Version=1.5.11.0, Culture=neutral, PublicKeyToken=b03f5f7f89d50a3a'. D:\...\Login Form.xaml.cs 97 21
Error 3 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 97 33
Error 4 Cannot find all types required by the 'async' modifier. Are you targeting the wrong framework version, or missing a reference to an assembly? D:\...\Login Form.xaml.cs 47 28
Я попытался добавить System.Threading.Tasks только из библиотеки PCL, что дало 7 разных ошибок. Куда я иду не так? Что нужно сделать, чтобы это работало?
Пожалуйста, объясните мне это. Потратьте много часов на то, чтобы понять, как лучше всего разработать библиотеку, доступную для настольного приложения и приложения Win Phone. Любая помощь очень признательна. Благодарю.
2 ответа
Если вы хотите получить результат задачи, вам нужно использовать Result
имущество:
var obj = API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").Result;
Однако обычно не стоит ожидать синхронного завершения асинхронного метода, поскольку это может привести к взаимоблокировке. Лучший подход заключается в await
метод:
var obj = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline");
Обратите внимание, что вам нужно сделать вызывающий метод async
также:
public static async Task<bool> agentStatus()
Синхронизация и асинхронный код не очень хорошо сочетаются друг с другом, поэтому асинхронность имеет тенденцию распространяться по всей базе кода.
Если вы позвоните async
api при выполнении вызовов http, вы также должны предоставить эту асинхронную конечную точку пользователю, а не блокировать запрос, используя Task.Wait
,
Также при создании сторонней библиотеки рекомендуется использовать ConfigureAwait(false)
чтобы избежать тупиков, когда вызывающий код пытается получить доступ к Result
собственность или Wait
метод. Вы также должны следовать рекомендациям и пометить любой асинхронный метод Async
поэтому метод должен быть вызван ExecuteStatusAsync
public static Task<bool> AgentStatusAsync()
{
bool loginSuccess = false;
try
{
// awaiting the task will unwrap it and return the JObject
var jObject = await API_Utility.ExecuteGet("http://api.mintchat.com/agent/autoonline").ConfigureAwait(false);
}
catch
{
}
}
И внутри ExecuteGet
:
response = await client.SendAsync(reqMsg).ConfigureAwait(false);
string content = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
В случае IsSuccessStatusCode
Значение false, вы можете выдать исключение в вызывающий код, чтобы показать, что что-то пошло не так. Для этого вы можете использовать HttpResponseMessage.EnsureSuccessStatusCode
который выдает исключение, если код состояния!= 200 OK.
Лично, если ExecuteGet
это публичный метод API, я бы определенно не выставлял его как JObject
но строго типизированный тип.