2

如何使用 MessageContract 处理 OnDeserialized 事件?

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

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

但是对于 MessageContract 它不起作用。

有没有办法做到这一点?

4

1 回答 1

2

您最好使用WCF 扩展点而不是序列化。特别是 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;
        }
    }

挂钩 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();
        }
    }
于 2012-05-12T19:50:07.553 回答