#define TRACE using System; using System.Diagnostics; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using ArchestrAServices.Common; namespace ArchestrAServices.Contract; public class ASBCustomSerializerContractBehaviorAttribute : Attribute, IContractBehavior { private Type _serializerOperationBehaviorType; private ASBCustomSerializerContractBehaviorAttribute() { } public ASBCustomSerializerContractBehaviorAttribute(Type SerializerOperationBehaviorType) { _serializerOperationBehaviorType = SerializerOperationBehaviorType; } public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { ReplaceSerializerOperationBehavior(contractDescription); } public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { ReplaceSerializerOperationBehavior(contractDescription); } public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { foreach (OperationDescription operation in contractDescription.Operations) { foreach (MessageDescription message in operation.Messages) { ValidateMessagePartDescription(message.Body.ReturnValue); foreach (MessagePartDescription part in message.Body.Parts) { ValidateMessagePartDescription(part); } foreach (MessageHeaderDescription header in message.Headers) { ValidateCustomSerializableType(header.Type); } } } } protected void ValidateMessagePartDescription(MessagePartDescription part) { if (part != null) { ValidateCustomSerializableType(part.Type); } } protected void ValidateCustomSerializableType(Type type) { Type type2 = type; if (type.IsArray) { type2 = type.GetElementType(); } if (typeof(IASBCustomSerializableType).IsAssignableFrom(type2)) { if (!type2.IsPublic) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, $"ASBCustomSerializerContractBehaviorAttribute:ValidateCustomSerializableType- Custom serialization is supported in public types only"); } if (type2.IsClass && type2.GetConstructor(new Type[0]) == null) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Warning, 0, $"ASBCustomSerializerContractBehaviorAttribute:ValidateCustomSerializableType- Custom serializable types must have a public, parameterless constructor"); } } } protected void ReplaceSerializerOperationBehavior(ContractDescription contract) { if (contract == null) { return; } if (_serializerOperationBehaviorType == null || !typeof(DataContractSerializerOperationBehavior).IsAssignableFrom(_serializerOperationBehaviorType)) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Warning, 0, "ASBCustomSerializerOperationBehavior:CreateSerializer-failed to create instance for DataContractSerializerOperationBehavior. Invalid type {0}", (_serializerOperationBehaviorType == null) ? "" : _serializerOperationBehaviorType.FullName); return; } foreach (OperationDescription operation in contract.Operations) { for (int i = 0; i < operation.Behaviors.Count; i++) { if (operation.Behaviors[i] is DataContractSerializerOperationBehavior) { SvcTrace.DiagDiagnostics.TraceEvent(TraceEventType.Information, 0, "Replacing the default serialization with ASB-Specific custom serialization"); operation.Behaviors[i] = Activator.CreateInstance(_serializerOperationBehaviorType, operation) as DataContractSerializerOperationBehavior; } } } } }