简体   繁体   English

通过HTTPClient.PostAsJsonAsync调用的JsonConverter中的HttpContext不可用

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

The setup 设置

  1. I've a WebAPI Controller, that makes a call to a web endpoint, using HttpClient.PostAsJsonAsync 我有一个WebAPI控制器,它使用HttpClient.PostAsJsonAsync调用Web终结点
  2. Let's say, that the response of the controller method and the request to the web endpoint is the same entity type 假设控制器方法的响应和对Web端点的请求是相同的实体类型
  3. I've a custom JsonConverter registered for this entity type. 我已经为此实体类型注册了一个自定义JsonConverter。 I have a use case to access the HttpContext in this converter 我有一个用例在此转换器中访问HttpContext

The issue : when the converter's WriteJson method is invoked, to serialize the entity during HttpClient.PostAsJsonAsync, HttpContext.Current is NULL. 问题 :当调用转换器的WriteJson方法以在HttpClient.PostAsJsonAsync期间将实体序列化时,HttpContext.Current为NULL。

However, when the same flow is invoked when serializing the entity in WebAPI response the context is available fine. 但是,当在WebAPI响应中序列化实体时调用相同的流程时,上下文可用。

Has anyone faced similar issues before? 有人遇到过类似的问题吗? I'm not sure what the cause of this issue is and what could be possible solutions / workarounds. 我不确定导致此问题的原因是什么以及可能的解决方案/解决方法。

I am able to re-produce this behavior with a sample WebAPI project. 我可以使用示例WebAPI项目来重现此行为。 Here are the relevant code snips: 以下是相关的代码片段:

[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());
    }
}

As explained in this answer , HttpContext.Current is in fact thread static, so what is possibly happening is that HttpClient.PostAsJsonAsync() is actually doing the serialization on a separate thread, one on which HttpContext.Current has not been initialized. 如此答案中所述HttpContext.Current实际上是线程静态的,因此可能发生的是HttpClient.PostAsJsonAsync()实际上是在单独的线程上进行序列化的,该线程尚未初始化HttpContext.Current While an awaited async task will not necessarily be run on a separate thread, it might be - especially since Json.NET doesn't support asynchronous serialization directly and instead recommends using Task.Factory.StartNew() . 尽管等待的async任务不一定要在单独的线程上运行,但它可能是-尤其是因为Json.NET不直接支持异步序列化,而是建议使用Task.Factory.StartNew()

To work around the issue, I'd recommend removing dependency on global state from inside serialization. 要变通解决此问题,我建议从序列化内部删除对全局状态的依赖。 Alternatives include: 备选方案包括:

  1. Inside your ApiController methods, construct an appropriate data transfer object from the HttpContext and each Entity , and serialize those instead. ApiController方法内部,从HttpContext和每个Entity构造一个适当的数据传输对象 ,然后对它们进行序列化。

  2. Cache the necessary information from HttpContext inside the Entity constructor for use during serialization: HttpContext的必要信息缓存在Entity构造函数中,以便在序列化期间使用:

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

    Caching the HttpContext itself might not be a good idea since the documentation states 缓存HttpContext本身可能不是一个好主意,因为文档指出

    Any public static (Shared in Visual Basic) members of this type are thread safe. 此类型的任何公共static(在Visual Basic中为Shared)成员都是线程安全的。 Any instance members are not guaranteed to be thread safe. 不保证任何实例成员都是线程安全的。

  3. For the call to PostAsJsonAsync() you could pre-serialize to a JToken then post that: 对于对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); 

    This still leaves the dependency on global state inside serialization, which may cause problems later on. 这仍然保留了序列化内部对全局状态的依赖,这可能会在以后引起问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 HttpClient.PostAsJsonAsync引发TaskCanceledException - HttpClient.PostAsJsonAsync throws TaskCanceledException HttpClient.PostAsJsonAsync 无法从 ASPX 工作的问题 - Issue with HttpClient.PostAsJsonAsync Not Working from ASPX HttpClient.PostAsJsonAsync 无一例外地崩溃了 - HttpClient.PostAsJsonAsync crushed without exception HttpClient.PostAsJsonAsync崩溃而不抛出异常 - HttpClient.PostAsJsonAsync crashing without throwing exception HttpClient.PostAsJsonAsync与MVC控制器动作之间的通信 - Communication between HttpClient.PostAsJsonAsync and MVC controller actions HttpClient.PostAsJsonAsync永远不会看到帖子成功和响应的时间 - HttpClient.PostAsJsonAsync never sees when the post is succeeding and responding 如何从httpClient.PostAsJsonAsync绑定JSON响应 - How to bind JSON response from httpClient.PostAsJsonAsync C# HttpClient.PostAsJsonAsync 因内部服务器错误而失败 - C# HttpClient.PostAsJsonAsync Failing with Internal Server Error C#HttpClient.PostAsJsonAsync()失败,即使通过PostMan发出的请求是完全相同的请求 - C# HttpClient.PostAsJsonAsync() fails, even though the exact same request is accepted when made through PostMan 如何确定HttpClient.PostAsJsonAsync调用上500错误的问题是什么? - How do I determine what is the issue with a 500 error on a HttpClient.PostAsJsonAsync call?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM