MVC中用JObject作为前端向后端传递的Model参数类型:
方案一:
1. 在Global.asax文件中:
using Test.Manage.Common;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;namespace Test.Manage
{
public class MvcApplication : HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new CustomModelBinder();
}
}
}
2. CustomModelBinder.cs文件:
using DevMate.Common;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;
using System.IO;
using System.Web;
using System.Web.Mvc;namespace Test.Manage.Common
{
public class CustomModelBinder : DefaultModelBinder
{
private readonly object _locker = new object();
private const string cachekey = "JsonModel";
private Dictionary<string, int> _indexCache = new Dictionary<string, int>();
private int _index = 0;
private JObject _data
{
get
{
return HttpContext.Current.Items[cachekey] as JObject;
}
set
{
HttpContext.Current.Items[cachekey] = value;
}
}public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var request = controllerContext.HttpContext.Request;
if (request.Files.Count > 0)
return base.BindModel(controllerContext, bindingContext);if (_data == null)
{
using (var sr = new StreamReader(request.InputStream))
{
sr.BaseStream.Position = 0;
var json = sr.ReadToEnd();
_data = JsonConvert.DeserializeObject<JObject>(json);
}
}if (_data == null)
return base.BindModel(controllerContext, bindingContext);string id = _data["RequestId"] == null ? null : _data["RequestId"].ToString();
if (string.IsNullOrEmpty(id))
return base.BindModel(controllerContext, bindingContext);string key = "param";
lock (_locker)
{
if (_indexCache.Count > 100)
_indexCache.Clear();if (!_indexCache.ContainsKey(id))
{
_indexCache.Add(id, 0);
}_index = _indexCache[id];
key = "param" + _index;
_index++;
_indexCache[id] = _index;
}object obj = null;
string jsonField = DataConvert.ToString(_data[key]);
if (bindingContext.ModelType == typeof(JArray))
{
obj = DataConvert.ToJArray(jsonField);
}
else if (bindingContext.ModelType.IsClass || bindingContext.ModelType.IsArray || bindingContext.ModelType.IsGenericType)
{
obj = JsonConvert.DeserializeObject(jsonField, bindingContext.ModelType);
}
else
{
obj = _data[key].ToObject(bindingContext.ModelType);
}return obj;
}
}
}
3. 前端RPC调用方法求封装:
(function (global, $) {
var jp = {};
global.jp = jp;function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
function guid() {
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}jp.createRpc = function (rpcUrl, fail, loading) {
return function () {
var ParamentersData = {
RequestId: 'JP' + guid()
};for (var i = 0; i < arguments.length; i++) {
var key = "param" + i;
ParamentersData[key] = arguments[i];
};var options = {
type: 'post',
url: rpcUrl,
dataType:'json',
contentType: 'application/json',
data: JSON.stringify(ParamentersData),
beforeSend: function () {
if (!loading)
$JVue.loading = true;
},
complete: function (event,xhr,options) {
$JVue.loading = false;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(XMLHttpRequest);
$JVue.loading = false;
if (!fail) {
$JVue.$message({
message: $JVue.$t('wsm.errorCode.'+XMLHttpRequest.responseJSON.Code),
type: 'error',
onClose: function() {
//登录超时
if (XMLHttpRequest.responseJSON.Code == 30014 && top.$JVue.loginPage)
top.location.href = top.$JVue.loginPage;
},
});
}
}
};var promise = $.ajax(options);
return promise;
};
}
})
(window, jQuery);
4. 示例:
前端调用:
var param = {
ItemId: this.itemForm.ID,
Fields: this.fields,
};
var action = jp.createRpc('TestAction');
action(param) //注意:这里无需使用如“{API参数名obj:param}” 作参数,方案二则需要
.done(function (data) {
......
});后端方法:
[HttpPost]
public JsonResult TestAction(JObject obj)
{
......
}
----------------------------------------------------------
方案二:
1. 在Global.asax文件中:
using test.Web.Common;
using System.Web.Mvc;
using System.Web.Routing;
using System.Linq;
using System.Web.Http;namespace test.Web
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
RouteConfig.RegisterRoutes(RouteTable.Routes);
//ValueProviderFactories.Factories默认包括以下ValueProviderFactory:
//System.Web.Mvc.ChildActionValueProviderFactory
//System.Web.Mvc.FormValueProviderFactory
//System.Web.Mvc.JsonValueProviderFactory
//System.Web.Mvc.RouteDataValueProviderFactory
//System.Web.Mvc.QueryStringValueProviderFactory
//System.Web.Mvc.HttpFileCollectionValueProviderFactoryValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new CustomValueProvider());
ModelBinderProviders.BinderProviders.Add(new CustomModelBinderProvider());
}
}
}
2. CustomModelBinderProvider.cs文件:
using Newtonsoft.Json.Linq;
using System;
using System.Web;
using System.Web.Mvc;namespace test.Web.Common
{
public class CustomModelBinderProvider : IModelBinderProvider
{
//public IModelBinder GetBinder(Type modelType)//{
// if (modelType == typeof(string) || modelType == typeof(HttpPostedFileBase))
// {
// return null;
// }
// else if (modelType == typeof(JArray))
// {
// return new CustomModelBinder(typeof(JArray));
// }
// else if (modelType == typeof(JObject))
// {
// return new CustomModelBinder(typeof(JObject));
// }
// else if (modelType.IsClass || modelType.IsArray || modelType.IsGenericType)
// {
// return new CustomModelBinder(modelType);
// }// return null;
//}
//改为以下:解决了ModelBinder绑定JArray/JObject与过去传递实体对象参数不可兼容的问题
public IModelBinder GetBinder(Type modelType)
{//if (modelType == typeof(string) || modelType == typeof(HttpPostedFileBase))
//{
// return null;
//}
//else
//if (modelType.IsClass || modelType.IsArray || modelType.IsGenericType)
//{
// return new CustomModelBinder(modelType);
//}
//else
if (modelType == typeof(JArray))
{
return new CustomModelBinder(typeof(JArray));
}
else if (modelType == typeof(JObject))
{
return new CustomModelBinder(typeof(JObject));
}return new DefaultModelBinder();
}}
}
3. CustomModelBinder
using System;
using System.Web.Mvc;
using Newtonsoft.Json;namespace test.Web.Common
{
public class CustomModelBinder : IModelBinder
{
public Type ModelType { get; set; }public CustomModelBinder(Type modelType)
{
ModelType = modelType;
}public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var value = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
if (value != null)
{
return JsonConvert.DeserializeObject(value.AttemptedValue, ModelType);
}
return null;
}
}}
4. CustomValueProviderFactory
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Text;
using System.Web.Mvc;namespace test.Web.Common
{
public class CustomValueProviderFactory : ValueProviderFactory
{
public override IValueProvider GetValueProvider(ControllerContext controllerContext)
{
if (controllerContext == null) throw new ArgumentNullException("controllerContext");if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return null;
controllerContext.HttpContext.Request.InputStream.Seek(0, SeekOrigin.Begin);
string json = null;
using (var reader = new StreamReader(controllerContext.HttpContext.Request.InputStream, Encoding.UTF8))
{
json = reader.ReadToEnd();
reader.Close();
//controllerContext.HttpContext.Request.InputStream.Seek(0,SeekOrigin.Begin);
}
if (string.IsNullOrEmpty(json) || !(json.StartsWith("{") || json.StartsWith("[")))
return new CommonValueProvider(json);//var jsonProvider = new JsonValueProviderFactory().GetValueProvider(controllerContext);
//if (jsonProvider != null)
// return jsonProvider;return new JObjectValueProvider(json.StartsWith("[") ?
JArray.Parse(json) as JContainer :
JObject.Parse(json) as JContainer);
}}
}
5. CommonValueProvider
using System.Globalization;
using System.Web.Mvc;namespace test.Web.Common
{public class CommonValueProvider : IValueProvider
{
private string _param;public CommonValueProvider(string param)
{
_param = param;
}public bool ContainsPrefix(string prefix)
{
return !string.IsNullOrEmpty(_param);
}public ValueProviderResult GetValue(string key)
{
return new ValueProviderResult(_param, _param, CultureInfo.CurrentCulture);
}
}
}
6. JObjectValueProvider
using Newtonsoft.Json.Linq;
using System.Globalization;
using System.Web.Mvc;namespace test.Web.Common
{
public class JObjectValueProvider : IValueProvider
{
private JContainer _jcontainer;public JObjectValueProvider(JContainer jcontainer)
{
_jcontainer = jcontainer;
}public bool ContainsPrefix(string prefix)
{
var token = _jcontainer.SelectToken(prefix);
return token != null;
}public ValueProviderResult GetValue(string key)
{
var token = _jcontainer.SelectToken(key);
if (token == null) return null;
return new ValueProviderResult(token.ToString(), token.ToString(), CultureInfo.CurrentCulture);
}
}
}
7. 前端RPC调用方法封装:
(function (global, $) {
var jp = {};
global.jp = jp;jp.createRpc = function (rpcUrl, fail, loading) {
return function (param) {
var options = {
type: 'post',
url: rpcUrl,
dataType:'json',
contentType: 'application/json',
data: JSON.stringify(param),
beforeSend: function () {
if (!loading)
$JVue.loading = true;
},
complete: function (event,xhr,options) {
$JVue.loading = false;
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
console.log(XMLHttpRequest);
$JVue.loading = false;
if (!fail) {
$JVue.$message({
message: !!XMLHttpRequest.responseJSON.Cause ? XMLHttpRequest.responseJSON.Cause : $JVue.$t('sos.errorCode.' + XMLHttpRequest.responseJSON.Code),
type: 'error',
onClose: function() {
//登录超时
if (XMLHttpRequest.responseJSON.Code == 30014 && top.$JVue.loginPage)
top.location.href = top.$JVue.loginPage;
},
});
}
}
};var promise = $.ajax(options);
return promise;
};
}jp.getQueryString = function(name) {
var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)", "i");
var reg_rewrite = new RegExp("(^|/)" + name + "/([^/]*)(/|$)", "i");
var r = window.location.search.substring(1).match(reg);
var q = window.location.pathname.substring(1).match(reg_rewrite);
if(r != null){
return decodeURI(r[2]);
}else if(q != null){
return decodeURI(q[2]);
}else{
return null;
}
}
})
(window, jQuery);
8. 示例:
前端调用:
var param = {
ItemId: this.itemForm.ID,
Fields: this.fields,
};
var action = jp.createRpc('TestAction');
action({obj:param}) //注意:这里需使用如“{API参数名obj:param}” 作参数,方案一则不需要
.done(function (data) {
......
});后端方法:
[HttpPost]
public JsonResult TestAction(JObject obj)
{
......
}