ASP.NET Web API中是否有与@JsonView等效的功能?

7

我在Spring和Java方面有更多的经验,但现在我正在开发ASP.NET Web API项目。

因此,在Spring中,有@JsonView注释,我可以使用它来注释我的DTO,以便我可以通过REST选择要显示的数据。 我觉得这非常有用。 但是我在ASP.NET中找不到任何等效的功能。 所以我需要为每个特殊用例创建DTO。

例如,在Java中,如果我有包含有关用户信息的UserEntity。 一些信息可以公开查看,而其他信息只能由管理员查看。 简单的解决方案可能是:

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实现相同的功能,我需要创建两个DTO。一个是供公众查看的用户DTO,另一个是仅供管理员查看的用户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中使用来创建视图呢?

2个回答

2

JSON.NET有一个叫做条件属性初始化的功能。您可以编写一个以下格式的方法:

public bool ShouldSerialize[YourPropertyName]() => someBoolCondition;

JSON.NET会调用该方法来确定是否应该序列化该属性。因此,您可以这样写:

public DateTime DateOfBirth {get; set;}

public bool ShouldSerializeDateOfBirth() => isAdmin;

它不如JsonView美观,但它应该能胜任工作。


您也可以尝试使用ServiceStack来实现这个功能。 - theMayer

2
你可以使用自定义合同解析器来实现。假设你有以下属性:
[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;
    }
}

并在配置文件中进行设置:

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格式 - 如果用户不是管理员,则会省略管理员属性。

请注意,如果您这样做:

[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序列化器以实现所需的结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接