. net 7:条件Json序列化/反序列化



我正在开发。net 7 api,我遇到了一个关于DTO对象Id字段的问题。

这是我的UserDTO(用于在get中返回用户以及post/put用户):

public class UserDTO
{
public string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
public bool ShouldSerializeId()
{
return false;
}
}

UsersController邮报:

[HttpPost]
[Route("users")]
public async Task<IActionResult> CreateUserAsync(UserDTO u)
{
...
}

得到:

[HttpGet("user/{userId}")]
public async Task<IActionResult> GetUserByIdAsync(string userId)
{
var u = await _usersApplication.GetByIdAsync(userId);
var user = _mapper.Map<UserDTO>(u);
return Ok(user);
}

我的问题是离开类,这是下一个json由swagger作为Post请求:

{
"id": "string",
"email": "string",
"password": "string",
"firstName": "string",
"lastName": "string",
"status": true,
"roles": [
{
"roleName": "string"
}
]
}

当然,我不希望"Id"以自动生成的方式呈现在请求中。

如果我使用[JsonIgnore]属性,它可以工作,但是然后使用"Id"将不会在Get中显示,因为它显然是需要的。

我需要的是一个条件序列化/反序列化器。

我尝试了ShouldSerializeId"方法,但据我所知,它在。net 7中不再工作了,因为这个版本的。net附带了一个不同的Json序列化器,不支持它。

对条件序列化有什么帮助吗?

如果您根本不想显示Id属性,唯一的方法是将DTO分成两个

public class UserDTO:UserDtoBase
{
public string Id { get; set; }
}
public class UserDTOBase
{
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
}

和使用不带Id的post

使用JsonIgnore或自定义序列化器与在POST操作中分配Id = null相同,因为新的Dto将被创建,只是Id不会被分配,并且默认为null。

简单的答案-使用不同的dto来创建和返回数据:

public class CreateUserDTO
{
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
}

可以选择通过继承在UserDTOCreateUserDTO之间共享基本属性集。

对于序列化部分(如果你真的需要,尽管在这种特殊情况下它是多余的),你可以利用。net 7中添加到System.Text.Json中的契约自定义支持:

class TestSe
{
public int Id { get; set; }
public string Data { get; set; }
[System.Text.Json.Serialization.JsonIgnore]
public bool ShouldSerializeId { get; set; } = true;
}
void SetShouldSerialize(JsonTypeInfo info)
{
if (info.Type == typeof(TestSe))
{
// NB: this uses JSON property name, not a class member name
var jsonPropertyInfo = info.Properties.Single(propertyInfo => propertyInfo.Name == "Id");
jsonPropertyInfo.ShouldSerialize = static (obj, val) => ((TestSe)obj).ShouldSerializeId;
}
}

和用法:

var testSe = new TestSe
{
Data = "data"
};
var opts = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver
{
Modifiers =
{
SetShouldSerialize
}
}
};
Console.WriteLine(JsonSerializer.Serialize(testSe, opts)); // {"Id":0,"Data":"data"}
testSe.ShouldSerializeId = false;
Console.WriteLine(JsonSerializer.Serialize(testSe, opts)); // {"Data":"data"}

您是否尝试过使用[JsonIgnore]装饰器和Newtonsoft。净JSONConverter吗?

public class UserDTO
{
[JsonIgnore]
public string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
public bool ShouldSerializeId()
{
return false;
}
}

将对象结构拆分为两个对象—一个模型将保存在数据库中(如果要添加数据,返回的对象也可能是DTO)。"请求时间)和一个用于创建新用户。

public class User //This is the one you'll have in your database
{
[Key]
public string Id { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
}
public class NewUserRequest //This is the one you'll send to your endpoint
{
public string Email { get; set; }
public string Password { get; set; }
public string? FirstName { get; set; }
public string? LastName { get; set; }
public bool Status { get; set; } = true;
public List<RoleDTO> Roles { get; set; } = new List<RoleDTO>();
}