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 に答える