上一篇主要是以Form鍵值對提交的數據,轉為Json方式處理,有時我們直接以Body字串提交,我們要解決以下兩種方式提交的取值問題:
JObject
$('#btn_add').click(function (e) {
var a = $('#tb_departments').bootstrapTable('getSelections');
var post = "{'str1':'foovalue', 'str2':'barvalue'}";// JSON.stringify(a);
$.ajax({
type: "POST",
url: "/Home/bout",
contentType: "application/json",//必須有
dataType: "json", //表示返回值類型,不必須
data: post,//相當於 //data: "{'str1':'foovalue', 'str2':'barvalue'}",
success: function (data) {
//獲取數據ok
alert(JSON.toString(data));
}
});
});
JArray
$('#btn_delete').click(function (e) {
var a = $('#tb_departments').bootstrapTable('getSelections');
var post = JSON.stringify(a);
$.ajax({
type: "POST",
url: "/Home/About",
contentType: "application/json",//必須有
dataType: "json", //表示返回值類型,不必須
data: post,//相當於 //data: "{[{'str1':'foovalue', 'str2':'barvalue'},{'str1':'foovalue', 'str2':'barvalue'}]}",
success: function (data) {
//獲取數據ok
alert(data.id + "--" +data.userName);
}
});
});
在.net core 中沒有用於取Body值的ValueProvider,編一個,這是基於工廠模式的ValueProvider,先上代碼 實現IValueProviderFactory接口:
public class JObjectValueProviderFactory : IValueProviderFactory
{
public Task CreateValueProviderAsync(ValueProviderFactoryContext controllerContext)
{
if (controllerContext == null) throw new ArgumentNullException("controllerContext");
if (controllerContext.ActionContext.HttpContext.Request.ContentType == null) { return Task.CompletedTask; } ;
if (!controllerContext.ActionContext.HttpContext.Request.ContentType.
StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
{
return Task.CompletedTask;//不是"application/json"類型不處理交給原有的
}
var bodyText = string.Empty;
using (var reader = new StreamReader(controllerContext.ActionContext.HttpContext.Request.Body))
{
bodyText = reader.ReadToEnd().Trim();//取得Body
}
if (string.IsNullOrEmpty(bodyText)) { return Task.CompletedTask; }//為空不處理
else
{//添加JObject一ValueProviders以便處理值
controllerContext.ValueProviders.Add(
new JObjectValueProvider(bodyText.EndsWith("]}") ?//是不是組
JArray.Parse(bodyText) as JContainer ://是Jarray
JObject.Parse(bodyText) as JContainer));// JObject
}
return Task.CompletedTask;
}
}
對應的IValueProvider:
internal class JObjectValueProvider : IValueProvider
{
private JContainer _jcontainer;
public JObjectValueProvider(JContainer jcontainer)
{
_jcontainer = jcontainer;
}
public bool ContainsPrefix(string prefix)
{
// return _jcontainer.SelectToken(prefix) != null;
return true;
}
public ValueProviderResult GetValue(string key)
{
var jtoken = _jcontainer.SelectToken("");
if (jtoken == null) return ValueProviderResult.None;
return new ValueProviderResult( jtoken.ToString(), CultureInfo.CurrentCulture);
}
}
在Startup中注冊:
services.AddMvc(options =>
{
options.ValueProviderFactories.Add(new JObjectValueProviderFactory());//取值
options.ModelBinderProviders.Insert(0, new JObjectModelBinderProvider());//加入Jobject綁定
});
由於新增//Jarray類型對.net core 1.1.0 MVC 控制器接收Json字串 (JObject對象) (一) JObjectModelBinderProvider做了改動
public class JObjectModelBinderProvider : IModelBinderProvider
{
public IModelBinder GetBinder(ModelBinderProviderContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (context.Metadata.ModelType == (typeof(JObject)))//同時支Body持數據JObject,和Form鍵值對
{
return new JObjectModelBinder(context.Metadata.ModelType);
}
if (context.Metadata.ModelType == (typeof(JArray)))//Jarray支持
{
return new JObjectModelBinder(context.Metadata.ModelType);
}
return null;
}
}
同樣也必須對JObjectModelBinder相應修改以增加對JObject,JArray支持,當然也可以另外寫
public class JObjectModelBinder : IModelBinder
{
public JObjectModelBinder(Type type)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
}
public Task BindModelAsync(ModelBindingContext bindingContext)
{
if (bindingContext == null) throw new ArgumentNullException("bindingContext");
ValueProviderResult result = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);//調用取值 ValueProvider
try
{
if (bindingContext.ModelType == typeof(JObject))
{
JObject obj = new JObject();
if (bindingContext.ActionContext.HttpContext.Request.ContentType == "application/json")//json
{
if (result.ToString().StartsWith("["))//是否是組?
{
obj =(JObject) JArray.Parse(result.ToString()).First;//取首值。
bindingContext.Result = (ModelBindingResult.Success(obj));
return Task.CompletedTask;
}
else
{
obj = JObject.Parse(result.ToString());//不是組直接取值
}
}
else //form
{
foreach (var item in bindingContext.ActionContext.HttpContext.Request.Form)
{
obj.Add(new JProperty(item.Key.ToString(), item.Value.ToString()));
}
}
if ((obj.Count == 0))
{
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(result.ToString()));
return Task.CompletedTask;
}
bindingContext.Result = (ModelBindingResult.Success(obj));
return Task.CompletedTask;
}
if (bindingContext.ModelType == typeof(JArray ))
{
JArray obj = new JArray();
if (bindingContext.ActionContext.HttpContext.Request.ContentType.
StartsWith("application/json", StringComparison.OrdinalIgnoreCase))//json
{
if (result.ToString().StartsWith("["))//是否是組?
{
JArray array = new JArray();
array = JArray.Parse(result.ToString());//取首值。
bindingContext.Result = (ModelBindingResult.Success(array));
return Task.CompletedTask;
}
}
if ((obj.Count == 0))
{
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, bindingContext.ModelMetadata.ModelBindingMessageProvider.ValueMustNotBeNullAccessor(result.ToString()));
return Task.CompletedTask;
}
bindingContext.Result = (ModelBindingResult.Success(obj));
return Task.CompletedTask;
}
return Task.CompletedTask;
}
catch (Exception exception)
{
if (!(exception is FormatException) && (exception.InnerException != null))
{
exception = ExceptionDispatchInfo.Capture(exception.InnerException).SourceException;
}
bindingContext.ModelState.TryAddModelError(bindingContext.ModelName, exception, bindingContext.ModelMetadata);
return Task.CompletedTask;
}
}
}
控制器寫法Form鍵值對、JObject、Jarry方式一樣 public IActionResult bout(JArray data)
在客戶客戶端有區別,JObject、Jarry數據必須指定: contentType: "application/json",//必須有
當以json內容為數組時提交,控制器接收類型為JObject,只取第一個JObject。