私の質問:これを行うにはどうすればよいですか?
ですから、今週まで約6年間、.Netには何も触れていませんでした。忘れてしまったことや知らなかったことはたくさんあります。async/ awaitキーワードのアイデアは気に入っていますが、クライアントのAPI実装に次の要件を実装するのに少し問題があります。
ServerAPI
クラスには、適切な入力パラメーターを受け取る各APIメソッドのメソッドがあります(たとえば、メソッドLogin
はid
とpassword
を取ります。 API呼び出しを行い、結果を呼び出し元に返します)。Login
メソッドは認証トークンやuidなどを含むUser
オブジェクトを返します)true
=成功)またはステータスコード。HttpResponseMessage
オブジェクトを返し、呼び出し元に処理させる必要がある場合があります。これは私がこれまでに持っているおおよそのものであり、上記のOR私がこれを正しく行っているかどうか)に準拠させる方法がわかりません。どんなガイダンスもありがたいです(ただし、炎上ではありません)。
// 200 (+User JSON) = success, otherwise APIError JSON
internal async Task<User> Login (string id, string password)
{
LoginPayload payload = new LoginPayload() { LoginId = id, Password = password};
var request = NewRequest(HttpMethod.Post, "login");
JsonPayload<LoginPayload>(payload, ref request);
return await Execute<Account>(request, false);
}
// 204: success, anything else failure
internal async Task<Boolean> LogOut ()
{
return await Execute<Boolean>(NewRequest(HttpMethod.Delete, "login"), true);
}
internal async Task<HttpResponseMessage> GetRawResponse ()
{
return await Execute<HttpResponseMessage>(NewRequest(HttpMethod.Get, "raw/something"), true);
}
internal async Task<Int32> GetMeStatusCode ()
{
return await Execute<Int32>(NewRequest(HttpMethod.Get, "some/intstatus"), true);
}
private async Task<RESULT> Execute<RESULT>(HttpRequestMessage request, bool authenticate)
{
if (authenticate)
AuthenticateRequest(ref request); // add auth token to request
var tcs = new TaskCompletionSource<RESULT>();
var response = await client.SendAsync(request);
// TODO: If the RESULT is just HTTPResponseMessage, the rest is unnecessary
if (response.IsSuccessStatusCode)
{
try
{
// TryParse needs to handle Boolean differently than other types
RESULT result = await TryParse<RESULT>(response);
tcs.SetResult(result);
}
catch (Exception e)
{
tcs.SetException(e);
}
}
else
{
try
{
APIError error = await TryParse<APIError>(response);
tcs.SetException(new APIException(error));
}
catch (Exception e)
{
tcs.SetException(new APIException("Unknown error"));
}
}
return tcs.Task.Result;
}
これはAPIError
JSON構造です(ステータスコード+カスタムエラーコードです)。
{
"status": 404,
"code":216,
"msg":"User not found"
}
System.Net
のままにしておきたいのですが、それは主に、すべてのコードを切り替えたくないためです。私が望むことが他の方法でより簡単に行われるのであれば、それは明らかに余分な作業の価値があります。
ありがとう。
したがって、最初にNewtonsoft.Json
コメントが必要ですが、私はまだその必要性を感じていません。これまでのところ、組み込みのサポートがうまく機能することがわかりました(元の質問でAPIError
Jsonを使用:
[DataContract]
internal class APIError
{
[DataMember (Name = "status")]
public int StatusCode { get; set; }
[DataMember (Name = "code")]
public int ErrorCode { get; set; }
}
また、(逆)シリアル化するJsonHelper
クラスを定義しました。
public class JsonHelper
{
public static T fromJson<T> (string json)
{
var bytes = Encoding.Unicode.GetBytes (json);
using (MemoryStream mst = new MemoryStream(bytes))
{
var serializer = new DataContractJsonSerializer (typeof (T));
return (T)serializer.ReadObject (mst);
}
}
public static string toJson (object instance)
{
using (MemoryStream mst = new MemoryStream())
{
var serializer = new DataContractJsonSerializer (instance.GetType());
serializer.WriteObject (mst, instance);
mst.Position = 0;
using (StreamReader r = new StreamReader(mst))
{
return r.ReadToEnd();
}
}
}
}
私がすでに働いていた上記のビット。期待される結果のタイプに基づいて各リクエストの実行を処理する単一のメソッドについては、変更処理方法(エラーなど)が簡単になりますが、複雑さが増し、したがって、私のコードの可読性。結局、別々のメソッドを作成しました(元の質問のExecute
メソッドのすべてのバリアント:
// execute and return response.StatusCode
private static async Task<HttpStatusCode> ExecuteForStatusCode (HttpRequestMessage request, bool authenticate = true)
// execute and return response without processing
private static async Task<HttpResponseMessage> ExecuteForRawResponse(HttpRequestMessage request, bool authenticate = true)
// execute and return response.IsSuccessStatusCode
private static async Task<Boolean> ExecuteForBoolean (HttpRequestMessage request, bool authenticate = true)
// execute and extract JSON payload from response content and convert to RESULT
private static async Task<RESULT> Execute<RESULT>(HttpRequestMessage request, bool authenticate = true)
不正な応答(現在のコードでは処理されていません)を新しいメソッドCheckResponse
に移動できます。このメソッドは、(たとえば)401を受信した場合にユーザーをログアウトします。