Click here to Skip to main content
Click here to Skip to main content

Conditional WCF DataContract Serialization (Using DataContractSurrogate)

, 11 Jul 2012
Rate this:
Please Sign up or sign in to vote.
How to add conditional DataContract Serialization in a declarative manner.

Introduction

During the development of Web Services for our system, we wanted to design a common service layer, and common data contracts which would cater to requirements of different role based users. User role distinction was important, because there were some sensitive data points which could be shared only with privileged users. One way to design this was to make the data translators role specific. The translators could ascertain the user role, and serialize the data accordingly. The approach was simple but not elegant, and would have introduced lot of additional role checks in various translators.  

An alternative was to keep the service layer and translators role agnostic, and use a more declarative approach by using Data Contract Surrogates. Data Contract Surrogate is an advanced feature which can be used to introduce special behavior during Data Contracts Serialization\Deserialization.

Implementation

Let's start by defining an attribute ConditionalDataMemberAttribute. This attribute will be used to decorate DataMembers which need to be conditionally serialized. Usage of this attribute is discussed later. 

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class ConditionalDataMemberAttribute : Attribute

Next step is to create a custom Service Behavior called ConditionalDataBehavior.

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ConditionalDataBehavior : Attribute, IServiceBehavior

In service behavior ConditionalDataBehavior,we override the DataContractSurrogate for each operation with our custom implementation of Data Contract Surrogate   ConditionalDataContractSurrogate

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
  foreach (ServiceEndpoint ep in serviceHostBase.Description.Endpoints) {
    foreach (OperationDescription od in ep.Contract.Operations) {
      ApplyDataContractSurrogate(od);
    }
  }
}

private static void ApplyDataContractSurrogate(OperationDescription description)
{
  var dcsOperationBehavior = description.Behaviors.Find<datacontractserializeroperationbehavior>();
  if (dcsOperationBehavior != null) {
    dcsOperationBehavior.DataContractSurrogate = new ConditionalDataContractSurrogate(dcsOperationBehavior.DataContractSurrogate);
  }
}

The class ConditionalDataContractSurrogate implements the Interface IDataContractSurrogate. We add our custom implementation to the method GetObjectToSerialize. During serialization this method is called on every object that needs to be serialized. This gives an opportunity to inspect each object before serialization. If the calling context is not authorized (checked inside IsAuthorized) to receive the object, then  we prevent the actual value from being serialized.

public object GetObjectToSerialize(object obj, Type targetType)
{
  if (obj == null) return null;

  var type = obj.GetType();
  type.GetProperties().ToList()
    .ForEach(prop => {
      try {
        var attr = prop.GetCustomAttributes(typeof(ConditionalDataMemberAttribute), false);
        if (attr.Any()) {
          var role = ((ConditionalDataMemberAttribute)attr[0]).Role;
          //Is the user authorized
          if (!IsAuthorized(role)) {
            var proptype = prop.PropertyType;
            //Set the property value to its default value
            prop.GetSetMethod().Invoke(obj,
                                       new[] { proptype.IsValueType ? Activator.CreateInstance(proptype) : null });
          }
        }
      } catch { }
    });

  return _baseSerializer != null ? _baseSerializer.GetObjectToSerialize(obj, targetType) : obj;
}

Using the code  

Step 1:  Decorate your webservice with ConditionalDataBehavior attribute.   

[ServiceBehavior(Namespace = "http://mywebservice.com/v1")]
[ConditionalDataBehavior]
public class MyWebService

Step 2:  Decorate the Data Contracts with ConditionalDataMember attribute.

[DataContract]
public class UserInformation
{
    [DataMember]
    public string FirstName { get; set; }
    [DataMember]
    public string LastName { get; set; }
    [DataMember]
    [ConditionalDataMember(Role = "Level2")]
    public string Email { get; set; }
    [DataMember]
    [ConditionalDataMember(Role = "Level2")]
    public string Phone { get; set; }
}

Step 3: Add your own implementation of IsAuthroized function.

private bool IsAuthorized(string role)
{
  //Implement your own Authorization check
  // currentUser.Roles.HasDesiredRole
  return true;
}

Example

//Object Returned by Translator
new UserInformation {
    FirstName = "Joe", 
    LastName = "Doe", 
    Email = "joe@doe.com", 
    PhoneNumber = "408000000"
  };
<!-- Data values received by Level 2 user -->
<userinfo> 
    <firstname>Joe</firstname>
    <lastname>Doe</lastname>
    <email>joe@doe.com</email>
    <phone>408000000</phone>
</userinfo> 
<!-- Data values received by Level 3 user -->
<userinfo>
    <firstname>Joe</firstname>
    <lastname>Doe</lastname>
    <email></email>
    <phone></phone>
</userinfo>

References

Data Contract Surrogate - http://msdn.microsoft.com/en-us/library/ms733064.aspx.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Sumit Chawla
Software Developer (Senior)
United States United States
I am currently working as a Senior Software Developer. My primary skills include .NET, WPF,MSSQL,and C++. I have also worked in ASP.NET, XML, XSL, JavaScript,and Web Automation.
I love to solve problems,and love to do programming. In my idle time i love to explore new technologies and domains.

Comments and Discussions

 
QuestionHow do I apply this to MVC 4 WebApi? Pinmemberseanxd10-Jul-12 13:16 
AnswerRe: How do I apply this to MVC 4 WebApi? PinmemberSumit Chawla10-Jul-12 18:38 
QuestionDownload missing PinstaffSmitha Vijayan9-Jul-12 6:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web02 | 2.8.140827.1 | Last Updated 11 Jul 2012
Article Copyright 2012 by Sumit Chawla
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid