将JSON对象转换为C#模型 Web API 2

4
这是我第四个使用AngularJS和Web API 2 C#后端的生产级系统。虽然我有经验,但我无法使非常简单的转换工作正常。我通常在Angular UI和Web API 2后端之间使用复杂模型而没有问题,所以这让我非常沮丧。
我会在下面发布JSON:
{
"appSelection": [
  {
  "name": "Withdrawal Service",
  "selected": true
  }
],
"dateSelection": {
  "startDate": "2016-06-13T23:00:00.000Z",
  "endDate": "2016-07-27T07:52:03.510Z"
},
"eventTypes": [
  {
  "name": "Fail",
  "selected": true
  },
  {
  "name": "Success",
  "selected": true
  }
]
}

针对Web API控制器:(为了简洁而编辑)

        [HttpPost]
        [Route("search")]
        [ResponseType(typeof(ProcessLog[]))]
        public async Task<IHttpActionResult> getLogs(LogRequest request)
        {
            string requestBody = string.Empty;
            using (var stream = new MemoryStream())
            {
                var context = (HttpContextBase)Request.Properties["MS_HttpContext"];
                context.Request.InputStream.Seek(0, SeekOrigin.Begin);
                context.Request.InputStream.CopyTo(stream);
                requestBody = Encoding.UTF8.GetString(stream.ToArray());
            }

这个模型被接受:

public class LogRequest
        {
            public DateViewModel DateSelection { get; set; }
            public NameAndSelect[] appSelection { get; set; }
            public NameAndSelect[] eventTypes { get; set; }
        }

        public class NameAndSelect
        {
            public bool selected { get; set; }
            public string name { get; set; }
        }
        public class DateViewModel
        {
            public DateTime startDate { get; set; }
            public DateTime endDate { get; set; }
        }

请求体的输出是:
{"appSelection":[{"name":"Withdrawal Service","selected":true}],"dateSelection":{"startDate":"2016-06-13T23:00:00.000Z","endDate":"2016-07-27T07:52:03.510Z"},"eventTypes":[{"name":"Fail","selected":true},{"name":"Success","selected":true}]}

这说明JSON已正确地POST到Web API控制器,但自动模型绑定失败了。请求对象(Web API接收的模型)是

DateSelection : null
appselection : null
eventTypes : null

我真的不明白为什么和在哪里出了问题。已经尝试了两天以上!非常感谢再来一双鲜眼。

提前感谢你的帮助。

更新 #1:

将模型更改为以下内容,但自动绑定仍然失败。

public class LogRequest
        {
            public DateViewModel DateSelection { get; set; }
            public List<NameAndSelect> appSelection { get; set; }
            public List<NameAndSelect> eventTypes { get; set; }
        }

更新 #2:

我已经尝试将模型简化为

public class LogRequestViewModel
    {
        public string testString { get; set; }
        public DateTime startDate { get; set; }
        public DateTime endDate { get; set; }
        public DateSelection dateselection { get; set; }
     }
public class DateSelection
     {
        public string startDate { get; set; }
        public string endDate { get; set; }
     }

并发布:

{"teststring":"plap","startdate":"2016-07-27T09:28:38.404Z","enddate":"2016-07-27T09:28:38.404Z","dateselection"
:{"startdate":"2016-07-27T09:28:38.404Z","enddate":"2016-07-27T09:28:38.404Z"}}

我收到:

dateselection:null
enddate:      {27/07/2016 10:28:38}
startdate:    {27/07/2016 10:28:38}
teststring:   "plap"

这表明它可以轻松转换日期时间,但更深层次的对象会导致问题


尝试使用通用列表来代替 List<NameAndSelect> - Shintu Joseph
我不感到意外@smoksnes - 我看不到它失败的理由。 - Mad Eddie
你是否已经连接了任何模型绑定器? - smoksnes
我已经尝试使用Angular $resource和$http,有时使用JSON.stringify,有时不使用,但由于我看不出它不能工作的原因,所以我并不惊讶它无法复制。 - Mad Eddie
1
@MadEddie,这是一个空白项目吗?如果不是,请尝试删除可能会干扰模型绑定的所有内容。例如配置中的格式化程序、模型绑定器等。由于在空白项目中可以正常工作,我认为您可能有一些干扰模型绑定的隐藏内容。请逐个删除所有内容。 - smoksnes
显示剩余10条评论
2个回答

3
感谢@Smoksnes的帮助,我已经将启动类和App_Start中所有JSON格式化程序注释掉了。不幸的是,这并没有解决问题。当我取消注释所有被注释的行时,我在我的WebApiConfig.cs文件中发现了以下内容。
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
            jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
            jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
            jsonFormatter.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.None;
            jsonFormatter.SerializerSettings.MaxDepth = 1;

重点!噢。 对所有的JSON格式化程序进行评论并没有解决问题,但除了这一行之外重新启用它们都修复了问题。我猜我需要其他一些格式化程序的组合,但不需要MaxDepth

谢谢大家。


真正的问题是:它一开始为什么在那里? 当你移除它时,现在会出现什么问题... :) - smoksnes
@smoksnes 这是为了防止Entity Framework返回包含在我的模型中深度相关/链接的实体(参见大规模递归)的JSON而进行的尝试。现在,每次初始化实体模型时,我都会添加ProxyCreationEnabled :( - Mad Eddie

0
    public class AppSelection
{
    public string name { get; set; }
    public bool selected { get; set; }
}

public class DateSelection
{
    public string startDate { get; set; }
    public string endDate { get; set; }
}

public class EventType
{
    public string name { get; set; }
    public bool selected { get; set; }
}

public class RootObject
{
    public List<AppSelection> appSelection { get; set; }
    public DateSelection dateSelection { get; set; }
    public List<EventType> eventTypes { get; set; }
}
change this model to your model and then try hope it will useful for you

同样是一个空模型,我很抱歉。 - Mad Eddie
奇怪,你能否存储这个JSON呢? - Pankaj Gupta
@MadEddie 为什么你在使用内存流,很好奇想知道。 - Pankaj Gupta
这是因为HTTPOST内容只能被读取一次,而Web API的内置模型绑定会在此方法之前读取它。 - Mad Eddie
展示完整的代码,才能更容易地找出错误。 - Pankaj Gupta

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接