问题
I'm calling an external HTTPS webservice.
In order to check what is wrong, the owner needs the SOAP request I'm sending.
I have a web reference and the generated proxy class generated by VS 2008...
Is there a way to see the SOAP message just before sending it?
I'm thinking in some .net code... because the Sniffers I tried didn't "see" the webservice invocation don't know why.
回答1:
What you need is a SoapExtension. There's quite a few good examples here:
How do I get access to SOAP response
Getting RAW Soap Data from a Web Reference Client running in ASP.net
XML Parse error while processing the SOAP response
One of the articles linked to: http://msdn.microsoft.com/en-us/magazine/cc164007.aspx
Also search SO for: https://stackoverflow.com/search?q=SoapExtension
回答2:
You can simply serialize the request object, before subtmit, like this:
var sreq = new SomeSoapRequest();
// ... fill in here ...
var serxml = new System.Xml.Serialization.XmlSerializer(sreq.GetType());
var ms = new MemoryStream();
serxml.Serialize(ms, sreq);
string xml = Encoding.UTF8.GetString(ms.ToArray());
// in xml string you have SOAP request
回答3:
You can use IClientMEssageInspector and IEndpointBehavior to fullfill this. I found using this way can capture the exact soap request likely as the fiddler one:
Create a class like this in the same project:
public class ClientMessageInspector : System.ServiceModel.Dispatcher.IClientMessageInspector
{
#region IClientMessageInspector Members
public string LastRequestXml { get; private set; }
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel)
{
string requestHeaderName = request.Headers.Action.Replace("urn:#",string.Empty);
LastRequestXml = request.ToString();
string serializedRequestFile = string.Format(requestHeaderName + "_request_{0}.xml", DateTime.Now.ToString("yyyyMMddHHmmss"));
string exportedFolder = ConfigurationManager.AppSettings["SubmittedRequestXmLocation"];
printSoapRequest(request, exportedFolder, serializedRequestFile);
return request;
}
public void printSoapRequest(System.ServiceModel.Channels.Message request, string exportedFolder, string fileName)
{
if (exportedFolder.Equals(string.Empty))
return;
if (!Directory.Exists(exportedFolder))
{
Directory.CreateDirectory(exportedFolder);
}
string exportedFile = string.Format("{0}\\{1}", exportedFolder, fileName);
if (File.Exists(exportedFile))
{
File.Delete(exportedFile);
}
string strRequestXML = request.ToString();
XDocument xDoc = XDocument.Parse(strRequestXML);
XmlWriter xw = XmlWriter.Create(exportedFile);
xDoc.Save(xw);
xw.Flush();
xw.Close();
LogOutput("Request file exported: " + exportedFile);
}
}
public class CustomInspectorBehavior : IEndpointBehavior
{
private readonly ClientMessageInspector clientMessageInspector = new ClientMessageInspector();
public string LastRequestXml
{
get { return clientMessageInspector.LastRequestXml; }
}
public string LastResponseXml
{
get { return clientMessageInspector.LastRequestXml; }
}
public void AddBindingParameters(
ServiceEndpoint endpoint,
System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
}
public void Validate(ServiceEndpoint endpoint)
{
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(clientMessageInspector);
}
}
Then you can call it like the following:
ProxyClass _class = new ProxyClass();
var requestInterceptor = new CustomInspectorBehavior();
_client.Endpoint.Behaviors.Add(requestInterceptor);
When you call the service method, it will automatically execute the interceptor and print the output. Using this way you can also manipulate the soap message before sending to the server!
回答4:
If you work in a more restricted environment and don't have the luxury of using an application like Fiddler, you can do the following:
- Generate your web reference as usual.
- Write code to perform whatever web method call you're going to me.
- Create a new ASP .NET project of your choice, I went with MVC 4.
- Create a handler or controller/action, and extract the request stream like this:
using (var reader = new System.IO.StreamReader(Request.InputStream))
{
result = reader.ReadToEnd();
}
- Put a breakpoint on it and run it in debug mode.
- On your client, set the Url of the SOAP request to your new controller/handler.
- Run your client. You should catch the breakpoint on your web app with your SOAP message.
It's not an ideal or pretty solution, but if you are working in a moderately restricted environment, it gets the job done.
来源:https://stackoverflow.com/questions/461744/get-soap-message-before-sending-it-to-the-webservice-in-net