এএসপি.নেট এমভিসি 3-তে ডিফল্ট জেএসএন সিরিয়ালাইজার হিসাবে JSON.NET ব্যবহার করা - এটি কি সম্ভব?


101

এএসপি.নেট এমভিসি 3 তে ডিফল্ট JSON সিরিয়ালাইজার হিসাবে JSON.NET ব্যবহার করা কি সম্ভব ?

আমার গবেষণা অনুসারে, মনে হয় এমভিসি 3 তে জেসনআরসাল্ট ভার্চুয়াল নয় বলে এটি সম্পাদনের একমাত্র উপায় অ্যাকশনারসাল্টকে প্রসারিত করা ...

আমি আশাবাদী যে এএসপি.নেট এমভিসি 3 এর সাথে জেএসএনে সিরিয়ালাইজ করার জন্য প্লাগেবল সরবরাহকারী নির্দিষ্ট করার উপায় থাকবে।

থটস?


উত্তর:


106

আমি বিশ্বাস করি এটি করার সর্বোত্তম উপায় হ'ল - আপনার লিঙ্কগুলিতে বর্ণিত হিসাবে - অ্যাকশনারসাল্ট প্রসারিত করা বা সরাসরি জসনরসাল্টকে প্রসারিত করা।

জাসনআরসাল্ট পদ্ধতিটি যা নিয়ামকটির পক্ষে ভার্চুয়াল নয় এটি সত্য নয়, কেবল সঠিক ওভারলোডটি চয়ন করুন। এটি ভাল কাজ করে:

protected override JsonResult Json(object data, string contentType, Encoding contentEncoding)

সম্পাদনা 1 : একটি জসনরসেল্ট এক্সটেনশান ...

public class JsonNetResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        var response = context.HttpContext.Response;

        response.ContentType = !String.IsNullOrEmpty(ContentType) 
            ? ContentType 
            : "application/json";

        if (ContentEncoding != null)
            response.ContentEncoding = ContentEncoding;

        // If you need special handling, you can call another form of SerializeObject below
        var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
        response.Write(serializedObject);
    }

সম্পাদনা 2 : আমি নীচের পরামর্শ অনুসারে ডেটা শূন্য হওয়ার জন্য চেকটি সরিয়েছি। এটি JQuery এর নতুন সংস্করণগুলি খুশি করা উচিত এবং করণীয় মতো বোধগম্য মনে হবে, কারণ প্রতিক্রিয়াটি তখন শর্তহীন deserialized করা যেতে পারে। তবে সচেতন থাকুন যে, এএসপি.নেট এমভিসি-র জেএসওএন প্রতিক্রিয়াগুলির জন্য এটি ডিফল্ট আচরণ নয় যা কোনও ডেটা নেই বলে খালি স্ট্রিংয়ের পরিবর্তে প্রতিক্রিয়া জানায়।


1
কোডটি মাইস্পেশিয়াল কনট্রাক্ট রিসোলভারকে বোঝায়, যা সংজ্ঞায়িত নয়। এই প্রশ্নের সঙ্গে সাহায্য করে (এবং খুব সমস্যা আমি সমাধান করতে ছিল সম্পর্কিত ছিল): stackoverflow.com/questions/6700053/...
Elliveny

1
দুর্দান্ত উত্তরের জন্য ধন্যবাদ। কেন যদি (ডেটা == নাল) ফিরে আসে; ? আমার ব্যবহারের ক্ষেত্রে আমি JSON স্ট্যান্ডার্ড যা ছিল তা ফিরে পেতে চেয়েছিলাম, যা জসন.নেট বিশ্বস্ততার সাথে করে, এমনকি নাল ("নাল" ফেরার জন্য)। সাইটে সময় 1.9.1 সঙ্গে - উদাহরণস্বরূপ নাল মান আটকাচ্ছে করে আপনি এই জন্য খালি স্ট্রিং পিছনে, যেটি মান থেকে বিচ্যুত এবং নিম্নমুখী সমস্যার কারণ পাঠানোর শেষ stackoverflow.com/a/15939945/176877
ক্রিস Moschini

1
@ ক্রিস মোসচিনি: আপনি একদম ঠিক বলেছেন। খালি স্ট্রিং ফিরিয়ে দেওয়া ভুল। তবে তারপরে কি জেসন মানটি নাল বা খালি জেসন বস্তুটি ফিরিয়ে দেওয়া উচিত? আমি নিশ্চিত না যে কোনও বস্তুর প্রত্যাশিত কোনও মান প্রত্যাবর্তন করা হয় সমস্যা মুক্ত হয় either তবে যেভাবেই হোক, বর্তমান কোডটি এই ক্ষেত্রে ভাল নয়।
asgerhallas

1
জেসন.নেটে একটি ত্রুটি রয়েছে যার ফলে আইই 9 এবং নীচে আইএসও 8601 তারিখগুলি জেসন.নেট উত্পাদনে পার্স করতে ব্যর্থ হয়েছে। এই জন্য ফিক্স এই উত্তর মধ্যে অন্তর্ভুক্ত করা হয়: stackoverflow.com/a/15939945/176877
ক্রিস Moschini

1
@ এসগারহালাস, @ ক্রিস মোছচিনি ডিফল্ট এসপ নেটওয়্যার এমভিসি জসনআরসাল্ট চেক সম্পর্কে কী if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) throw new InvalidOperationException(MvcResources.JsonRequest_GetNotAllowed);? আমি মনে করি এই চেকটি উত্তরে যুক্ত করতে হবে (অভ্যন্তরীণ ছাড়া MvcResources.JsonRequest_GetNotAllowedতবে কিছু কাস্টম বার্তা সহ) এছাড়াও, অন্যান্য 2 ডিফল্ট এসপ নেটওয়্যার এমভিসি চেকগুলি কী - ম্যাকজেসনলেন্থ এবং রিকার্সনলিমিট? আমরা json.net ব্যবহার করলে আমাদের কি তাদের দরকার?
ক্রোমিগো

60

বেস কন্ট্রোলার বা ইনজেকশনের প্রয়োজন ছাড়াই আমি এটি প্রয়োগ করেছি।

আমি জসোনারসাল্টকে জসননেটআরসাল্টের সাথে প্রতিস্থাপন করতে অ্যাকশন ফিল্টার ব্যবহার করেছি।

public class JsonHandlerAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
       var jsonResult = filterContext.Result as JsonResult;

        if (jsonResult != null)
        {
            filterContext.Result = new JsonNetResult
            {
                ContentEncoding = jsonResult.ContentEncoding,
                ContentType = jsonResult.ContentType,
                Data = jsonResult.Data,
                JsonRequestBehavior = jsonResult.JsonRequestBehavior
            };
        }

        base.OnActionExecuted(filterContext);
    }
}

Global.asax.cs অ্যাপ্লিকেশন_স্টার্ট () এ আপনাকে যুক্ত করতে হবে:

GlobalFilters.Filters.Add(new JsonHandlerAttribute());

সমাপ্তির স্বার্থে, এখানে আমার জসননেটআরসল্ট এক্সটেনশন ক্লাস যা আমি অন্য কোথাও থেকে তুলেছি এবং সঠিক স্টিমিং সমর্থন পেতে আমি কিছুটা পরিবর্তন করেছি:

public class JsonNetResult : JsonResult
{
    public JsonNetResult()
    {
        Settings = new JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Error
        };
    }

    public JsonSerializerSettings Settings { get; private 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("JSON GET is not allowed");

        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = string.IsNullOrEmpty(this.ContentType) ? "application/json" : this.ContentType;

        if (this.ContentEncoding != null)
            response.ContentEncoding = this.ContentEncoding;
        if (this.Data == null)
            return;

        var scriptSerializer = JsonSerializer.Create(this.Settings);
        scriptSerializer.Serialize(response.Output, this.Data);
    }
}

1
এটি একটি দুর্দান্ত সমাধান। এটিকে এমনভাবে তৈরি করে যাতে দেশীয় return Json()কার্যকরভাবে Json.Net ব্যবহার করে।
OneHoopyFrood

1
ভাবছি এই মাত্র কীভাবে কাজ করে যে কেউ জন্য, এটি বিছিন্ন করে JsonResultথেকে Json()এবং এটি একটি পরিবর্তিত JsonNetResult। এটি এমন asকীওয়ার্ডটি ব্যবহার করে যা রূপান্তর সম্ভব না হলে বাতিল করে দেয় । খুব নিফটি। গ্রিফিন্ডারের জন্য ১০ পয়েন্ট!
OneHoopyFrood

4
যদিও প্রশ্ন, ডিফল্ট সিরিয়ালাইজটি বাধা দেওয়ার আগে কি বস্তুটিতে চালিত হয়?
OneHoopyFrood

এটি একটি চমত্কার উত্তর - সবচেয়ে নমনীয়তা সহ। যেহেতু আমার প্রকল্পটি ইতিমধ্যে সামনের প্রান্তে সমস্ত ধরণের ম্যানুয়াল সমাধানগুলি করছে, তাই আমি কোনও বিশ্বব্যাপী ফিল্টার যোগ করতে পারিনি - এটির জন্য আরও বড় পরিবর্তন প্রয়োজন। আমি কেবলমাত্র আমার নিয়ামকের ক্রিয়াকলাপগুলিতে অ্যাট্রিবিউটটি ব্যবহার করে যেখানে প্রয়োজন কেবল নিয়ন্ত্রক ক্রিয়ায় সমস্যার সমাধান করেছি। তবে, আমি এটিকে ফোন করেছি - [BetterJsonHandler]:-)।
সিমচা খাবিনস্কি

এইটি ফিরিয়ে দিচ্ছে। জেসন (নাল); এখনও কিছুই
ফেরায়

27

নিউটনসফটের জেএসএন রূপান্তরকারীটি ব্যবহার করুন:

public ActionResult DoSomething()
{
    dynamic cResponse = new ExpandoObject();
    cResponse.Property1 = "value1";
    cResponse.Property2 = "value2";
    return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}

7
এটি হ্যাকি কিনা তা নিশ্চিত নয় তবে পবিত্র বোকাটি কেবল বোকা জেসন স্ট্রিং ফিরিয়ে দেওয়ার জন্য এক্সটেনশন ক্লাস তৈরি করা সহজ।
dennis.sheppard

21

আমি জানি প্রশ্নের উত্তরের পরে এটি ঠিক আছে, তবে আমি আমার নিয়ন্ত্রণকারীদের তাত্ক্ষণিকভাবে নির্ভরতা ইনজেকশন ব্যবহার করায় আমি একটি ভিন্ন পদ্ধতির ব্যবহার করছি।

আমি আইভ্যাকশনভোকারকে (কন্ট্রোলারের কন্ট্রোলারঅ্যাকশনআইভোকার প্রপার্টি ইনজেকশন দিয়ে) প্রতিস্থাপন করেছি এমন একটি সংস্করণ যা ইনভেকশনমিথড পদ্ধতিটিকে ওভাররাইড করে।

এর অর্থ নিয়ন্ত্রকের উত্তরাধিকারে কোনও পরিবর্তন নেই এবং আমি যখন সমস্ত কন্ট্রোলারের জন্য ডিআই কনটেইনার রেজিস্ট্রেশন পরিবর্তন করে এমভিসি 4 তে আপগ্রেড করি তখন এটি সহজেই মুছে ফেলা যায়

public class JsonNetActionInvoker : ControllerActionInvoker
{
    protected override ActionResult InvokeActionMethod(ControllerContext controllerContext, ActionDescriptor actionDescriptor, IDictionary<string, object> parameters)
    {
        ActionResult invokeActionMethod = base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);

        if ( invokeActionMethod.GetType() == typeof(JsonResult) )
        {
            return new JsonNetResult(invokeActionMethod as JsonResult);
        }

        return invokeActionMethod;
    }

    private class JsonNetResult : JsonResult
    {
        public JsonNetResult()
        {
            this.ContentType = "application/json";
        }

        public JsonNetResult( JsonResult existing )
        {
            this.ContentEncoding = existing.ContentEncoding;
            this.ContentType = !string.IsNullOrWhiteSpace(existing.ContentType) ? existing.ContentType : "application/json";
            this.Data = existing.Data;
            this.JsonRequestBehavior = existing.JsonRequestBehavior;
        }

        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))
            {
                base.ExecuteResult(context);                            // Delegate back to allow the default exception to be thrown
            }

            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = this.ContentType;

            if (this.ContentEncoding != null)
            {
                response.ContentEncoding = this.ContentEncoding;
            }

            if (this.Data != null)
            {
                // Replace with your favourite serializer.  
                new Newtonsoft.Json.JsonSerializer().Serialize( response.Output, this.Data );
            }
        }
    }
}

--- সম্পাদনা - নিয়ামকদের জন্য ধারক নিবন্ধকরণ দেখানোর জন্য আপডেট করা হয়েছে। আমি এখানে ইউনিটি ব্যবহার করছি।

private void RegisterAllControllers(List<Type> exportedTypes)
{
    this.rootContainer.RegisterType<IActionInvoker, JsonNetActionInvoker>();
    Func<Type, bool> isIController = typeof(IController).IsAssignableFrom;
    Func<Type, bool> isIHttpController = typeof(IHttpController).IsAssignableFrom;

    foreach (Type controllerType in exportedTypes.Where(isIController))
    {
        this.rootContainer.RegisterType(
            typeof(IController),
            controllerType, 
            controllerType.Name.Replace("Controller", string.Empty),
            new InjectionProperty("ActionInvoker")
        );
    }

    foreach (Type controllerType in exportedTypes.Where(isIHttpController))
    {
        this.rootContainer.RegisterType(typeof(IHttpController), controllerType, controllerType.Name);
    }
}

public class UnityControllerFactory : System.Web.Mvc.IControllerFactory, System.Web.Http.Dispatcher.IHttpControllerActivator
{
    readonly IUnityContainer container;

    public UnityControllerFactory(IUnityContainer container)
    {
        this.container = container;
    }

    IController System.Web.Mvc.IControllerFactory.CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        return this.container.Resolve<IController>(controllerName);
    }

    SessionStateBehavior System.Web.Mvc.IControllerFactory.GetControllerSessionBehavior(RequestContext requestContext, string controllerName)
    {
        return SessionStateBehavior.Required;
    }

    void System.Web.Mvc.IControllerFactory.ReleaseController(IController controller)
    {
    }

    IHttpController IHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
    {
        return this.container.Resolve<IHttpController>(controllerType.Name);
    }
}

ভাল লাগছে, তবে আপনি কীভাবে এটি ব্যবহার করবেন? বা আরও ভাল আপনি এটি ইনজেক্ট কিভাবে?
অ্যাডাপ্টবি

.শিরাইজ () এর স্ট্রিম ফর্মটি ব্যবহার করার জন্য +1। আমি আপনাকে উল্লেখ করতে যাচ্ছিলাম আপনি অন্যান্য শীর্ষ উত্তরের মতো কেবল জসনকনভার্ট ব্যবহার করতে পারেন, তবে আপনার পদ্ধতির ধীরে ধীরে দীর্ঘ / বড় অবজেক্টগুলি প্রবাহিত করে - এটি একটি নিখরচায় পারফরম্যান্সের উত্সাহ, বিশেষত যদি ডাউন স্ট্রিম ক্লায়েন্ট আংশিক প্রতিক্রিয়াগুলি পরিচালনা করতে পারে।
ক্রিস মোসচিনি

1
সুন্দর বাস্তবায়ন এই উত্তর হওয়া উচিত!
ক্যাট লিম রুইজ

ভাল যাচ্ছে, এটি আমি কেবল বেস নিয়ামকটিই ব্যবহার করছিলাম।
ক্রিস ডুবুরি

সত্যিই দুর্দান্ত - এটি জাসন () ফাংশনকে ওভাররাইড করার পরে আরও অনেক ভাল, যেহেতু আপনি যেখানে কোনও জাসনআরসাল্ট ফিরে পাবেন তার প্রতিটি স্থানে এটি কিক করবে এবং এটি যাদু করবে। যারা ডিআই ব্যবহার করেন না তাদের জন্য কেবল সুরক্ষিত ওভাররাইড যুক্ত করুন IActionInvoker CreateActionInvoker () new আপনার বেস কন্ট্রোলারে নতুন জসননেটঅ্যাকশনআইভোকার (); {ফিরিয়ে দিন
আভি পিন্টো

13

Https://stackoverflow.com/users/183056/sami-beyoglu থেকে উত্তরের প্রসারিত করে , আপনি যদি বিষয়বস্তুর ধরণটি সেট করেন তবে jQuery আপনার জন্য প্রত্যাবর্তিত ডেটা রূপান্তর করতে সক্ষম হবে।

public ActionResult DoSomething()
{
    dynamic cResponse = new ExpandoObject();
    cResponse.Property1 = "value1";
    cResponse.Property2 = "value2";
    return Content(JsonConvert.SerializeObject(cResponse), "application/json");
}

ধন্যবাদ, আমার একটি হাইব্রিড মিশ্রণ রয়েছে এবং এটিই আমার পক্ষে কাজ করবে।
সম্পন্ন_মারসন

আমি এটি JSON.NET এর সাথে এটির মতো ব্যবহার করেছি: JObject jo = GetJSON(); return Content(jo.ToString(), "application/json");
জন মোট

6

আমার পোস্ট কারও সাহায্য করতে পারে।

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.Mvc;
namespace MultipleSubmit.Service
{
    public abstract class BaseController : Controller
    {
        protected override JsonResult Json(object data, string contentType,
            Encoding contentEncoding, JsonRequestBehavior behavior)
        {
            return new JsonNetResult
            {
                Data = data,
                ContentType = contentType,
                ContentEncoding = contentEncoding,
                JsonRequestBehavior = behavior
            };
        }
    }
}


using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MultipleSubmit.Service
{
    public class JsonNetResult : JsonResult
    {
        public JsonNetResult()
        {
            Settings = new JsonSerializerSettings
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Error
            };
        }
        public JsonSerializerSettings Settings { get; private 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("JSON GET is not allowed");
            HttpResponseBase response = context.HttpContext.Response;
            response.ContentType = string.IsNullOrEmpty(this.ContentType) ? 
"application/json" : this.ContentType;
            if (this.ContentEncoding != null)
                response.ContentEncoding = this.ContentEncoding;
            if (this.Data == null)
                return;
            var scriptSerializer = JsonSerializer.Create(this.Settings);
            using (var sw = new StringWriter())
            {
                scriptSerializer.Serialize(sw, this.Data);
                response.Write(sw.ToString());
            }
        }
    }
} 

public class MultipleSubmitController : BaseController
{
   public JsonResult Index()
    {
      var data = obj1;  // obj1 contains the Json data
      return Json(data, JsonRequestBehavior.AllowGet);
    }
}    

আমি একটি আসল সমাধানের সন্ধান করছিলাম এবং আপনিই একমাত্র সঠিক উত্তর
রিচার্ড আগুয়েরে

ধন্যবাদ। ইতিমধ্যে আমার নিজের প্রয়োগ করে BaseController, এটি সর্বনিম্ন প্রভাবের চ্যাং - কেবল ক্লাস এবং আপডেট যুক্ত করতে হয়েছিল BaseController
অ্যান্ড্রুপি

4

আমি এমন একটি সংস্করণ তৈরি করেছি যা ওয়েব পরিষেবা ক্রিয়াগুলি টাইপ-নিরাপদ এবং সহজ করে তোলে। আপনি এটি এর মতো ব্যবহার করুন:

public JsonResult<MyDataContract> MyAction()
{
    return new MyDataContract();
}

শ্রেণী:

public class JsonResult<T> : JsonResult
{
    public JsonResult(T data)
    {
        Data = data;
        JsonRequestBehavior = JsonRequestBehavior.AllowGet;
    }

    public override void ExecuteResult(ControllerContext context)
    {
        // Use Json.Net rather than the default JavaScriptSerializer because it's faster and better

        if (context == null)
            throw new ArgumentNullException("context");

        var response = context.HttpContext.Response;

        response.ContentType = !String.IsNullOrEmpty(ContentType)
            ? ContentType
            : "application/json";

        if (ContentEncoding != null)
            response.ContentEncoding = ContentEncoding;

        var serializedObject = JsonConvert.SerializeObject(Data, Formatting.Indented);
        response.Write(serializedObject);
    }

    public static implicit operator JsonResult<T>(T d)
    {
        return new JsonResult<T>(d);
    }
}

তবে আপনি কেন জসনআরসাল্টের মতো দৃ types় ধরনের চান? : ডি আপনি বেনামে ধরণের ফলাফলগুলি আলগা করেন এবং ক্লায়েন্টের পক্ষে কোনও উপার্জন করেন না কেননা এটি কোনওভাবে সি # ক্লাসেস ব্যবহার করছে না?
মিকাস

1
@ মিকাস এটি সার্ভারের দিকের টাইপসেফ: পদ্ধতিটিতে অবশ্যই মাইডেটা কনট্রাক্ট টাইপ করতে হবে। এটি ক্লায়েন্টের পক্ষ থেকে এটি পরিষ্কার করে দেয় যে ঠিক কী কাঠামোর ডেটা স্ট্রাকচার ফিরিয়ে দেওয়া হচ্ছে। এটি সংক্ষিপ্ত এবং পঠনযোগ্য - জসনআরসাল্ট <টি> জসনের কাছে প্রত্যাবর্তিত কোনও প্রকারকে স্বতঃস্ফূর্ত করে দেয় এবং আপনাকে কিছু করতে হবে না।
কার্টিস ইয়ালাপ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.