IClientMessageInspectorとそのメソッドBeforeSendRequestを使用して、要求メッセージを検査します。重要なのは、一部の要求メッセージにはメンバーがあり、そのメンバーはオブジェクト型です(実際のシナリオでは、KnownType属性で指定された文字列またはその他の値の例があります)。
[DataContract(Namespace = "")]
[KnownType(typeof(SomeValueDTO))]
public class CenDTO
{
[DataMember]
public string Uri { get; set; }
[DataMember]
public object Value { get; set; }
}
このプロジェクトでは、名前空間がどこにも定義されていないことに注意してください。そのため、「BeforeSendRequest」で例外が発生しました。そして、このインターフェースは実際のサービスと同じDataContractSerializerを使用していないように見えます。これには、そのようなシリアル化エラーやそのようなsmthはありません。エラー:
The empty string '' is not a valid name.
at System.Xml.XmlTextWriter.LookupPrefix(String ns)
at System.Xml.XmlDictionaryWriter.XmlWrappedWriter.LookupPrefix(String namespaceUri)
at System.Xml.XmlDictionaryWriter.XmlWrappedWriter.WriteXmlnsAttribute(String prefix, String namespaceUri)
at System.Xml.XmlDictionaryWriter.WriteXmlnsAttribute(String prefix, XmlDictionaryString namespaceUri)
at System.Runtime.Serialization.XmlWriterDelegator.WriteXmlnsAttribute(XmlDictionaryString ns)
at System.Runtime.Serialization.XmlWriterDelegator.WriteAttributeQualifiedName(String attrPrefix, XmlDictionaryString attrName, XmlDictionaryString attrNs, XmlDictionaryString name, XmlDictionaryString ns)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteTypeInfo(XmlWriterDelegator writer, XmlDictionaryString dataContractName, XmlDictionaryString dataContractNamespace)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteTypeInfo(XmlWriterDelegator writer, DataContract contract, DataContract declaredContract)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithXsiType(XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle objectTypeHandle, Type objectType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle, Type declaredType)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.InternalSerialize(XmlWriterDelegator xmlWriter, Object obj, Boolean isDeclaredType, Boolean writeXsiType, Int32 declaredTypeID, RuntimeTypeHandle declaredTypeHandle)
at WriteCenDTOToXml(XmlWriterDelegator , Object , XmlObjectSerializerWriteContext , ClassDataContract )
at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph, DataContractResolver dataContractResolver)
at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameterPart(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameter(XmlDictionaryWriter writer, PartInfo part, Object graph)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeParameters(XmlDictionaryWriter writer, PartInfo[] parts, Object[] parameters)
at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.SerializeBody(XmlDictionaryWriter writer, MessageVersion version, String action, MessageDescription messageDescription, Object returnValue, Object[] parameters, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.SerializeBodyContents(XmlDictionaryWriter writer, MessageVersion version, Object[] parameters, Object returnValue, Boolean isRequest)
at System.ServiceModel.Dispatcher.OperationFormatter.OperationFormatterMessage.OperationFormatterBodyWriter.OnWriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriter.WriteBodyContents(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.BodyWriterMessage.OnBodyToString(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.ToString(XmlDictionaryWriter writer)
at System.ServiceModel.Channels.Message.ToString()
at CID.TopicAnalyst.CIA.Test.Utils.MessageInspector.BeforeSendRequest(Message& request, IClientChannel channel) in D:\git\...\MessageInspector.cs:line 25
at System.ServiceModel.Dispatcher.ImmutableClientRuntime.BeforeSendRequest(ProxyRpc& rpc)
「BeforeSendRequest」の実装(クラッシュは.ToString()で発生します):
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
if(request.Headers.Count > 0)
{
request.Headers.RemoveAt(0);
}
MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);
request = buffer.CreateMessage();
var message = buffer.CreateMessage().ToString();
var resultFile = ConfigurationManager.AppSettings.GetValues("requestFile").First();
_serializer.Write(resultFile, message);
return null;
}
テスト自体は、サービスの参照を使用する別個のソリューションです。サービスの実装では、操作は次のようになります。
[ServiceContract]
public interface ISoapService
{
[OperationContract]
SomeListResponseMessage GetSomeList(SomeListRequestMessage request);
}
[MessageContract]
public class SomeListRequestMessage : BaseRequestMessage
{
...
[MessageBodyMember]
public CenDTO Cen { get; set; }
...
}
[DataContract(Namespace = "")]
[KnownType(typeof(SemValueDTO))]
public class CenDTO
{
...
[DataMember]
public object Value { get; set; }
}
テストソリューションのいくつかのコード:
static class Program
{
static void Main(string[] args)
{
while(true)
{
var client = new SoapServiceClient("BasicHttpBinding_ISoapService");
client.Endpoint.Behaviors.Add(new InspectorBehavior());
var soapService = client.ChannelFactory.CreateChannel();
var co = new CooRequestCreator(soapService);
co.CreateAndWriteRequests();
Console.WriteLine("Press y to repeat");
var str = Console.ReadLine();
if(str != "y") break;
}
}
サービスを呼び出す前に要求メッセージを作成します。
class CooRequestCreator : BaseRequestCreator<SomeListRequestMessage>
{
SemValueDTO _semaValue = new SemValueDTO
{
Key = "fb",
Label = "Guild",
Type = "org"
};
public CooRequestCreator(ISoapService soapService) : base(soapService)
{
}
protected override SomeListRequestMessage CreateMinRequest()
{
return new SomeListRequestMessage
{
Cen =
new CenDTO
{
Value = _semaValue,
},
MaxCount = 5
};
}
たぶん誰かが同じ経験をしてそれを手伝うことができますか?