[英]HttpContext unavailable in JsonConverter called via HTTPClient.PostAsJsonAsync
The setup 设置
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:
备选方案包括:
Inside your ApiController
methods, construct an appropriate data transfer object from the HttpContext
and each Entity
, and serialize those instead. 在
ApiController
方法内部,从HttpContext
和每个Entity
构造一个适当的数据传输对象 ,然后对它们进行序列化。
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.
不保证任何实例成员都是线程安全的。
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.