2

The Visual Studio "Web API" project template includes endpoints for handling registration, authentication, and authorization of users. In a production application, however, users will typically be associated with other Entities as well, such as:

public class Post {
  public Post() {};
  public int Id { get; set; }
  public ApplicationUser User { get; set; }
}

In these scenarios, the ApplicationUser class (which is derived from IdentityUser) cannot be serialized. Attempting to do so will yield an error similar to:

The 'ObjectContent`1' type failed to serialize the response body for content type 'application/json; charset=utf-8'.

I've seen similar issues raised elsewhere with the recommendation to pass a DTO instead of the ApplicationUser object. That seems like a lot of developer overhead, however. Is there not a way to serialize ApplicationUser directly?

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77

1 Answers1

4

Obviously, there are properties available on IdentityUser which should not be publicly exposed to other users, such as PasswordHash. Others, such as Email and PhoneNumber may violate user privacy expectations depending on your API's authentication settings. As such, which properties are and are not exposed should be carefully evaluated. Using a DTO addresses these issues.

That said, there is no reason you can't configure the IdentityUser class to be serialized by adding the DataContractAttribute to your inherited class:

[DataContract] 
public class ApplicationUser : IdentityUser {
  //...
}

You may then explicitly include any custom properties you wish to expose using the DataMemberAttribute:

[DataMember]
public string TwitterHandle { get; set; }

If you wish to expose members of UserIdentity, you'll need to override them:

[DataMember]
public override string UserName {
  get {
    return base.UserName;
  }
  set {
    base.UserName = value;
  }
}

Finally, it's worth noting that these properties will be shared with anyone who has access to the endpoint. If you want more detailed control over who sees what then wrapping the object in a DTO will provide that.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
  • I wasn't able to serialize User by adding `[DataContract]` and `[DataMember]` attributes. Probably, the only way to make it work is to create a separate DTO class. – Ivan Yurchenko Sep 29 '17 at 09:05
  • 1
    I've found another solution using anonymous types here: https://stackoverflow.com/a/658056/3731444 – Ivan Yurchenko Sep 29 '17 at 09:23