【问题标题】:Is there @JsonView equivalent in ASP.NET Web APIASP.NET Web API 中是否有 @JsonView 等效项
【发布时间】:2018-04-06 04:02:15
【问题描述】:

我在 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 中的等效功能,我需要创建 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 中创建数据视图?

【问题讨论】:

    标签: java c# asp.net spring


    【解决方案1】:

    JSON.NET 有一个叫做Conditional Property Initialization 的东西。你可以编写如下格式的方法:

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

    JSON.NET 将调用该方法来确定该属性是否应该被序列化。所以你可以有类似的东西:

    public DateTime DateOfBirth {get; set;}
    
    public bool ShouldSerializeDateOfBirth() => isAdmin;
    

    它不如JsonView 漂亮,但它应该可以胜任。

    【讨论】:

    • 您也许还可以使用 ServiceStack 来实现此功能。
    【解决方案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"
        });
    }
    

    不使用格式化程序,您必须自己使用自定义格式化程序传递序列化设置(当然您需要将其变成可重用的方法,例如在您的基本控制器中声明 Json 方法,所有其他方法都从该方法继承):

    return Json(new UserDto()
    {
        ID = 1,
        DateOfBirth = DateTime.UtcNow,
        Email = "test",
        Name = "name"
    }, GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings);
    

    使用角色只是一个示例,展示了如何扩展 asp.net api 默认使用的 JSON.NET 序列化程序以实现所需的结果。

    【讨论】:

      猜你喜欢
      • 2012-04-08
      • 2014-05-28
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多