我正在将.NET Core与Newtonsoft.Json一起使用。我有一个UserModel
属性的List<Claim>
类
public class UserModel
{
public string GUID { get; set; }
public bool isActive { get; set; }
public string Username { get; set; }
public string Password { get; set; }
public List<Claim> Claims { get; set; }
}
,而我试图像这样将JSON请求解析为该对象类:
public IActionResult Testpost([FromBody]JObject body)
{
if (body == null) return BadRequest();
UserModel user = JsonConvert.DeserializeObject<UserModel>(body.ToString());
return Ok(user);
}
但是将JSON反序列化为我无法访问的类似Claim
类的对象会抛出异常
Newtonsoft.Json.JsonSerializationException:'无法找到用于类型System.Security.Claims.Claim的构造函数。一个类应该具有一个默认构造函数,一个带有参数的构造函数或一个标有JsonConstructor属性的构造函数。路径“索赔”
因为它不能决定构造函数
根据在线资源,我可以创建一个自定义转换器类,该类可以管理UserModel
对象的创建,但是我想避免这种情况。
是否可以将JSON对象反序列化到我的UserModel
类中,并告诉JsonConvert.DeserializeObject
使用像Claim(String, String)
这样的特定Claim构造函数来解析Claims?
编辑: 如@PaulG所述,我已经检查了How to programmatically choose a constructor during deserialization?
的答案但是,使用的可接受解决方案创建一个新类,该类实现JsonConverter类,然后手动解析JObject请求的主体。而且,答案显示了如何处理Claims,而不是处理将Claims嵌套为属性的复杂对象
在线程中阅读另一种解决方案,它显示了如何创建一个类来直接实现所需的构造函数,如下所示:
class MyClaim : Claim {
public MyClaim(string type, string value):
base(type, value){}
}
但是,这将要求我在编写代码时注意Claim和MyClaim之间的区别。 JSON转换器可能无法假定要使用哪个构造函数,但我应该能够告诉它哪个。还是它是设计使然,我必须为此专门吸收并编写额外的代码?
因为对我来说替代方法是这样的:
public IActionResult CreatePublicUser([FromBody]JObject body)
{
string Username = body["Username"].ToString();
string Password = body["Password"].ToString();
var Claims = body["Claims"].Children();
List<Claim> UserClaims = new List<Claim>();
foreach (var c in Claims)
{
UserClaims.Add(
new Claim(
c["Type"].ToString(),
c["Value"].ToString()
)
);
}
UserModel NewUser = (new UserBuilder())
.WithUserName(Username)
.WithPassword(Password)
.WithClaims(UserClaims)
.Build();
return Ok(NewUser)
}
答案 0 :(得分:0)
我建议您完全采用另一种方法,这也是一种常见做法。定义仅用于与客户互动的模型,例如
public class UserModelWeb
{
public List<ClaimWeb> Claims { get; set; }
}
这些DTO对象将仅用于从JSON进行数据转换,而不会用于业务逻辑层。然后,您可以将Web模型映射到以后将要使用的业务逻辑。这将使您在读取外部数据时不必依赖内部类。即如果您突然添加了一个新字段,它将从外部(可能是不受信任的)源中填充。这种明确的关注点分离将不允许这样做,因为您将必须在Web模型中显式定义一个字段。
您的情况的示例:假设您稍后在数据库中将只有一个内部字段可以编辑:“ InternalNote”。如果您将该字段添加到模型中,则任何人都可以发布数据并编辑该字段,而您的意图只是允许您自己对其进行编辑。
此外,这将解决您的问题,因为您无需转换为其他类。
P.S。您可以在操作方法中直接使用您的类:
MyAction([FromBody]UserModelWeb user)
应该立即从json反序列化。