2012-11-22 2 views
1

Я очень смущаюсь о новой платформе Microsoft, ASP.NET MVC WebAPI. Я пытаюсь создать полное решение для межсайтового API с данными JSONP.Почему WebAPI не использует форматирование JSONP для десериализации модели?

Во-первых, я изменяю свой WebApiConfig по умолчанию на следующий код.

public static class WebApiConfig 
{ 
    public static void Register(HttpConfiguration config) 
    { 
     config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}/{id}", new {id = RouteParameter.Optional}); 

     // Custom customization 
     config.Formatters.Clear(); 
     config.Formatters.Add(new JsonpFormatter()); 
    } 
} 

Я использую jQuery для создания запроса на этот веб-сайт API.

// jQuery will create HTTP GET the following URL 
// http://localhost:3557/api/FlightAvailability/SearchFlight?callback=jQuery18206342989655677229_1353568617029&origin=JFK&destination=SLC&isOneWayFlight=false&departFlightDate=Wed%2C+28+Nov+2012+17%3A00%3A00+GMT&returnFlightDate=Wed%2C+05+Dec+2012+17%3A00%3A00+GMT&numberOfGuests=1&numberOfChildren=1&numberOfInfants=1&preferredCurrency=USD&query=%7B+Origin%3A+'JFK'+%7D&flightDate=Wed%2C+28+Nov+2012+17%3A00%3A00+GMT&_=1353568618465 

$.ajax 
({ 
    url: 'http://localhost:3557/api/FlightAvailability/SearchFlight', 
    dataType: 'jsonp', 
    data: $.postify(model), 
    success: processResponse 
}); 

Я создаю действие для обработки вышеуказанного запроса. Все правильно. Я могу вызвать это действие, но WebAPI не использует форматирование JSONP для десериализации моего объекта запроса.

Однако я пытаюсь напрямую вызвать ContentNegotiator, чтобы получить тот форматтер, который обрабатывает мой запрос. Удивительно, что переговорщик - это мой форматировщик JSONP.

[HttpGet] 
public List<FlightInfo> SearchFlight(FlightAvailabilityQuery query) 
{ 
    var negotiator = Configuration.Services.GetContentNegotiator(); 
    var negotiatorResult = negotiator.Negotiate(typeof (FlightAvailabilityQuery), Request, Configuration.Formatters); 

    var flight = new FlightsAvailability(); 

    var result = flight.GetAvailability(WebApiAuthentication.UserInfo.SessionService, query); 

    return result; 
} 

Почему WebAPI не использует мой JSONP форматировщик десериализации объекта запроса FlightAvailabilityQuery?

enter image description here

PS. Я пытаюсь сломать всю возможную строку в форматировщике JSONP, но Visual Studio не попадает ни в какую точку прерывания, она напрямую переходит к методу действия без вызова в моем единственном форматировании. Однако, когда я напрямую вызываю ContentNegotiator, он правильно попадает в точку прерывания.

Update # 1 - Добавить JSONP источник форматировщик код

public class JsonpFormatter : JsonMediaTypeFormatter 
{ 
    private readonly JsonSerializerSettings _serializerSettings; 
    private string _jsonpCallbackFunction; 

    public JsonpFormatter() 
    { 
     JsonpParameterName = "callback"; 
     _serializerSettings = new JsonSerializerSettings(); 
     _serializerSettings.TypeNameHandling = TypeNameHandling.Objects; 
     _serializerSettings.Converters.Add(new IsoDateTimeConverter()); 

     MediaTypeMappings.Add(new ExtendedQueryStringMapping(JsonpParameterName, "application/json")); 
    } 

    public string JsonpParameterName { get; set; } 

    public override bool CanReadType(Type type) 
    { 
     return true; 
    } 

    public override bool CanWriteType(Type type) 
    { 
     return true; 
    } 

