如何使用MessageContract处理OnDeserialized事件?
接收消息后(但在执行方法之前)需要进行一些数据验证和转换。
对于DataContract,它由声明属性解决。
但是对于MessageContract它不起作用。
有没有办法做到这一点?
答案 0 :(得分:2)
您最好使用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;
}
}
加入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();
}
}