ASP.NET MVC中C#类序列化为JSON的实现及EF优化方案问询
我在ASP.NET MVC项目中通过VS菜单「编辑>选择性粘贴>将JSON粘贴为类」生成了如下C#类:
public class Rootobject { public string MerchantOrderId { get; set; } public Customer Customer { get; set; } public Payment Payment { get; set; } } public class Customer { public string Name { get; set; } } public class Payment { public string Type { get; set; } public bool Authenticate { get; set; } public int Amount { get; set; } public string ReturnUrl { get; set; } public Debitcard DebitCard { get; set; } } public class Debitcard { public string CardNumber { get; set; } public string Holder { get; set; } public string ExpirationDate { get; set; } public string SecurityCode { get; set; } public string Brand { get; set; } }
我希望使用自定义数据,而非直接通过「Rootobject obj = new Rootobject { ... }」的方式实例化对象,在控制器中通过「return Json(MyModel, JsonRequestBehavior.AllowGet);」语句将其序列化为指定格式的JSON。请问该如何构建自定义数据模型实现序列化?是否有借助EF实现的更优方案?
嘿,其实你已经拿到了最核心的东西——VS生成的这些类本身就是完美适配目标JSON格式的序列化模型,根本不需要额外重新构建!下面我分两种场景给你讲具体实现方式:
一、手动填充自定义数据并序列化
你觉得直接new Rootobject { ... }不够“自定义”?其实可以把数据填充的逻辑抽离出来,比如放到专门的服务类或者方法里,让代码更整洁,示例如下:
1. 抽离数据填充逻辑
先写一个专门的方法来生成填充好的模型,这里的数据可以从任意来源获取:
private Rootobject BuildCustomPaymentModel() { // 示例:从请求表单、配置或第三方接口获取自定义数据 string orderId = $"ORD-{DateTime.Now:yyyyMMdd}-{new Random().Next(1000,9999)}"; string customerName = Request.Form["CustomerName"] ?? "默认用户"; int paymentAmount = int.Parse(Request.Form["Amount"] ?? "500"); return new Rootobject { MerchantOrderId = orderId, Customer = new Customer { Name = customerName }, Payment = new Payment { Type = "DebitCard", Authenticate = true, Amount = paymentAmount, ReturnUrl = Url.Action("PaymentResult", "Home", null, Request.Url.Scheme), DebitCard = new Debitcard { CardNumber = "4111****1111", // 实际项目注意卡号脱敏 Holder = customerName, ExpirationDate = "12/28", SecurityCode = "***", Brand = "Visa" } } }; }
2. 在控制器中调用并返回
然后在控制器Action里调用这个方法,直接返回JSON:
public ActionResult GeneratePaymentJson() { var myModel = BuildCustomPaymentModel(); // ASP.NET MVC 5+ 可省略 JsonRequestBehavior.AllowGet,默认允许GET请求返回JSON return Json(myModel); }
3. 自定义属性映射(可选)
如果想要修改类名/属性名,但又要和目标JSON的键保持一致,可以用Newtonsoft.Json的[JsonProperty]特性(需先安装Newtonsoft.Json NuGet包):
using Newtonsoft.Json; // 把Rootobject改成更有意义的名字 public class PaymentOrder { // 让属性名OrderId对应JSON里的MerchantOrderId [JsonProperty("MerchantOrderId")] public string OrderId { get; set; } public Customer Customer { get; set; } public Payment Payment { get; set; } }
二、借助EF实现的更优方案(数据来自数据库)
如果你的自定义数据来自数据库,EF可以帮你更高效地获取并转换数据,主要有两种方式:
1. 让EF实体类直接匹配序列化结构
如果数据库表结构和目标JSON结构对应,可以直接定义EF实体类(可用EF反向生成工具从数据库生成):
// EF实体类,对应数据库中的PaymentOrders表 public class PaymentOrderEntity { public int Id { get; set; } public string MerchantOrderId { get; set; } // 导航属性,关联Customer表 public virtual CustomerEntity Customer { get; set; } // 导航属性,关联Payment表 public virtual PaymentEntity Payment { get; set; } } public class CustomerEntity { public int Id { get; set; } public string Name { get; set; } public int PaymentOrderId { get; set; } public virtual PaymentOrderEntity PaymentOrder { get; set; } } // 其他实体类(PaymentEntity、DebitcardEntity)同理,和序列化模型结构对齐
然后在控制器中从EF上下文查询数据,直接返回或者转换:
public ActionResult GetPaymentOrderFromDb(int orderId) { using(var dbContext = new YourDbContext()) { // 关联查询所需的导航属性 var dbOrder = dbContext.PaymentOrders .Include(o => o.Customer) .Include(o => o.Payment.DebitCard) .FirstOrDefault(o => o.Id == orderId); if(dbOrder == null) { return HttpNotFound(); } // 如果EF实体和序列化模型完全一致,直接返回 return Json(dbOrder); // 如果实体和模型结构有差异,手动转换或者用AutoMapper自动映射 // var serializedModel = new Rootobject // { // MerchantOrderId = dbOrder.MerchantOrderId, // Customer = new Customer { Name = dbOrder.Customer.Name }, // // 其他属性转换... // }; // return Json(serializedModel); } }
2. 使用EF投影直接生成序列化模型
不需要查询完整的EF实体,直接通过LINQ投影生成需要的序列化模型,这样可以减少数据库查询的数据量,性能更优:
public ActionResult GetProjectedPaymentOrder(int orderId) { using(var dbContext = new YourDbContext()) { var myModel = dbContext.PaymentOrders .Where(o => o.Id == orderId) .Select(o => new Rootobject { MerchantOrderId = o.MerchantOrderId, Customer = new Customer { Name = o.Customer.Name }, Payment = new Payment { Type = o.Payment.Type, Authenticate = o.Payment.Authenticate, Amount = o.Payment.Amount, ReturnUrl = o.Payment.ReturnUrl, DebitCard = new Debitcard { CardNumber = o.Payment.DebitCard.CardNumber.Substring(0,4) + "****" + o.Payment.DebitCard.CardNumber.Substring(8), Holder = o.Payment.DebitCard.Holder, ExpirationDate = o.Payment.DebitCard.ExpirationDate, SecurityCode = "***", Brand = o.Payment.DebitCard.Brand } } }) .FirstOrDefault(); return myModel == null ? HttpNotFound() : Json(myModel); } }
内容的提问来源于stack exchange,提问作者user8207463

