我在Spring和Java方面有很多经验,但现在我正在开发ASP.NET Web API项目。
所以在Spring中有@JsonView注释,我可以用它来注释我的DTO,所以我可以选择通过REST显示哪些数据。而且我发现它非常有用。但我在ASP.NET中找不到任何等价物。所以我需要为每个特殊用例创建DTO。
因此,例如在Java中,如果我有UserEntity包含有关用户的信息。有些信息可以公开查看,有些信息只能由管理员查看。 siple解决方案可能是这个
public class UserEntity {
@JsonView(Views.Public.class)
@JsonProperty("ID")
private Integer id;
@JsonView(Views.Public.class)
private String name;
@JsonView(Views.Admin.class)
@JsonFormat(
shape = JsonFormat.Shape.STRING,
pattern = "dd-MM-yyyy hh:mm:ss")
private Date dateOfBirth;
@JsonView(Views.Admin.class)
private String email;
@JsonIgnore
private String password;
private Integer version;
}
因此,在这种情况下,对于ASP.NET中的等效功能,我需要创建2个DTO。一个可以公开查看的用户,另一个只能由管理员查看的用户。
public class PublicUserDto {
public int ID {get; set;}
public String Name {get; set;}
}
public class AdminUserDto {
public int ID {get; set;}
public String Name {get; set;}
public DateTime DateOfBirth {get; set;}
public string Email {get; set;}
}
有没有更好的解决方案?是否有一些机制可用于在ASP.NET Web API中创建我的数据视图?
答案 0 :(得分:1)
JSON.NET有一个名为Conditional Property Initialization的东西。您可以使用以下格式编写方法:
public bool ShouldSerialize[YourPropertyName]() => someBoolCondition;
JSON.NET将调用该方法来确定是否应该序列化该属性。所以你可以有类似的东西:
public DateTime DateOfBirth {get; set;}
public bool ShouldSerializeDateOfBirth() => isAdmin;
它不像JsonView
那么漂亮,但应该可以胜任。
答案 1 :(得分:1)
您可以使用自定义合约解析程序自行实现。假设你有属性:
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
public class JsonViewAttribute : Attribute {
public JsonViewAttribute(string viewName) {
ViewName = viewName;
}
public string ViewName { get; }
}
查看:
public static class JsonViews {
public const string Administrator = "Administrator";
}
和DTO课程:
public class UserDto
{
public int ID { get; set; }
public String Name { get; set; }
[JsonView(JsonViews.Administrator)]
public DateTime DateOfBirth { get; set; }
[JsonView(JsonViews.Administrator)]
public string Email { get; set; }
}
您的目标是仅在当前用户经过身份验证且具有目标角色("管理员")时序列化用JsonView
修饰的属性。然后你可以创建这样的合同解析器:
public class JsonViewContractResolver : JsonContractResolver {
public JsonViewContractResolver(MediaTypeFormatter formatter) : base(formatter) {
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) {
JsonProperty property = base.CreateProperty(member, memberSerialization);
var viewAttr = member.GetCustomAttribute<JsonViewAttribute>();
if (viewAttr != null) {
// if decorated with attribute
property.ShouldSerialize = (instance) => {
var context = HttpContext.Current;
if (context == null)
return true;
// we are in context of http request
if (context.User == null || context.User.Identity == null)
return false;
// should serialize only if user is in target role
return context.User.Identity.IsAuthenticated && context.User.IsInRole(viewAttr.ViewName);
};
}
return property;
}
}
并在config中设置:
public static void Register(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonViewContractResolver(config.Formatters.JsonFormatter);
}
现在每当你在控制器中返回json时都会这样:
[System.Web.Http.HttpGet]
public UserDto Get()
{
return new UserDto()
{
ID = 1,
DateOfBirth = DateTime.UtcNow,
Email = "test",
Name = "name"
};
}
它被序列化为json - 如果用户不是管理员,则会省略admin属性。
请注意,如果您这样做:
[System.Web.Http.HttpGet]
public IHttpActionResult Get()
{
return Json(new UserDto()
{
ID = 1,
DateOfBirth = DateTime.UtcNow,
Email = "test",
Name = "name"
});
}
没有使用Formatter,你必须自己传递自定义格式化程序的序列化设置(当然你需要将它变成可重用的方法,例如在你的基本控制器中声明所有其他继承的Json方法):
return Json(new UserDto()
{
ID = 1,
DateOfBirth = DateTime.UtcNow,
Email = "test",
Name = "name"
}, GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings);
使用角色只是一个示例,说明默认情况下如何扩展asp.net api使用的JSON.NET序列化程序以获得所需的结果。