设置
问题:调用转换器的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());
}
}
答案 0 :(得分:1)
正如this answer中所解释的,HttpContext.Current
实际上是线程静态的,所以可能发生的是HttpClient.PostAsJsonAsync()
实际上是在单独进行序列化线程,其中HttpContext.Current
尚未初始化的线程。虽然等待async
任务不一定会在单独的线程上运行,但它可能是 - 尤其是因为Json.NET不直接支持异步序列化而是recommends using Task.Factory.StartNew()
。
要解决此问题,我建议从序列化内部删除对全局状态的依赖。替代方案包括:
在ApiController
方法中,从HttpContext
和每个Entity
构建一个合适的data transfer object,并将其序列化。
从HttpContext
构造函数中的Entity
缓存必要信息,以便在序列化期间使用:
public class Entity : IEntity
{
protected internal readonly IPrincipal Principal = HttpContext.Current?.User;
}
以来缓存HttpContext
本身可能不是一个好主意
此类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的。任何实例成员都不保证是线程安全的。
对于PostAsJsonAsync()
的来电,您可以预先序列化为JToken
,然后发布:{/ p>
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);
这仍然依赖于序列化中的全局状态,这可能会在以后引起问题。