Is there an @JsonView equivalent in ASP.NET Web API

I have much more experience with Spring and Java, but now I am working on an ASP.NET Web API project.

So, in Spring there is an @JsonView annotation with which I can annotate my DTOs, so I could choose which data I will show through REST. And I find it very useful. But I can not find the equivalent in ASP.NET. Therefore, I need to create a DTO for each special utility.

So, for example, in Java, if I have a UserEntity that contains information about users. Some information can be seen publicly, and some are visible only to admins. One solution might be this

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; } 

So, in this case, for equivalent functionality in ASP.NET I will need to create 2 DTOs. One for the user that can be seen publicly and one for the user that can only be seen by the administrator.

 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;} } 

Is there a better solution? Is there any mechanism that I can use to create a view on my data in the ASP.NET Web API?

+5
source share
2 answers

JSON.NET has something called Conditional Property Initialization . You can write a method in the following format:

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

JSON.NET will call this method to determine if this property should be serialized or not. So you can have something like:

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

This is not as good as JsonView , but it should do the job.

+1
source

You can implement this yourself using a custom contract resolver. Suppose you have an attribute:

 [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class JsonViewAttribute : Attribute { public JsonViewAttribute(string viewName) { ViewName = viewName; } public string ViewName { get; } } 

Views:

 public static class JsonViews { public const string Administrator = "Administrator"; } 

And the DTO class:

 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; } } 

And your goal is to serialize properties decorated with JsonView only if the current user is authenticated and has the target role ("Administrator"). Then you can create a contract converter as follows:

 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; } } 

And set it to config:

 public static void Register(HttpConfiguration config) { config.MapHttpAttributeRoutes(); config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new JsonViewContractResolver(config.Formatters.JsonFormatter); } 

Now when you return json in the controller as follows:

 [System.Web.Http.HttpGet] public UserDto Get() { return new UserDto() { ID = 1, DateOfBirth = DateTime.UtcNow, Email = "test", Name = "name" }; } 

And it is serialized in the json-admin properties, which will be omitted if the user is not an administrator.

Please note that if you do this:

 [System.Web.Http.HttpGet] public IHttpActionResult Get() { return Json(new UserDto() { ID = 1, DateOfBirth = DateTime.UtcNow, Email = "test", Name = "name" }); } 

Formatter is not used, and you yourself must pass serialization parameters using custom formatting (of course, you need to make it a reusable method, for example, declare the Json method in your base controller from which everyone else inherits):

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

Using roles is just an example showing how, by default, you can extend the JSON.NET serializer used by asp.net api to achieve the desired result.

+1
source

Source: https://habr.com/ru/post/1276268/


All Articles