2013-07-11 7 views
0

아마도 멍청한 질문이지만 내 webapi 응용 프로그램에 jsonp 지원을 추가하려고합니다. 내 webapiconfig.cs이 라인을 추가했지만이 개 인수가 jsonpmediatypeformatter 생성자 예상되기 때문에 그것은 실패하는 것 : 타입 mediatypeformatter이 될 것으로 보인다jsonp 미디어 형식 포매터 C# 문제

public static void Register(HttpConfiguration configuration) 
    { 
     configuration.Routes.MapHttpRoute("API Default", "api/v1/{controller}/{id}", 
      new { id = RouteParameter.Optional }); 

     var appXmlType = configuration.Formatters.XmlFormatter.SupportedMediaTypes.FirstOrDefault(t => t.MediaType == "application/xml"); 
     configuration.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType); 
     **configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter();** 
    } 

처음있는 나에게 많은 이해가되지 않습니다 . 시도 : jsonp라는 함수에서 응답을 올바르게 래핑하지만 표준 json 응답도 중단합니다.

아이디어가 있으십니까?

+0

의 mediatypeformatter은 할 필요가 json과 jsonp가 모두 작동하도록 단일 하위 클래스로 결합되었습니다 (WebapiContrib.Formatting.Jsonp Nuget 패키지를 사용함). 트릭을 수행하는 것으로 보이는 해결책을 찾았습니다. http://www.west-wind.com/weblog/posts/2012/Apr/02/Creating-a-JSONP-Formatter-for-ASPNET-Web- API – AesopWaits

답변

1

그래서 WebAPI에 JSONP 지원을 추가하는 방법에 대한 내용을 읽었습니다. 나는 그들 모두에 대해 시도했다.

그런 다음 Jsonp 포맷을 읽는 데 시간이 걸렸습니다. 필자도 Jsonp를 지원합니다.

public class JsonNetFormatter : MediaTypeFormatter 
{ 
    private readonly JsonSerializerSettings _jsonSerializerSettings; 
    private string _callbackQueryParameter; 

    public JsonNetFormatter(JsonSerializerSettings jsonSerializerSettings) 
    { 
     _jsonSerializerSettings = jsonSerializerSettings ?? new JsonSerializerSettings(); 

     // Fill out the mediatype and encoding we support 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/json")); 
     SupportedEncodings.Add(new UTF8Encoding(false, true)); 

     //we also support jsonp. 
     SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/javascript")); 
    } 

    private Encoding Encoding 
    { 
     get { return SupportedEncodings[0]; } 
    } 

    public string CallbackQueryParameter 
    { 
     get { return _callbackQueryParameter ?? "callback"; } 
     set { _callbackQueryParameter = value; } 
    } 

    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 JsonNetFormatter(_jsonSerializerSettings) 
     { 
      JsonpCallbackFunction = GetJsonCallbackFunction(request) 
     }; 

     return formatter; 
    } 

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

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

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

     return queryVal; 
    } 

    private string JsonpCallbackFunction { get; set; } 

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

     // Create task reading the content 
     return Task.Factory.StartNew(() => 
     { 
      using (var streamReader = new StreamReader(readStream, SupportedEncodings[0])) 
      { 
       using (var jsonTextReader = new JsonTextReader(streamReader)) 
       { 
        return serializer.Deserialize(jsonTextReader, type); 
       } 
      } 
     }); 
    } 

    public override Task WriteToStreamAsync(Type type, object value, Stream writeStream, HttpContent content, TransportContext transportContext) 
    { 
     var isJsonp = JsonpCallbackFunction != null; 

     // Create a serializer 
     JsonSerializer serializer = JsonSerializer.Create(_jsonSerializerSettings); 

     // Create task writing the serialized content 
     return Task.Factory.StartNew(() => 
     { 
      using (var jsonTextWriter = new JsonTextWriter(new StreamWriter(writeStream, Encoding)) { CloseOutput = false }) 
      { 
       if (isJsonp) 
       { 
        jsonTextWriter.WriteRaw(JsonpCallbackFunction + "("); 
        jsonTextWriter.Flush(); 
       } 

       serializer.Serialize(jsonTextWriter, value); 
       jsonTextWriter.Flush(); 

       if (isJsonp) 
       { 
        jsonTextWriter.WriteRaw(")"); 
        jsonTextWriter.Flush(); 
       } 
      } 
     }); 
    } 
} 

이 그런 다음 global.asax.cs이 작은 아름다움 추가 :

private static void AddJsonFormatterAndSetDefault() 
    { 
     var serializerSettings = new JsonSerializerSettings(); 
     serializerSettings.Converters.Add(new IsoDateTimeConverter()); 
     var jsonFormatter = new JsonNetFormatter(serializerSettings); 
     jsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html")); 
     GlobalConfiguration.Configuration.Formatters.Insert(0, jsonFormatter); 
    } 

를 그리고 위해 Application_Start

에서 호출이 나를 위해 작동 여기

는 클래스입니다 json과 jsonp를 모두 지원합니다.

2

작동시키기까지 오래 걸렸습니다. 이 코드는 https://gist.github.com/ninnemana/3715076을 기반으로합니다. HttpContext.Current이 .NET Framework 4.5 버전에서 null을 반환하기 때문에 저에게 적합하지 않습니다.

클래스입니다 :

public class JsonpMediaTypeFormatter : JsonMediaTypeFormatter 
    { 

     private string _callbackQueryParamter; 
     private HttpRequestMessage HttpRequest; 

     public JsonpMediaTypeFormatter() 
     { 
      SupportedMediaTypes.Add(DefaultMediaType); 
      SupportedMediaTypes.Add(new MediaTypeWithQualityHeaderValue("text/javascript")); 

      MediaTypeMappings.Add(new UriPathExtensionMapping("jsonp", DefaultMediaType)); 
     } 


     public string CallbackQueryParameter 
     { 
      get { return _callbackQueryParamter ?? "callback"; } 
      set { _callbackQueryParamter = value; } 
     } 

     public override MediaTypeFormatter GetPerRequestFormatterInstance(Type type, 
              HttpRequestMessage request, MediaTypeHeaderValue mediaType) 
     { 
      HttpRequest = request; 
      return base.GetPerRequestFormatterInstance(type, request, mediaType); 
     } 

     public override System.Threading.Tasks.Task WriteToStreamAsync(Type type, object value, System.IO.Stream writeStream, System.Net.Http.HttpContent content, System.Net.TransportContext transportContext) 
     { 
      string callback; 

      if (IsJsonpRequest(out callback)) 
      { 
       return Task.Factory.StartNew(() => 
       { 
        var writer = new StreamWriter(writeStream); 
        writer.Write(callback + "("); 
        writer.Flush(); 
        base.WriteToStreamAsync(type, value, writeStream, content, transportContext).Wait(); 
        writer.Write(")"); 
        writer.Flush(); 
       }); 
      } 
      return base.WriteToStreamAsync(type, value, writeStream, content, transportContext); 
     } 

     private bool IsJsonpRequest(out string callback) 
     { 
      var query = HttpUtility.ParseQueryString(HttpRequest.RequestUri.Query); 
      callback = query[CallbackQueryParameter]; 

      return !string.IsNullOrEmpty(callback); 
     } 
    } 

그리고이 시동에 추가해야합니다 : 나는 WebAPI의 기본 시리얼 라이저는 JSON.NET 때문에 생각

public class Startup 
    { 
     // This code configures Web API. The Startup class is specified as a type 
     // parameter in the WebApp.Start method. 
     public void Configuration(IAppBuilder appBuilder) 
     { 
      // Configure Web API for self-host. 
      HttpConfiguration config = new HttpConfiguration(); 

      // Remove the XML formatter (only want JSON) see http://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization 
      config.Formatters.Remove(config.Formatters.XmlFormatter); 
      // add jsonp formatter as the one with the highest prio 
      config.Formatters.Insert(0, new JsonpMediaTypeFormatter()); 

      // routes 

      config.Routes.MapHttpRoute(
       name: "DefaultApi", 
       routeTemplate: "api/{controller}/{arg1}/{arg2}", 
       defaults: new { arg1 = RouteParameter.Optional, arg2 = RouteParameter.Optional } 
      ); 

      appBuilder.UseWebApi(config); 
     } 
    }