    public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, HttpRequestMessage request, MediaTypeHeaderValue mediaType) 
    { 
     var formatter = new JsonpFormatter() 
     { 
      _jsonpCallbackFunction = GetJsonCallbackFunction(request) 
     }; 

     // this doesn't work unfortunately 
     //formatter.SerializerSettings = GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings; 

     formatter.SerializerSettings.Converters.Add(new StringEnumConverter()); 
     formatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver(); 
     formatter.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented; 

     return formatter; 
    } 

    public override Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContent content, IFormatterLogger formatterLogger) 
    { 
     // Create a serializer 
     var serializer = JsonSerializer.Create(_serializerSettings); 

     // Create task reading the content 
     return Task.Factory.StartNew(() => 
     { 
      using (var streamReader = new StreamReader(stream, Encoding.UTF8)) 
      { 
       using (var jsonTextReader = new JsonTextReader(streamReader)) 
       { 
        return serializer.Deserialize(jsonTextReader, type); 
       } 
      } 
     }); 
    } 

    public override Task WriteToStreamAsync(Type type, object value, Stream stream, HttpContent content, TransportContext transportContext) 
    { 
     if (string.IsNullOrEmpty(_jsonpCallbackFunction)) 
      return base.WriteToStreamAsync(type, value, stream, content, transportContext); 

     StreamWriter writer = null; 

     // write the pre-amble 
     try 
     { 
      writer = new StreamWriter(stream); 
      writer.Write(_jsonpCallbackFunction + "("); 
      writer.Flush(); 
     } 
     catch (Exception ex) 
     { 
      try 
      { 
       if (writer != null) 
        writer.Dispose(); 
      } 
      catch { } 

      var tcs = new TaskCompletionSource<object>(); 
      tcs.SetException(ex); 
      return tcs.Task; 
     } 

     return base.WriteToStreamAsync(type, value, stream, content, transportContext) 
        .ContinueWith(innerTask => 
         { 
          if (innerTask.Status == TaskStatus.RanToCompletion) 
          { 
           writer.Write(")"); 
           writer.Flush(); 
          } 

         }, TaskContinuationOptions.ExecuteSynchronously) 
        .ContinueWith(innerTask => 
         { 
          writer.Dispose(); 
          return innerTask; 

         }, TaskContinuationOptions.ExecuteSynchronously) 
        .Unwrap(); 
    } 

    private string GetJsonCallbackFunction(HttpRequestMessage request) 
    { 
     if (request.Method != HttpMethod.Get) 
      return null; 

     var query = HttpUtility.ParseQueryString(request.RequestUri.Query); 
     var queryVal = query[this.JsonpParameterName]; 

     if (string.IsNullOrEmpty(queryVal)) 
      return null; 

     return queryVal; 
    } 
} 
+0

Я думаю, что я мог бы неправильно понять некоторые концепции WebAPI. Я трачу почти 3 дня на работу над этой проблемой, но я никогда не нашел полного решения для JSONP. –

+0

BTW, ContentNegotiator используется только на стороне ответа ...но я удивлен, почему вы видите это поведение, учитывая, что у вас есть только один форматировщик, который является форматировщиком JsonP, и это должно было быть использовано для десериализации запроса ... возможно ли вам поделиться своим кодом приложения? –

+0

Что предлагает метод ReadFromStreamAsync? Вначале я пытаюсь создать некоторый пользовательский класс HttpParameterBinding для десерилизации модели. –

ответ

1

Ваше действие не получить удар, потому что он не может моделировать связать свой параметр запроса. Также JsonP предназначен только для HTTP GET, поэтому ваш форматтер не будет выбран для десериализации. Как вы ожидаете, что ваш FlightAvailabilityQuery является deserialized? Я видел много параметров запроса с вашего URL, вы хотите, чтобы это было превращено в FlightAvailabilityQuery?

Самый простой способ получить это - использовать FromUri.

public List<FlightInfo> SearchFlight([FromUri]FlightAvailabilityQuery query)

Если по какой-то причине не работает, вы можете попробовать добавить имя параметра индивидуальный запрос на действия, такие как происхождение, isOneWay, пункт назначения. и т. Д. Затем внутри вашего действия создайте объект FlightAvailabilityQuery. Кроме того, если у вас есть много действий, которые вы хотите повторно использовать эту логику привязки модели, вы можете зарегистрировать привязку настраиваемого параметра для ее решения. Пожалуйста, см. this link, как зарегистрировать привязку настраиваемого параметра для решения этой проблемы.

Надеюсь, это поможет!

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

  • Нет связанных вопросов^_^