2016-08-20 3 views
0

УстановкаHttpContext недоступен в JsonConverter вызывается через HTTPClient.PostAsJsonAsync

  1. У меня есть контроллер WebAPI, что делает вызов на веб-конечной точки, используя HttpClient.PostAsJsonAsync
  2. Допустим, что ответ метода контроллера и запрос к веб-конечной точке - это тот же тип объекта
  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()); 
    } 
} 
+0

Не могли бы вы просто попробовать с полным пространством имен - System.Web.HttpContext.Current – Developer

ответ

1

Как объяснен в this answer, HttpContext.Current это на самом деле нити статический, так что возможно происходит то, что HttpClient.PostAsJsonAsync() на самом деле делают сериализации в отдельном потоке, один, на котором HttpContext.Current не был инициализирован. Хотя ожидаемая задача async не обязательно будет запускаться в отдельном потоке, это может быть особенно, поскольку Json.NET не поддерживает асинхронную сериализацию напрямую, а вместо recommends using Task.Factory.StartNew().

Чтобы решить эту проблему, я рекомендую удалить зависимость от глобального состояния изнутри сериализации. Альтернативы включают в себя:

  1. Внутри ваших ApiController методов, построить соответствующий data transfer object из HttpContext и каждого Entity, и сериализовать их вместо.

  2. Cache необходимую информацию из HttpContext внутри Entity конструктора для использования во время сериализации:

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

    Кэширование сам HttpContext не может быть хорошей идеей, так как documentation состояний

    Любые открытые (Shared in Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют безопасность потоков.

  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); 
    

    Это по-прежнему оставляет зависимость от глобального состояния внутри сериализации, что может вызвать проблемы в дальнейшем.

Смежные вопросы