2016-08-20 14 views
0

セットアップのHttpContext HTTPClient.PostAsJsonAsync経由で呼び出さJsonConverterでは使用できません

  1. 私が使用して、ウェブのエンドポイントへの呼び出しを行うWebAPIのコントローラーを、しましたHttpClient.PostAsJsonAsync
  2. 、のは言わせていますコントローラメソッドのレスポンスとWebエンドポイントへのリクエストは同じエンティティタイプです
  3. このエンティティタイプに対してカスタムJsonConverterが登録されました。 HttpClient.PostAsJsonAsync、HttpContext.CurrentがNULLである時に、コンバータのWriteJsonメソッドが呼び出されたときに、エンティティをシリアル化するために:私はこのコンバータ

問題でのHttpContextにアクセスするためのユースケースを持っています。

しかし、WebAPIレスポンスでエンティティをシリアライズするときに同じフローが呼び出されると、コンテキストは正常に利用できます。

誰も以前に同様の問題に直面していますか?私はこの問題の原因が何であるか、解決策/回避策の可能性については不明です。

サンプルWebAPIプロジェクトでこの動作を再現できます。ここにある関連するコードは、切れ端:

[JsonConverter(typeof(EntityConverter))] 
public interface IEntity 
{ 
} 

public class Entity : IEntity 
{ 
} 

public class EntityConverter : JsonConverter 
{ 
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     // httContext is NULL when deserializing the HttpClient request entity 
     var httpContext = HttpContext.Current; 
     var principal = httpContext?.User; 
     Console.WriteLine(""); 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     return new Entity(); 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return typeof(Entity) == objectType; 
    } 
} 

public class ValuesController : ApiController 
{ 
    // POST api/values 
    public async Task<HttpResponseMessage> Post([FromBody]string value) 
    { 
     HttpClient client = new HttpClient(); 
     var message = await client.PostAsJsonAsync("http://example.com", new Entity()); 
     Console.WriteLine(message); 

     return Request.CreateResponse(HttpStatusCode.Created, new Entity()); 
    } 
} 
+0

あなたは完全な名前空間で試すことができますか - System.Web.HttpContext.Current – Developer

答えて

1

としてはthis answerに説明し、HttpContext.Currentがそう起こっHttpClient.PostAsJsonAsync()は、実際に、別のスレッドでシリアル化を行っているということです可能性ものです、実際のスレッドに静的であるその一つHttpContext.Currentに初期化されていません。 asyncタスクは必ずしも別のスレッドで実行されるとは限りませんが、特にJson.NETは非同期シリアル化を直接サポートせず、代わりにrecommends using Task.Factory.StartNew()をサポートしているためです。

問題を回避するには、内部状態からグローバル状態への依存関係を削除することをお勧めします。 HttpContextEntityから適切なdata transfer objectを構築し、あなたのApiController方法インサイド

  1. を、代わりにそれらをシリアル化:選択肢があります。

  2. キャッシュシリアライズ時に使用するEntityコンストラクタの内部HttpContextから必要な情報:

    public class Entity : IEntity 
    { 
        protected internal readonly IPrincipal Principal = HttpContext.Current?.User; 
    } 
    

    HttpContext自体のキャッシュはdocumentation状態

    すべてのパブリックstatic以来、良いアイデアではないかもしれません(Visual BasicではShared)メンバはスレッドセーフです。どのインスタンスメンバーもスレッドセーフであるとは限りません。PostAsJsonAsync()への呼び出しのために

  3. あなたはJTokenに予めシリアライズ可能性があり、その投稿:

    var entity = new Entity(); 
    var formatter = new System.Net.Http.Formatting.JsonMediaTypeFormatter(); 
    // Or use GlobalConfiguration.Configuration.Formatters.JsonFormatter; 
    var token = JToken.FromObject(entity, JsonSerializer.Create(formatter.SerializerSettings)); 
    
    HttpClient client = new HttpClient(); 
    var message = await client.PostAsJsonAsync("http://example.com", token); 
    Console.WriteLine(message); 
    

    これはまだ、後に問題を引き起こす可能性がある、シリアライズ内のグローバル状態への依存を残します。

関連する問題