我正在尝试在控制器保存操作上将JSON映射到c#ViewModel。基本上,JSON具有以下结构:
{
"Id": "",
"TypeId": "37",
"FormId": "",
"ExtraData":{
"title": "Some random title",
"contribute": "author",
"location": {
"url": "/Files/ed5cf2ea-c920.jpeg",
"size": "100",
"format": "application/json"
}
}
}
有些字段是“知道”而另一些则不是。 'ExtraData'是所有这些未知字段的容器,它们可以变化很大。
我创建了一个c#VIewModel来映射它:
public class ContentViewModel
{
public Guid Id { get; set; }
public int TypeId{ get; set; }
public int FormId{ get; set; }
public Dictionary<string, object> ExtraData { get; set; }
}
当我使用上面的JSON发出请求时,只会映射ExtraData的“root”元素。 “location”对象被映射到一个对象。
我试图将Dictionary更改为动态,仍然无法正常工作。我也尝试创建一个JsonConverter,但它从未被执行过。我的猜测它不适用于开箱即用的ASP.NET MVC应用程序?
我尝试了很多东西,搜索过,我觉得我走到了尽头。
编辑:ExtraData将按原样存储在MongoDB中。它可以非常简单或复杂(具有多个节点和嵌套对象)。
答案 0 :(得分:3)
如果您可以使用“动态”对象解析您的要求(因为您提到过,您已经尝试将字典更改为动态),您可以尝试使用以下方法。
请注意,虽然我不确定这种方法是否符合您的要求,但我希望它可以从某种方式开始帮助您。
我采用了自定义模型绑定器(针对特定属性Type)方法,因为这是处理ASP.NET MVC中复杂模型/属性绑定的另一个可扩展点
自定义模型活页夹
public class ComplexObjectModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var contentType = controllerContext.HttpContext.Request.ContentType;
if (!contentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
return (null);
string jsonString;
using (var stream = controllerContext.HttpContext.Request.InputStream)
{
stream.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(stream))
jsonString = reader.ReadToEnd();
}
if (string.IsNullOrEmpty(jsonString)) return (null);
DynamicComplexObject ExtraData = new DynamicComplexObject();
ExtraData.Details = new JavaScriptSerializer().Deserialize<dynamic>(jsonString);
return (ExtraData);
}
}
在Global.asax中注册自定义活页夹:
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
//Custom model binder registration
ModelBinders.Binders.Add(typeof(Models.DynamicComplexObject), new ComplexObjectModelBinder());
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
查看模型:
public class ContentViewModel
{
public Guid Id { get; set; }
public int TypeId { get; set; }
public int FormId { get; set; }
public DynamicComplexObject ExtraData { get; set; }
}
//You may try to improve the following model and update the custom model binder logic as appropriate.
public class DynamicComplexObject
{
public dynamic Details { get; set; }
}
在下面的JSON中,我添加了一个用于测试的级别嵌套
var data = {
"Id": "",
"TypeId": "37",
"FormId": "",
"ExtraData": {
"title": "Some random title",
"contribute": "author",
"location": {
"url": "/Files/ed5cf2ea-c920.jpeg",
"size": "100",
"format": "application/json",
"onemorelocation": { //Added one more nested object to test
"a": 1,
"b": 2
}
}
}
};
$("#btnSubmit").on("click", function () {
$.ajax({
"datatype": "json",
"contentType": "application/json; charset=utf-8",
"type": "POST",
"url": '@Url.Action("SaveData", "Home")',
"data": JSON.stringify(data),
success: function (d) {
//Do stuff here
}
});
});
答案 1 :(得分:0)
Siva的回答可能有效,但我不想搞乱默认的Model Binder。阅读this后,我能理解为什么我的动态/词典没有正确绑定。
所以,我已经创建了一个自定义的ValueProvider,它取代了默认的JsonValueProviderFactory,它不能用于动态的嵌套字典。
<强> JsonNetValueProviderFactory 强>
public sealed class JsonNetValueProviderFactory : 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;
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 ExpandoObjectConverter()), CultureInfo.CurrentCulture);
}
}
<强>的Global.asax.cs 强>
public static void RegisterFactory()
{
ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType<JsonValueProviderFactory>().FirstOrDefault());
ValueProviderFactories.Factories.Add(new JsonNetValueProviderFactory());
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple,
TypeNameHandling = TypeNameHandling.All
};
}
<强>视图模型强>
public class ContentViewModel
{
public Guid Id { get; set; }
public int TypeId{ get; set; }
public int FormId{ get; set; }
public dynamic ExtraData { get; set; }
}
同样,Siva的答案也可能有效,但对于我的情况,我认为创建自定义ValueProvider而不是弄乱模型绑定器会更好。
此外,列出了非常有用的链接: ASP.Net MVC3 JSON.Net Custom ValueProviderFactory ASP.NET MVC 3 – Improved JsonValueProviderFactory using Json.Net