2012-05-12 8 views
2

MessageContractを使用してOnDeserializedイベントを処理するにはどうすればよいですか?WCF:MessageContract handle OnDeserializedイベント

メッセージの受信後(ただし、メソッドを実行する前に)、データの検証と変換を行う必要があります。

DataContractの場合、宣言属性によって解決されました。

しかし、MessageContractでは機能しません。

これを行う方法はありますか?

+0

MessageContractはXmlSerializerをを使用しているシリアル化コールバックを実装していません。 –

答えて

2

シリアル化の代わりにWCF extension pointsを使用する方がよいでしょう。特にIOperationInvoker。

EDIT

例:以下

サービスおよびメッセージの定義。新しい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(); 
     } 
    } 
+0

ありがとう、Petarですが、シリアライゼーションコールバックはWCF拡張ポイントの一部です。 IOperationInvokerはそれには不向きです。私はベースのMessageContractクラス(どの論理が検証されなければならない)と、派生したMessageContractsを持ついくつかのサービスを持っています。 –

+0

大変ありがとうございました!できます! –

関連する問題