|
using System;
using System.CodeDom;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
namespace DataContractExtensions
{
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ConditionalDataBehavior : Attribute, IServiceBehavior
{
#region Implementation of IServiceBehavior
private static void ApplyDataContractSurrogate(OperationDescription description)
{
var dcsOperationBehavior = description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null) {
dcsOperationBehavior.DataContractSurrogate = new ConditionalDataContractSurrogate(dcsOperationBehavior.DataContractSurrogate);
}
}
/// <summary>
/// Provides the ability to inspect the service host and the service description to confirm that the service can run successfully.
/// </summary>
/// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The service host that is currently being constructed.</param>
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
}
/// <summary>
/// Provides the ability to pass custom data to binding elements to support the contract implementation.
/// </summary>
/// <param name="serviceDescription">The service description of the service.</param><param name="serviceHostBase">The host of the service.</param><param name="endpoints">The service endpoints.</param><param name="bindingParameters">Custom objects to which binding elements have access.</param>
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
{
}
/// <summary>
/// Provides the ability to change run-time property values or insert custom extension objects such as error handlers, message or parameter interceptors, security extensions, and other custom extension objects.
/// </summary>
/// <param name="serviceDescription">The service description.</param><param name="serviceHostBase">The host that is currently being built.</param>
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ServiceEndpoint ep in serviceHostBase.Description.Endpoints) {
foreach (OperationDescription od in ep.Contract.Operations) {
ApplyDataContractSurrogate(od);
}
}
}
#endregion
}
/// <summary>
/// Attribute to mark a datamember as being conditional. The datamember will be flushed only if the invoker has
/// permissions to obtain the data
/// </summary>
[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class ConditionalDataMemberAttribute : Attribute
{
public string Role { get; set; }
}
/// <summary>
/// DataContractSurrogate class which implements the default DataContract Serialization behavior
/// </summary>
public class ConditionalDataContractSurrogate : IDataContractSurrogate
{
private readonly IDataContractSurrogate _baseSerializer;
public ConditionalDataContractSurrogate(IDataContractSurrogate baseSerializer)
{
_baseSerializer = baseSerializer;
}
public Type GetDataContractType(Type type)
{
return _baseSerializer != null ? _baseSerializer.GetDataContractType(type) : type;
}
private bool IsAuthorized(string role)
{
//Implement your own Authorization check
// currentUser.Roles.HasDesiredRole
return true;
}
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;
prop.GetSetMethod().Invoke(obj,
new[] { proptype.IsValueType ? Activator.CreateInstance(proptype) : null });
}
}
} catch { }
});
return _baseSerializer != null ? _baseSerializer.GetObjectToSerialize(obj, targetType) : obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
return _baseSerializer != null ? _baseSerializer.GetDeserializedObject(obj, targetType) : obj;
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
return _baseSerializer != null ? _baseSerializer.GetCustomDataToExport(memberInfo, dataContractType) : null;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
return _baseSerializer != null ? _baseSerializer.GetCustomDataToExport(clrType, dataContractType) : null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
if (_baseSerializer != null) _baseSerializer.GetKnownCustomDataTypes(customDataTypes);
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return _baseSerializer != null ? _baseSerializer.GetReferencedTypeOnImport(typeName, typeNamespace, customData) : null;
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
return _baseSerializer != null ? _baseSerializer.ProcessImportedType(typeDeclaration, compileUnit) : typeDeclaration;
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
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.