برای استفاده از JSON.NET در یک اکشن متد، به صورت معمولی میتوان به نحو ذیل عمل کرد:
[HttpGet] public ActionResult GetSimpleJsonData() { return new ContentResult { Content = JsonConvert.SerializeObject(new { id = 1 }), ContentType = "application/json", ContentEncoding = Encoding.UTF8 }; }
اگر بخواهیم این عملیات را کمی بهینهتر کنیم، نیاز است بتوانیم از استریمها استفاده کرده و خروجی JSON را بدون تبدیل به رشته، مستقیما در استریم response.Output بنویسیم. با اینکار به سرعت بیشتر و همچنین مصرف منابع کمتری خواهیم رسید.
نمونهای از این پیاده سازی را در ذیل مشاهده میکنید:
using System; using System.Web.Mvc; using Newtonsoft.Json; namespace MvcJsonNetTests.Utils { public class JsonNetResult : JsonResult { public JsonNetResult() { Settings = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Error }; } public JsonSerializerSettings Settings { get; set; } public override void ExecuteResult(ControllerContext context) { if (context == null) throw new ArgumentNullException("context"); if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) { throw new InvalidOperationException("To allow GET requests, set JsonRequestBehavior to AllowGet."); } if (this.Data == null) return; var response = context.HttpContext.Response; response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType; if (this.ContentEncoding != null) response.ContentEncoding = this.ContentEncoding; var serializer = JsonSerializer.Create(this.Settings); using (var writer = new JsonTextWriter(response.Output)) { serializer.Serialize(writer, Data); writer.Flush(); } } } }
در این حالت برای استفاده از این Action Result جدید میتوان نوشت:
[HttpGet] public ActionResult GetJsonData() { return new JsonNetResult { Data = new { Id = 1, Name = "Test 1" }, JsonRequestBehavior = JsonRequestBehavior.AllowGet, Settings = { ReferenceLoopHandling = ReferenceLoopHandling.Ignore } }; }
تا اینجا قسمت ارسال اطلاعات از سمت سرور به سمت کاربر بازنویسی شد. امکان بازنویسی و تعویض موتور پردازش JSON دریافتی از سمت کاربر، در سمت سرور نیز وجود دارد. خود ASP.NET MVC به صورت استاندارد توسط کلاسی به نام JsonValueProviderFactory، اطلاعات اشیاء JSON دریافتی از سمت کاربر را پردازش میکند. در اینجا نیز اگر دقت کنید از کلاس JavaScriptSerializer استفاده شدهاست.
برای جایگزینی آن باید یک ValueProvider جدید را تهیه کنیم:
using System; using System.Dynamic; using System.Globalization; using System.IO; using System.Web.Mvc; using Newtonsoft.Json; using Newtonsoft.Json.Converters; namespace MvcJsonNetTests.Utils { public class JsonNetValueProviderFactory : ValueProviderFactory { public override IValueProvider GetValueProvider(ControllerContext controllerContext) { if (controllerContext == null) throw new ArgumentNullException("controllerContext"); if (controllerContext.HttpContext == null || controllerContext.HttpContext.Request == null || controllerContext.HttpContext.Request.ContentType == null) { return null; } if (!controllerContext.HttpContext.Request.ContentType.StartsWith( "application/json", StringComparison.OrdinalIgnoreCase)) { return null; } using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream)) { var bodyText = reader.ReadToEnd(); return string.IsNullOrEmpty(bodyText) ? null : new DictionaryValueProvider<object>( JsonConvert.DeserializeObject<ExpandoObject>(bodyText, new JsonSerializerSettings { Converters = { new ExpandoObjectConverter() } }), CultureInfo.CurrentCulture); } } } }
در ادامه، اطلاعات JSON دریافتی به شکل یک رشتهی خام دریافت شده و سپس به متد JsonConvert.DeserializeObject ارسال میشود. با استفاده از تنظیم ExpandoObjectConverter، میتوان محدودیت کلاس JavaScriptSerializer را در مورد خواص و یا پارامترهای dynamic، برطرف کرد.
[HttpPost] public ActionResult TestValueProvider(string data1, dynamic data2)
و در آخر برای معرفی این ValueProvider جدید میتوان در فایل Global.asax.cs به نحو ذیل عمل نمود:
using System.Linq; using System.Web.Mvc; using System.Web.Routing; using MvcJsonNetTests.Utils; namespace MvcJsonNetTests { public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { AreaRegistration.RegisterAllAreas(); RouteConfig.RegisterRoutes(RouteTable.Routes); ValueProviderFactories.Factories.Remove( ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault()); ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory()); } } }
البته نگارش بعدی ASP.NET MVC موتور پردازشی JSON خود را از طریق تزریق وابستگیها دریافت میکند و از همان ابتدای کار قابل تنظیم و تعویض است. مقدار پیش فرض آن نیز به JSON.NET تنظیم شدهاست.
دریافت یک مثال کامل
MvcJsonNetTests.zip