如何使用 MongoDB 将动态 JSON 属性发布到 C# ASP.Net Core Web API?
Posted
技术标签:
【中文标题】如何使用 MongoDB 将动态 JSON 属性发布到 C# ASP.Net Core Web API?【英文标题】:How to post a dynamic JSON property to a C# ASP.Net Core Web API using MongoDB? 【发布时间】:2017-12-09 16:44:45 【问题描述】:似乎 MongoDB 的优势之一是能够将您需要的任何内容存储在 Object 类型属性中,但似乎不清楚如何通过 C# Web 从客户端 ajax 帖子获取动态属性信息MongoDB 的 API。
我们希望允许管理员创建一个带有标题和开始日期/时间的事件,但我们也希望允许用户使用响应式表单添加自定义表单字段,以满足他们想要的任何内容,例如 T 恤尺寸或膳食偏好。 .. 无论用户将来想出什么。然后,当有人注册该事件时,他们会将 EventID 和自定义字段发布到 Web API。
我们可以拥有一个包含 _id、event_id、reg_time 和 form_fields 的 Event MongoDB 集合,其中 form_fields 是存储动态数据的对象类型。
所以我们想用自定义的 FormsFields 发布这个 JSON 的变体:
变体 1:
"EventId": "595106234fccfc5fc88c40c2",
"RegTime":"2017-07-21T22:00:00Z",
"FormFields":
"FirstName": "John",
"LastName": "Public",
"TShirtSize": "XL"
变体 2:
"EventId": "d34f46234fccfc5fc88c40c2",
"RegTime":"2017-07-21T22:00:00Z",
"FormFields":
"Email": "John.Public@email.com",
"MealPref": "Vegan"
我想要一个带有 Post 操作的 EventController,它采用映射到上述 JSON 的自定义 C# EventReg 对象。
事件控制器:
[HttpPost]
public void Post([FromBody]EventReg value)
eventService.AddEventRegistration(value);
EventReg 类:
public class EventReg
public EventReg()
FormFields = new BsonDocument();
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string EventRegId get; set;
[BsonElement("EventId")]
[BsonRepresentation(BsonType.ObjectId)]
public string EventId get; set;
[BsonElement("reg_time")]
public DateTime RegTime
set; get;
[BsonElement("form_fields")]
public MongoDB.Bson.BsonDocument FormFields get; set;
事件服务
public string AddEventRegistration(EventReg eventReg)
this.database.GetCollection<EventReg>("event_regs").InsertOne(eventReg);
return eventReg.EventRegId;
现在,如果我发布到控制器,我的 EventReg 为 null,因为它一定不知道如何将我的 JSON FormFields 属性映射到 BsonDocument。
FormFields 可以使用什么类型? 我可以将 FormFields 属性设置为 BsonDocument,是否有一种简单的方法可以将 Web API 参数映射到该属性? 是否有示例说明某些自定义序列化程序在这种情况下如何工作?我们也许可以使用动态类型并循环通过发布的属性,但这看起来很难看。我还从这里的帖子中看到了 JToken 解决方案,但这看起来也很丑陋。
如果 MongoDB 打算像这样动态使用,难道不应该有一个干净的解决方案将动态数据传递给 MongoDB 吗?有什么想法吗?
【问题讨论】:
【参考方案1】:JToken 示例用于获取数据,但在检索时会导致浏览器和 Postman 抛出错误并显示警告,指示内容被作为文档读取,但它是 application/json 格式。我看到 FormFields 属性被返回为 "TShirtSize":"XL" 所以在序列化过程中双括号可能是一个问题。
我最终在 System.Dynamic 命名空间中使用了 .NET ExpandoObject。 ExpandoObject 与 MongoDB BsonDocument 兼容,因此序列化会像您期望的那样自动完成。所以不需要奇怪的代码来手动处理问题中的 JToken 示例等属性。
我仍然认为,如果可能的话,应该使用更强类型的 C# 表示,但是如果您必须允许任何 JSON 内容通过 Web API 以自定义 C# 类作为输入发送到 MongoDB,那么 ExpandoObject 应该这样做诀窍。
看看下面 EventReg 类的 FormFields 属性是如何变成 ExpandoObject 的,并且没有代码可以手动处理保存到 MongoDB 的对象的属性。
这是用标准类型属性和动态 FormFields 属性手动填充对象的原始有问题且过于复杂的 JToken 代码:
[HttpPost]
public void Post([FromBody]JToken token)
if (token != null)
EventReg eventReg = new EventReg();
if (token.Type == Newtonsoft.Json.Linq.JTokenType.Object)
eventReg.RegTime = DateTime.Now;
foreach (var pair in token as Newtonsoft.Json.Linq.JObject)
if (pair.Key == "EventID")
eventReg.EventId = pair.Value.ToString();
else if (pair.Key == "UserEmail")
eventReg.UserEmail = pair.Value.ToString();
else
eventReg.FormFields.Add(new BsonElement(pair.Key.ToString(), pair.Value.ToString()));
//Add Registration:
eventService.AddEventRegistration(eventReg);
使用 ExpandoObject 消除了对所有这些代码的需要。请参阅下面的最终代码。 Web API 控制器现在是 1 行而不是 30 行代码。此代码现在可以毫无问题地从上述问题中插入和返回 JSON。
事件控制器:
[HttpPost]
public void Post([FromBody]EventReg value)
eventService.AddEventRegistration(value);
EventReg 类:
public class EventReg
public EventReg()
FormFields = new ExpandoObject();
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
public string EventRegId get; set;
[BsonElement("event_id")]
[BsonRepresentation(BsonType.ObjectId)]
public string EventId get; set;
[BsonElement("user_email")]
public string UserEmail get; set;
[BsonElement("reg_time")]
public DateTime RegTime get; set;
[BsonElement("form_fields")]
public ExpandoObject FormFields get; set;
事件服务:
public string AddEventRegistration(EventReg eventReg)
this.database.GetCollection<EventReg>("event_regs").InsertOne(eventReg);
return eventReg.EventRegId;
【讨论】:
【参考方案2】:在 ASP.NET Core 3.0+ 中,Newtonsoft.Json 不再是默认的 JSON 序列化程序。因此我会使用 JsonElement:
[HttpPost("general")]
public IActionResult Post([FromBody] JsonElement elem)
var title = elem.GetProperty("title").GetString();
...
【讨论】:
【参考方案3】:如果您不确定要发送的 Json 的类型,即如果您正在处理动态 json。那么下面的方法将起作用。 接口:
[HttpPost]
[Route("demoPath")]
public void DemoReportData([FromBody] JObject Jsondata)
来自 .net 核心应用程序的 Http 客户端调用:
using (var httpClient = new HttpClient())
return await httpClient.PostAsJsonAsync(serviceUrl,
new demoClass()
id= "demoid",
name= "demo name",
place= "demo place"
;).ConfigureAwait(false);
【讨论】:
【参考方案4】:您可以将FormFields定义为字符串,将JSON转成字符串后以字符串格式发送数据到API:
"\"FirstName\":"John\",\"LastName\":\"Public\",\"TShirtSize\":\"XL\""
然后在您的控制器中将字符串解析为 BsonDocument
BsonDocument.Parse(FormFields);
我会使用 AutoMapper 来自动化 dto 和文档之间的转换
【讨论】:
以上是关于如何使用 MongoDB 将动态 JSON 属性发布到 C# ASP.Net Core Web API?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JavaScript 中使用 Mongoose 动态更新文档?
如何将 JSON 数据格式化为动态生成对象属性的 C# 对象