【问题标题】:jsonp media type formatter c# issuejsonp媒体类型格式化程序c#问题
【发布时间】:2013-07-09 22:12:56
【问题描述】:

可能是一个愚蠢的问题,但我正在尝试将 jsonp 支持添加到我的 webapi 应用程序中。我将此行添加到我的 webapiconfig.cs,但它失败了,因为 jsonpmediatypeformatter 构造函数需要 2 个参数:

 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();**
    }

其中第一个似乎是 mediatypeformatter 类型,这对我来说没有多大意义。我试过了:

configuration.Formatters.Insert(0, new JsonpMediaTypeFormatter(new JsonMediaTypeFormatter(),"jsonp"));

它确实将响应正确地包装在一个名为 jsonp 的函数中,但也破坏了标准的 json 响应。

有什么想法吗?

【问题讨论】:

  • 我认为由于 WebAPI 的默认序列化程序是 JSON.NET,因此需要将 mediatypeformatter 组合到一个子类中才能使 json 和 jsonp 工作(我使用的是 WebapiContrib.Formatting.Jsonp nuget包裹)。我在这里找到了一个似乎可以解决问题的解决方案:west-wind.com/weblog/posts/2012/Apr/02/…

标签: c# .net asp.net-mvc asp.net-mvc-4 jsonp


【解决方案1】:

我也花了很长时间才让它工作。此代码基于 https://gist.github.com/ninnemana/3715076 - 这对我不起作用,因为 HttpContext.Current 使用 .NET 框架的 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);
        }
    }

这需要添加到您的启动中:

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

【讨论】:

    【解决方案2】:

    所以,我已经阅读了大量关于向 WebAPI 添加 JSONP 支持的文章。我都试过了。

    然后,我花时间阅读了我一直在使用的常规 Json 格式化程序......嘿,它也支持 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。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 2020-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多