WCF:MessageContract 处理 OnDeserialized 事件

标签 wcf xml-deserialization messagecontract

如何使用 MessageContract 处理 OnDeserialized 事件?

收到消息后(但在执行方法之前)需要做一些数据验证和转换。

对于DataContract,它是通过声明属性解决的。

但是对于 MessageContract 来说它不起作用。

有什么办法可以做到这一点吗?

最佳答案

您最好使用 WCF extension points而不是序列化。特别是 IOperationInvoker。

编辑

示例:

下面的服务和消息定义。请注意新的 MyValidationBeforeInvokeBehavior 属性。

[ServiceContract]
    public interface IService1
    {

        [OperationContract]
        string GetData(int value);

        [OperationContract]
        [MyValidationBeforeInvokeBehavior]
        AddPatientRecordResponse AddPatientRecord(PatientRecord composite);
    }

    [MessageContract(IsWrapped = false, ProtectionLevel = ProtectionLevel.None)]
    public class AddPatientRecordResponse
    {
        [MessageHeader(ProtectionLevel = ProtectionLevel.None)]
        public Guid recordID;
        [MessageHeader(ProtectionLevel = ProtectionLevel.None)]
        public string patientName;
        [MessageBodyMember(ProtectionLevel = ProtectionLevel.None)]
        public string status;

    }


    [MessageContract(IsWrapped = false, ProtectionLevel = ProtectionLevel.None)]
    public class PatientRecord
    {
        [MessageHeader(ProtectionLevel = ProtectionLevel.None)]
        public Guid recordID;
        [MessageHeader(ProtectionLevel = ProtectionLevel.None)]
        public string patientName;

        //[MessageHeader(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
        [MessageHeader(ProtectionLevel = ProtectionLevel.None)]
        public string SSN;
        [MessageBodyMember(ProtectionLevel = ProtectionLevel.None)]
        public string comments;
        [MessageBodyMember(ProtectionLevel = ProtectionLevel.None)]
        public string diagnosis;
        [MessageBodyMember(ProtectionLevel = ProtectionLevel.None)]
        public string medicalHistory;
    }

public class Service1 : IService1
    {
        public string GetData(int value)
        {
            return string.Format("You entered: {0}", value);
        }

        public AddPatientRecordResponse AddPatientRecord(PatientRecord patient)
        {
            var response = new AddPatientRecordResponse
                               {
                                   patientName = patient.patientName, 
                                   recordID = patient.recordID, 
                                   status = "Sucess"
                               };

            return response;
        }
    }

Hook wcf 扩展性

public class MyValidationBeforeInvokeBehavior : Attribute, IOperationBehavior
    {
        public void Validate(OperationDescription operationDescription)
        {
        }

        public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
        {
            dispatchOperation.Invoker = new MyValidationBeforeInvoke(dispatchOperation.Invoker);
        }

        public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
        {
        }

        public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
        {
        }
    }

自定义操作调用程序:

public class MyValidationBeforeInvoke : IOperationInvoker
    {
        private readonly IOperationInvoker _original;

        public MyValidationBeforeInvoke(IOperationInvoker original)
        {
            _original = original;
        }

        public object[] AllocateInputs()
        {
            return _original.AllocateInputs();
        }

        public object Invoke(object instance, object[] inputs, out object[] outputs)
        {

            var validator = new ValidatePatientRecord((PatientRecord) inputs[0]);
            if (validator.IsValid())
            {
                var ret = _original.Invoke(instance, inputs, out outputs);
                return ret;
            }
            else
            {
                outputs = new object[] {};

                var patientRecord = (PatientRecord) inputs[0];

                var returnMessage = new AddPatientRecordResponse
                                        {
                                            patientName = patientRecord.patientName,
                                            recordID = patientRecord.recordID,
                                            status = "Validation Failed"
                                        };
                return returnMessage;    
            }


        }

        public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
        {
           return _original.InvokeBegin(instance, inputs, callback, state);
        }

        public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
        {
            return _original.InvokeEnd(instance, out outputs, result);
        }

        public bool IsSynchronous
        {
            get { return _original.IsSynchronous; }
        }
    }

本质是我们永远不会调用服务调用,因为由于验证错误它永远不会到达那里。我们还可以将发生的情况返回给客户端。

验证类和客户端调用(用于完成):

public class ValidatePatientRecord
    {
        private readonly PatientRecord _patientRecord;

        public ValidatePatientRecord(PatientRecord patientRecord)
        {
            _patientRecord = patientRecord;
        }

        public bool IsValid()
        {
            return _patientRecord.patientName != "Stack Overflow";
        }
    }

客户:

class Program
    {
        static void Main(string[] args)
        {
            var patient = new PatientRecord { SSN = "123", recordID = Guid.NewGuid(), patientName = "Stack Overflow" };

            var proxy = new ServiceReference1.Service1Client();

            var result = proxy.AddPatientRecord(patient);

            Console.WriteLine(result.status);
            Console.ReadLine();
        }
    }

关于WCF:MessageContract 处理 OnDeserialized 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10562751/

相关文章:

c# - 新添加成员后反序列化类时出现问题

java - 变量类型更改时的 XStream 反序列化

C# XML反序列化错误(2,2)

message - 服务总线的消息契约版本如何?

c# - 在 WCF 的其他契约(Contract)中将 MessageContract 作为 MessageBodyMember

c# - 如何生成 24 小时后过期的唯一 token ?

javascript - 在 Javascript 中使用 AES 加密文本,然后在 C# WCF 服务中解密

c# - WCF 测试客户端打破一个字符串值,然后再次将两个部分连接在一起

c# - 如何使用反序列化使用 C# 类读取 xml 属性

c# - 如何将 XML 文件转换为 MessageContract 类的实例?