MessageContractを使用してOnDeserializedイベントを処理するにはどうすればよいですか?WCF:MessageContract handle OnDeserializedイベント
メッセージの受信後(ただし、メソッドを実行する前に)、データの検証と変換を行う必要があります。
DataContractの場合、宣言属性によって解決されました。
しかし、MessageContractでは機能しません。
これを行う方法はありますか?
MessageContractを使用してOnDeserializedイベントを処理するにはどうすればよいですか?WCF:MessageContract handle OnDeserializedイベント
メッセージの受信後(ただし、メソッドを実行する前に)、データの検証と変換を行う必要があります。
DataContractの場合、宣言属性によって解決されました。
しかし、MessageContractでは機能しません。
これを行う方法はありますか?
シリアル化の代わりに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();
}
}
ありがとう、Petarですが、シリアライゼーションコールバックはWCF拡張ポイントの一部です。 IOperationInvokerはそれには不向きです。私はベースのMessageContractクラス(どの論理が検証されなければならない)と、派生したMessageContractsを持ついくつかのサービスを持っています。 –
大変ありがとうございました!できます! –
MessageContractはXmlSerializerをを使用しているシリアル化コールバックを実装していません。 –