2013-03-19 3 views
9

Я пытаюсь выйти из содержимого запроса API-интерфейса, то есть строки json. Я реализовал класс ITraceWriter (example) и настроил его так, чтобы веб-API вызывал его в конвейере. Но если я прочитаю запрос. Контент или копирование в поток для чтения, он недоступен для метода, приводящего к нулевой модели. This post переговоры об этом проблема немного. У кого-нибудь есть опыт выхода из входящего веб-запроса API-запроса и узнать, какой лучший подход?Ведение журнала входящего запроса ASP.NET Web API

Благодаря

Обновление

Я создал простой пример проекта Web API, чтобы исключить что-нибудь в моем проекте, и я все еще вижу, что модель будет аннулирована из-за лесозаготовок. Я просто тестирую несколько раз подряд, отправляя через Fidder и вижу, что моя модель имеет нулевое значение. С точками останова это может сработать, поэтому я думаю, что есть проблема синхронизации/синхронизации. Любые мысли о том, как заставить это работать?

Заголовок:

User-Agent: Fiddler 
Host: localhost:56824 
Content-Type: application/json 
Content-Length: 22 

тела:

{ 
"A":1,"B":"test" 
} 

Вот код:

Контроллер:

public class ValuesController : ApiController 
{ 
    [HttpPost] 
    public void Post(ValuesModel model) 
    { 
     if (model == null) 
     { 
      Debug.WriteLine("model was null!"); 
     } 
     else 
     { 
      Debug.WriteLine("model was NOT null!"); 
     } 
    } 
} 

Модель:

public class ValuesModel 
{ 
    public int A { get; set; } 
    public string B { get; set; } 
} 

Logger:

public class APITraceLogger : DelegatingHandler 
    { 
     protected override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
     { 
      if (request.Content != null) 
      { 
       // This can cause model to be null 
       request.Content.ReadAsStringAsync().ContinueWith(s => 
       { 
        string requestText = s.Result; 
        Debug.WriteLine(requestText); 
       }); 

       // and so can this 
       //request.Content.ReadAsByteArrayAsync() 
       // .ContinueWith((task) => 
       // { 
       //  string requestText = System.Text.UTF8Encoding.UTF8.GetString(task.Result); 
       //  Debug.WriteLine(requestText); 
       // }); 
      } 
      // Execute the request, this does not block 
      var response = base.SendAsync(request, cancellationToken); 

      // TODO: 
      // Once the response is processed asynchronously, log the response data 
      // to the database 


      return response; 
     } 


    } 

Подключение до регистратора в классе WebApiConfig:

config.MessageHandlers.Add(new APITraceLogger()); 

Update B

Похоже, он сейчас работает, если я изменю регистратор к следующий код добавляет ожидание, async и возвращает результат. Кажется, что я не понимаю в асинхронном коде или поистине проблема времени или что-то в этом роде.

public class APITraceLogger : DelegatingHandler 
{ 
    protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken) 
    { 
     if (request.Content != null) 
     { 

      // This does seem to work - is it because it is synchronous? Is this a potential problem? 
      var requestText = await request.Content.ReadAsStringAsync(); 
      Debug.WriteLine(requestText); 
     } 
     // Execute the request, this does not block 
     var response = base.SendAsync(request, cancellationToken); 

     // TODO: 
     // Once the response is processed asynchronously, log the response data 
     // to the database 


     return response.Result; 
    } 


} 

ответ

5

Как Филип упоминает в этом пост ReadAsStringAsync или способы ReadAsByteArrayAsync буфера содержание запроса внутри. Это означает, что даже если тип потока входящего запроса является небуферизованным потоком, вы можете безопасно выполнить ReadAsStringAsync/ReadAsByteArrayAsync, например, в обработчике сообщений, а также ожидать, что привязка модели будет работать нормально.

По умолчанию поток запроса буферизуется как в случае с веб-хостом, так и в случае с самим собой. Но если вы хотите проверить, используя ReadAsStringAsync/ReadAsByteArrayAsync и модель выжидать отлично работают даже в небуферизованном режиме, вы можете выполнить следующие действия, чтобы заставить небуферизованный режим:

public class CustomBufferPolicySelector : WebHostBufferPolicySelector 
{ 
    public override bool UseBufferedInputStream(object hostContext) 
    { 
     //NOTE: by default, the request stream is always in buffered mode. 
     //return base.UseBufferedInputStream(hostContext); 

     return false; 
    } 
} 

config.Services.Replace(typeof(IHostBufferPolicySelector), new CustomBufferPolicySelector()); 

Просто FYI ... выше Селектор политик работает только для веб-хостинга.Если вы хотели бы сделать подобный тест в SelfHost, то сделайте следующее:

//NOTE: by default, the transfer mode is TransferMode.Buffered 
config.TransferMode = System.ServiceModel.TransferMode.StreamedRequest; 

После обновления B поста выше:

Вы можете изменить свой обработчик, как показано ниже:

public class LoggingHandler : DelegatingHandler 
{ 
    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 
    { 
     if (request.Content != null) 
     { 
      string requestContent = await request.Content.ReadAsStringAsync(); 
     } 

     HttpResponseMessage response = await base.SendAsync(request, cancellationToken); 

     if (response.Content != null) 
     { 
      string responseContent = await response.Content.ReadAsStringAsync(); 
     } 

     return response; 
    } 
} 
+0

Я был брошен этим комментарием Филиппа. Я использовал ReadAsStringAsync, и моя модель была бы нулевой. Вот базовый код, который я использовал в реализации ITraceWriter: request.Content.ReadAsStringAsync(). ContinueWith (s => {} string requestText = s.Result; Logger.Log (requestText); }); – Bryan

+0

Я не могу воспроизвести проблему, о которой вы упоминаете. Например (не лучший способ сделать это), у меня есть следующий код в методе WriteTrace SimpleTracer из образца Майка Уосона: if (rec.Request! = Null) {Console.WriteLine (rec.Category + "," + rec.Request.Content.ReadAsStringAsync() Результат). } –

+0

Спасибо за попытку воспроизведения. Попытка выяснить, что другое. Я использую MVC 4 и работаю в IIS Express для своего локального разработчика. Возможно, IIS Express - это разница. Я пытаюсь что-то другое и вернусь. – Bryan

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