簡體   English   中英

通過HTTPClient.PostAsJsonAsync調用的JsonConverter中的HttpContext不可用

[英]HttpContext unavailable in JsonConverter called via HTTPClient.PostAsJsonAsync

設置

  1. 我有一個WebAPI控制器,它使用HttpClient.PostAsJsonAsync調用Web終結點
  2. 假設控制器方法的響應和對Web端點的請求是相同的實體類型
  3. 我已經為此實體類型注冊了一個自定義JsonConverter。 我有一個用例在此轉換器中訪問HttpContext

問題 :當調用轉換器的WriteJson方法以在HttpClient.PostAsJsonAsync期間將實體序列化時,HttpContext.Current為NULL。

但是,當在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());
    }
}

如此答案中所述HttpContext.Current實際上是線程靜態的,因此可能發生的是HttpClient.PostAsJsonAsync()實際上是在單獨的線程上進行序列化的,該線程尚未初始化HttpContext.Current 盡管等待的async任務不一定要在單獨的線程上運行,但它可能是-尤其是因為Json.NET不直接支持異步序列化,而是建議使用Task.Factory.StartNew()

要變通解決此問題,我建議從序列化內部刪除對全局狀態的依賴。 備選方案包括:

  1. ApiController方法內部,從HttpContext和每個Entity構造一個適當的數據傳輸對象 ,然后對它們進行序列化。

  2. HttpContext的必要信息緩存在Entity構造函數中,以便在序列化期間使用:

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

    緩存HttpContext本身可能不是一個好主意,因為文檔指出

    此類型的任何公共static(在Visual Basic中為Shared)成員都是線程安全的。 不保證任何實例成員都是線程安全的。

  3. 對於對PostAsJsonAsync()的調用,您可以預序列化為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); 

    這仍然保留了序列化內部對全局狀態的依賴,這可能會在以后引起問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM