加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

在MVC中使用Json.Net序列化和反序列化Json对象

发布时间:2020-12-15 21:16:39 所属栏目:asp.Net 来源:网络整理
导读:在.Net的MVC开发中,经常会使用到Json对象,于是,系统提供了JsonResult这个对象,其本质是调用.Net系统自带的Json序列化类JavaScriptSerializer对数据对象进行序列化。但是这个系统自带的Json序列化对象方法没有Json.Net好用,于是打算有些时候用Json.Net替

在.Net的MVC开发中,经常会使用到Json对象,于是,系统提供了JsonResult这个对象,其本质是调用.Net系统自带的Json序列化类JavaScriptSerializer对数据对象进行序列化。但是这个系统自带的Json序列化对象方法没有Json.Net好用,于是打算有些时候用Json.Net替代默认的实现。

要实现有时候用Json.Net,有时候用默认实现,那么就要保证系统中两种实现并存。对于Server将对象序列化成Json传给Client很简单,我们只需要建立一个新的ActionResult,我们命名为JsonNetResult,然后在Get时,return这个JsonNetResult即可。JsonNetResult的代码实现为:

 System;
 System.Collections.Generic;
 System.Linq;
 System.Text;

<span class="kwrd">namespace MvcJsonNet
{
<span class="kwrd">using System.IO;
<span class="kwrd">using System.Web;
<span class="kwrd">using System.Web.Mvc;
<span class="kwrd">using Newtonsoft.Json;

<span class="kwrd"&gt;public</span> <span class="kwrd"&gt;class</span> JsonNetResult : JsonResult
{
    <span class="kwrd"&gt;public</span> JsonNetResult()
    {
        Settings = <span class="kwrd"&gt;new</span> JsonSerializerSettings
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Error
        };
    }
    <span class="kwrd"&gt;public</span> JsonNetResult(<span class="kwrd"&gt;object</span> data,JsonRequestBehavior behavior = JsonRequestBehavior.AllowGet,<span class="kwrd"&gt;string</span> contentType=<span class="kwrd"&gt;null</span>,Encoding contentEncoding=<span class="kwrd"&gt;null</span>)
    {
        <span class="kwrd"&gt;this</span>.Data = data;
        <span class="kwrd"&gt;this</span>.JsonRequestBehavior = behavior;
        <span class="kwrd"&gt;this</span>.ContentEncoding = contentEncoding;
        <span class="kwrd"&gt;this</span>.ContentType = contentType;
    }

    <span class="kwrd"&gt;public</span> JsonSerializerSettings Settings { get; <span class="kwrd"&gt;private</span> set; }

    <span class="kwrd"&gt;public</span> <span class="kwrd"&gt;override</span> <span class="kwrd"&gt;void</span> ExecuteResult(ControllerContext context)
    {


        <span class="kwrd"&gt;if</span> (context == <span class="kwrd"&gt;null</span>)
            <span class="kwrd"&gt;throw</span> <span class="kwrd"&gt;new</span> ArgumentNullException(<span class="str"&gt;"context"</span>);
        <span class="kwrd"&gt;if</span> (<span class="kwrd"&gt;this</span>.JsonRequestBehavior == JsonRequestBehavior.DenyGet &amp;&amp; <span class="kwrd"&gt;string</span>.Equals(context.HttpContext.Request.HttpMethod,<span class="str"&gt;"GET"</span>,StringComparison.OrdinalIgnoreCase))
            <span class="kwrd"&gt;throw</span> <span class="kwrd"&gt;new</span> InvalidOperationException(<span class="str"&gt;"JSON GET is not allowed"</span>);

        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = <span class="kwrd"&gt;string</span>.IsNullOrEmpty(<span class="kwrd"&gt;this</span>.ContentType) ? <span class="str"&gt;"application/json"</span> : <span class="kwrd"&gt;this</span>.ContentType;

        <span class="kwrd"&gt;if</span> (<span class="kwrd"&gt;this</span>.ContentEncoding != <span class="kwrd"&gt;null</span>)
            response.ContentEncoding = <span class="kwrd"&gt;this</span>.ContentEncoding;
        <span class="kwrd"&gt;if</span> (<span class="kwrd"&gt;this</span>.Data == <span class="kwrd"&gt;null</span>)
            <span class="kwrd"&gt;return</span>;

        var scriptSerializer = JsonSerializer.Create(<span class="kwrd"&gt;this</span>.Settings);

        <span class="kwrd"&gt;using</span> (var sw = <span class="kwrd"&gt;new</span> StringWriter())
        {
            scriptSerializer.Serialize(sw,<span class="kwrd"&gt;this</span>.Data);
            response.Write(sw.ToString());
        }
    }
}

}

要返回一个Json.Net序号列后的对象,那么调用方法是:

 ActionResult GetJsonNet()
{
    var myClass = InitClass();
      JsonNetResult(myClass);
}

这是Get方法,但是对于ClientPost一个Json回Server,那么就比较麻烦了,需要修改好几处地方:

1,建立Json.Net的ValueProviderFactory,这个类主要就是用于Json字符串的反序列化。

 System;
 System.Collections.Generic;
 System.Linq;
 System.Web;

<span class="kwrd">namespace MvcJsonNet
{
<span class="kwrd">using System.Collections;
<span class="kwrd">using System.Dynamic;
<span class="kwrd">using System.Globalization;
<span class="kwrd">using System.IO;
<span class="kwrd">using System.Web.Mvc;
<span class="kwrd">using System.Web.Script.Serialization;
<span class="kwrd">using Newtonsoft.Json;

<span class="kwrd"&gt;public</span> <span class="kwrd"&gt;class</span> JsonNetValueProviderFactory : ValueProviderFactory
{
    <span class="kwrd"&gt;private</span> <span class="kwrd"&gt;void</span> AddToBackingStore(Dictionary<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>> backingStore,<span class="kwrd"&gt;string</span> prefix,<span class="kwrd"&gt;object</span> <span class="kwrd"&gt;value</span>)
    {
        IDictionary<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>> d = <span class="kwrd"&gt;value</span> <span class="kwrd"&gt;as</span> IDictionary<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>>;
        <span class="kwrd"&gt;if</span> (d != <span class="kwrd"&gt;null</span>)
        {
            <span class="kwrd"&gt;foreach</span> (KeyValuePair<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>> entry <span class="kwrd"&gt;in</span> d)
            {
                AddToBackingStore(backingStore,MakePropertyKey(prefix,entry.Key),entry.Value);
            }
            <span class="kwrd"&gt;return</span>;
        }

        IList l = <span class="kwrd"&gt;value</span> <span class="kwrd"&gt;as</span> IList;
        <span class="kwrd"&gt;if</span> (l != <span class="kwrd"&gt;null</span>)
        {
            <span class="kwrd"&gt;for</span> (<span class="kwrd"&gt;int</span> i = 0; i < l.Count; i++)
            {
                AddToBackingStore(backingStore,MakeArrayKey(prefix,i),l[i]);
            }
            <span class="kwrd"&gt;return</span>;
        }

        <span class="rem"&gt;// primitive</span>
        backingStore[prefix] = <span class="kwrd"&gt;value</span>;
    }

    <span class="kwrd"&gt;private</span> <span class="kwrd"&gt;object</span> GetDeserializedObject(ControllerContext controllerContext)
    {
        <span class="kwrd"&gt;if</span> (!controllerContext.HttpContext.Request.ContentType.StartsWith(<span class="str"&gt;"application/json"</span>,StringComparison.InvariantCultureIgnoreCase))
        {
            <span class="rem"&gt;// not JSON request</span>
            <span class="kwrd"&gt;return</span> <span class="kwrd"&gt;null</span>;
        }

        StreamReader reader = <span class="kwrd"&gt;new</span> StreamReader(controllerContext.HttpContext.Request.InputStream);
        <span class="kwrd"&gt;string</span> bodyText = reader.ReadToEnd();
        <span class="kwrd"&gt;if</span> (String.IsNullOrEmpty(bodyText))
        {
            <span class="rem"&gt;// no JSON data</span>
            <span class="kwrd"&gt;return</span> <span class="kwrd"&gt;null</span>;
        }
        <span class="rem"&gt;//接下来的代码是关键,判断content type,如果是json.net,那么就使用Json.Net的反序列化方法,如果不是,那么就使用系统默认的反序列化方法</span>
        <span class="kwrd"&gt;if</span> (controllerContext.HttpContext.Request.ContentType.StartsWith(<span class="str"&gt;"application/json.net"</span>,StringComparison.InvariantCultureIgnoreCase))
        {
            var jsonData = JsonConvert.DeserializeObject<ExpandoObject>(bodyText);
            <span class="kwrd"&gt;return</span> jsonData;
        }
        <span class="kwrd"&gt;else</span>
        {
            JavaScriptSerializer serializer = <span class="kwrd"&gt;new</span> JavaScriptSerializer();
            <span class="kwrd"&gt;object</span> jsonData = serializer.DeserializeObject(bodyText);
            <span class="kwrd"&gt;return</span> jsonData;
        }
    }

    <span class="kwrd"&gt;public</span> <span class="kwrd"&gt;override</span> IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        <span class="kwrd"&gt;if</span> (controllerContext == <span class="kwrd"&gt;null</span>)
        {
            <span class="kwrd"&gt;throw</span> <span class="kwrd"&gt;new</span> ArgumentNullException(<span class="str"&gt;"controllerContext"</span>);
        }

        <span class="kwrd"&gt;object</span> jsonData = GetDeserializedObject(controllerContext);
        <span class="kwrd"&gt;if</span> (jsonData == <span class="kwrd"&gt;null</span>)
        {
            <span class="kwrd"&gt;return</span> <span class="kwrd"&gt;null</span>;
        }

        Dictionary<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>> backingStore = <span class="kwrd"&gt;new</span> Dictionary<<span class="kwrd"&gt;string</span>,<span class="kwrd"&gt;object</span>>(StringComparer.OrdinalIgnoreCase);
        AddToBackingStore(backingStore,String.Empty,jsonData);
        <span class="kwrd"&gt;return</span> <span class="kwrd"&gt;new</span> DictionaryValueProvider<<span class="kwrd"&gt;object</span>>(backingStore,CultureInfo.CurrentCulture);
    }

    <span class="kwrd"&gt;private</span>  <span class="kwrd"&gt;string</span> MakeArrayKey(<span class="kwrd"&gt;string</span> prefix,<span class="kwrd"&gt;int</span> index)
    {
        <span class="kwrd"&gt;return</span> prefix + <span class="str"&gt;"["</span> + index.ToString(CultureInfo.InvariantCulture) + <span class="str"&gt;"]"</span>;
    }

    <span class="kwrd"&gt;private</span>  <span class="kwrd"&gt;string</span> MakePropertyKey(<span class="kwrd"&gt;string</span> prefix,<span class="kwrd"&gt;string</span> propertyName)
    {
        <span class="kwrd"&gt;return</span> (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + <span class="str"&gt;"."</span> + propertyName;
    }
}

}

2,在初始化MVC时替换掉默认的JsonValueProviderFactory。 在Global.asax的Application_Start时,写入以下代码:

().FirstOrDefault());
ValueProviderFactories.Factories.Add( JsonNetValueProviderFactory());

3,建立新的ModelBinder,命名为JsonNetModelBinder。

 MvcJsonNet
{
     System;
     System.ComponentModel;
     System.Diagnostics;
     System.Globalization;
     System.Linq;
     System.Web.Mvc;
     Newtonsoft.Json;
<span class="kwrd"&gt;public</span> <span class="kwrd"&gt;class</span> JsonNetModelBinder : DefaultModelBinder
{
    <span class="kwrd"&gt;protected</span> <span class="kwrd"&gt;override</span> <span class="kwrd"&gt;void</span> BindProperty(ControllerContext controllerContext,ModelBindingContext bindingContext,PropertyDescriptor propertyDescriptor)
    {
        Debug.WriteLine(<span class="str"&gt;"BindProperty"</span>);
        <span class="kwrd"&gt;if</span> (!controllerContext.HttpContext.Request.ContentType.StartsWith(<span class="str"&gt;"application/json.net"</span>,StringComparison
                                                                              .InvariantCultureIgnoreCase))
        {
            <span class="rem"&gt;//根据Content type来判断,只有json.net这种content type的才会使用该ModelBinder,否则使用默认的Binder</span>
            <span class="kwrd"&gt;base</span>.BindProperty(controllerContext,bindingContext,propertyDescriptor);
            <span class="kwrd"&gt;return</span>;
        }

        <span class="rem"&gt;// need to skip properties that aren't part of the request,else we might hit a StackOverflowException</span>
        <span class="kwrd"&gt;string</span> name = propertyDescriptor.Name;
        <span class="kwrd"&gt;foreach</span> (<span class="kwrd"&gt;object</span> attribute <span class="kwrd"&gt;in</span> propertyDescriptor.Attributes)
        {
            <span class="kwrd"&gt;if</span> (attribute <span class="kwrd"&gt;is</span> JsonPropertyAttribute)
            {
                var jp = attribute <span class="kwrd"&gt;as</span> JsonPropertyAttribute;
                name = jp.PropertyName;
            }
        }

        <span class="kwrd"&gt;string</span> fullPropertyKey = CreateSubPropertyName(bindingContext.ModelName,name);
        <span class="kwrd"&gt;if</span> (!bindingContext.ValueProvider.ContainsPrefix(fullPropertyKey))
        {
            <span class="kwrd"&gt;return</span>;
        }

        <span class="rem"&gt;// call into the property's model binder</span>
        IModelBinder propertyBinder = Binders.GetBinder(propertyDescriptor.PropertyType);
        <span class="kwrd"&gt;object</span> originalPropertyValue = propertyDescriptor.GetValue(bindingContext.Model);
        ModelMetadata propertyMetadata = bindingContext.PropertyMetadata[propertyDescriptor.Name];
        propertyMetadata.Model = originalPropertyValue;
        var innerBindingContext = <span class="kwrd"&gt;new</span> ModelBindingContext
            {
                ModelMetadata = propertyMetadata,ModelName = fullPropertyKey,ModelState = bindingContext.ModelState,ValueProvider = bindingContext.ValueProvider
            };
        <span class="kwrd"&gt;object</span> newPropertyValue = GetPropertyValue(controllerContext,innerBindingContext,propertyDescriptor,propertyBinder);
        propertyMetadata.Model = newPropertyValue;

        <span class="rem"&gt;// validation</span>
        ModelState modelState = bindingContext.ModelState[fullPropertyKey];
        <span class="kwrd"&gt;if</span> (modelState == <span class="kwrd"&gt;null</span> || modelState.Errors.Count == 0)
        {
            <span class="kwrd"&gt;if</span> (OnPropertyValidating(controllerContext,newPropertyValue))
            {
                SetProperty(controllerContext,newPropertyValue);
                OnPropertyValidated(controllerContext,newPropertyValue);
            }
        }
        <span class="kwrd"&gt;else</span>
        {
            SetProperty(controllerContext,newPropertyValue);

            <span class="rem"&gt;// Convert FormatExceptions (type conversion failures) into InvalidValue messages</span>
            <span class="kwrd"&gt;foreach</span> (
                ModelError error <span class="kwrd"&gt;in</span>
                    modelState.Errors.Where(err => String.IsNullOrEmpty(err.ErrorMessage) &amp;&amp; err.Exception != <span class="kwrd"&gt;null</span>)
                              .ToList())
            {
                <span class="kwrd"&gt;for</span> (Exception exception = error.Exception; exception != <span class="kwrd"&gt;null</span>; exception = exception.InnerException)
                {
                    <span class="kwrd"&gt;if</span> (exception <span class="kwrd"&gt;is</span> FormatException)
                    {
                        <span class="kwrd"&gt;string</span> displayName = propertyMetadata.GetDisplayName();
                        <span class="kwrd"&gt;string</span> errorMessageTemplate = <span class="str"&gt;"The value '{0}' is not valid for {1}."</span>;
                        <span class="kwrd"&gt;string</span> errorMessage = String.Format(CultureInfo.CurrentCulture,errorMessageTemplate,modelState.Value.AttemptedValue,displayName);
                        modelState.Errors.Remove(error);
                        modelState.Errors.Add(errorMessage);
                        <span class="kwrd"&gt;break</span>;
                    }
                }
            }
        }
    }
}

}

4,建立一个VModel的基类,为该基类添加Attribute,然后在Global中添加Model和Binder的映射。

 (JsonNetModelBinder))]
   VEntity
{
       Id { get; set; }
}

Global.asax中Application_Start添加代码:

(VEntity), JsonNetModelBinder());

5在前端Post Json时,指定content type为application/json.net

 PostJsonNet() {
              jsonstr = $()[0].innerHTML;
             $.ajax({
                 url: ,type: ,data: jsonstr,contentType: ,dataType: ,success:  (data) {
                     alert(data);
             }
         });
     }</pre>

我们这样处理后,Client在往Server传送Json数据时,如果指定了contentType是application/json,那么就使用系统默认的方法来反序列化对象,如果是application/json.net,那么就使用Json.Net来反序列化。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读