WCF 웹 서비스 요청의 XML SOAP 요청은 어떻게 받습니까?
코드 내에서이 웹 서비스를 호출하고 있는데 XML을보고 싶지만이를 노출하는 속성을 찾을 수 없습니다.
서버에서 XML을 추적하는 것이 아니라 클라이언트에서 XML을보고 싶다는 뜻이라고 생각합니다. 이 경우 귀하의 답변은 위에서 링크 한 질문과 클라이언트에서 메시지를 검사하거나 수정하는 방법에 있습니다. 그러나 해당 기사의 .NET 4 버전에는 C #이 누락되어 있고 .NET 3.5 예제에는 약간의 혼란 (버그는 아니지만)이 있으므로 여기서는 사용자의 목적에 맞게 확장되었습니다.
IClientMessageInspector를 사용하여 메시지가 나가기 전에 가로 챌 수 있습니다 .
using System.ServiceModel.Dispatcher;
public class MyMessageInspector : IClientMessageInspector
{ }
해당 인터페이스 BeforeSendRequest
및 의 메소드 AfterReceiveReply
는 요청 및 응답에 대한 액세스를 제공합니다. 인스펙터를 사용하려면 IEndpointBehavior 에 추가해야합니다 .
using System.ServiceModel.Description;
public class InspectorBehavior : IEndpointBehavior
{
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
}
기능을 사용하지 않으려면 해당 인터페이스의 다른 메서드를 빈 구현으로 남겨 둘 수 있습니다. 자세한 내용은 방법을 읽어보십시오.
클라이언트를 인스턴스화 한 후 엔드 포인트에 동작을 추가하십시오. 샘플 WCF 프로젝트의 기본 이름 사용 :
ServiceReference1.Service1Client client = new ServiceReference1.Service1Client();
client.Endpoint.Behaviors.Add(new InspectorBehavior());
client.GetData(123);
에 중단 점을 설정하십시오 MyMessageInspector.BeforeSendRequest()
. request.ToString()
XML을 표시하기 위해 오버로드됩니다.
메시지를 전혀 조작하려면 메시지 사본을 작업해야합니다. 자세한 내용 은 메시지 클래스 사용 을 참조하십시오.
이러한 링크를 찾는 다른 질문에 대한 Zach Bonham의 답변 에 감사드립니다 .
옵션 1
메시지 추적 / 로깅을 사용 합니다 .
옵션 2
항상 Fiddler 를 사용 하여 HTTP 요청 및 응답을 볼 수 있습니다 .
옵션 3
System.Net 추적을 사용하십시오 .
OperationContext.Current.RequestContext.RequestMessage
이 컨텍스트는 요청을 처리하는 동안 서버 측에 액세스 할 수 있습니다. 단방향 작업에는 작동하지 않습니다.
간단히 요청 메시지를 추적 할 수 있습니다.
OperationContext context = OperationContext.Current;
if (context != null && context.RequestContext != null)
{
Message msg = context.RequestContext.RequestMessage;
string reqXML = msg.ToString();
}
나는 Kimberly의 답변에 이것을 추가하고 싶었습니다. IEndpointBehaviour 인터페이스에 필요한 모든 메서드를 구현하지 않아서 시간을 절약하고 컴파일 오류를 방지 할 수 있습니다.
친애하는
니키
/*
// This is just to illustrate how it can be implemented on an imperative declarared binding, channel and client.
string url = "SOME WCF URL";
BasicHttpBinding wsBinding = new BasicHttpBinding();
EndpointAddress endpointAddress = new EndpointAddress(url);
ChannelFactory<ISomeService> channelFactory = new ChannelFactory<ISomeService>(wsBinding, endpointAddress);
channelFactory.Endpoint.Behaviors.Add(new InspectorBehavior());
ISomeService client = channelFactory.CreateChannel();
*/
public class InspectorBehavior : IEndpointBehavior
{
public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters)
{
// No implementation necessary
}
public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new MyMessageInspector());
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
{
// No implementation necessary
}
public void Validate(ServiceEndpoint endpoint)
{
// No implementation necessary
}
}
public class MyMessageInspector : IClientMessageInspector
{
public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
// Do something with the SOAP request
string request = request.ToString();
return null;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState)
{
// Do something with the SOAP reply
string replySoap = reply.ToString();
}
}
ASP.NET 호환성 모드에서 IIS 호스팅을 위해 아래 솔루션을 사용하고 있습니다. Rodney Viana의 MSDN 블로그에 대한 크레딧 .
appSettings 아래의 web.config에 다음을 추가하십시오.
<add key="LogPath" value="C:\\logpath" />
<add key="LogRequestResponse" value="true" />
global.asax.cs를 아래로 바꿉니다 (네임 스페이스 이름도 수정).
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Security;
using System.Web.SessionState;
using System.Text;
using System.IO;
using System.Configuration;
namespace Yournamespace
{
public class Global : System.Web.HttpApplication
{
protected static bool LogFlag;
protected static string fileNameBase;
protected static string ext = "log";
// One file name per day
protected string FileName
{
get
{
return String.Format("{0}{1}.{2}", fileNameBase, DateTime.Now.ToString("yyyy-MM-dd"), ext);
}
}
protected void Application_Start(object sender, EventArgs e)
{
LogFlag = bool.Parse(ConfigurationManager.AppSettings["LogRequestResponse"].ToString());
fileNameBase = ConfigurationManager.AppSettings["LogPath"].ToString() + @"\C5API-";
}
protected void Session_Start(object sender, EventArgs e)
{
}
protected void Application_BeginRequest(object sender, EventArgs e)
{
if (LogFlag)
{
// Creates a unique id to match Rquests with Responses
string id = String.Format("Id: {0} Uri: {1}", Guid.NewGuid(), Request.Url);
FilterSaveLog input = new FilterSaveLog(HttpContext.Current, Request.Filter, FileName, id);
Request.Filter = input;
input.SetFilter(false);
FilterSaveLog output = new FilterSaveLog(HttpContext.Current, Response.Filter, FileName, id);
output.SetFilter(true);
Response.Filter = output;
}
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
}
protected void Application_Error(object sender, EventArgs e)
{
}
protected void Session_End(object sender, EventArgs e)
{
}
protected void Application_End(object sender, EventArgs e)
{
}
}
class FilterSaveLog : Stream
{
protected static string fileNameGlobal = null;
protected string fileName = null;
protected static object writeLock = null;
protected Stream sinkStream;
protected bool inDisk;
protected bool isClosed;
protected string id;
protected bool isResponse;
protected HttpContext context;
public FilterSaveLog(HttpContext Context, Stream Sink, string FileName, string Id)
{
// One lock per file name
if (String.IsNullOrWhiteSpace(fileNameGlobal) || fileNameGlobal.ToUpper() != fileNameGlobal.ToUpper())
{
fileNameGlobal = FileName;
writeLock = new object();
}
context = Context;
fileName = FileName;
id = Id;
sinkStream = Sink;
inDisk = false;
isClosed = false;
}
public void SetFilter(bool IsResponse)
{
isResponse = IsResponse;
id = (isResponse ? "Reponse " : "Request ") + id;
//
// For Request only read the incoming stream and log it as it will not be "filtered" for a WCF request
//
if (!IsResponse)
{
AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
AppendToFile(id);
if (context.Request.InputStream.Length > 0)
{
context.Request.InputStream.Position = 0;
byte[] rawBytes = new byte[context.Request.InputStream.Length];
context.Request.InputStream.Read(rawBytes, 0, rawBytes.Length);
context.Request.InputStream.Position = 0;
AppendToFile(rawBytes);
}
else
{
AppendToFile("(no body)");
}
}
}
public void AppendToFile(string Text)
{
byte[] strArray = Encoding.UTF8.GetBytes(Text);
AppendToFile(strArray);
}
public void AppendToFile(byte[] RawBytes)
{
bool myLock = System.Threading.Monitor.TryEnter(writeLock, 100);
if (myLock)
{
try
{
using (FileStream stream = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.ReadWrite))
{
stream.Position = stream.Length;
stream.Write(RawBytes, 0, RawBytes.Length);
stream.WriteByte(13);
stream.WriteByte(10);
}
}
catch (Exception ex)
{
string str = string.Format("Unable to create log. Type: {0} Message: {1}\nStack:{2}", ex, ex.Message, ex.StackTrace);
System.Diagnostics.Debug.WriteLine(str);
System.Diagnostics.Debug.Flush();
}
finally
{
System.Threading.Monitor.Exit(writeLock);
}
}
}
public override bool CanRead
{
get { return sinkStream.CanRead; }
}
public override bool CanSeek
{
get { return sinkStream.CanSeek; }
}
public override bool CanWrite
{
get { return sinkStream.CanWrite; }
}
public override long Length
{
get
{
return sinkStream.Length;
}
}
public override long Position
{
get { return sinkStream.Position; }
set { sinkStream.Position = value; }
}
//
// For WCF this code will never be reached
//
public override int Read(byte[] buffer, int offset, int count)
{
int c = sinkStream.Read(buffer, offset, count);
return c;
}
public override long Seek(long offset, System.IO.SeekOrigin direction)
{
return sinkStream.Seek(offset, direction);
}
public override void SetLength(long length)
{
sinkStream.SetLength(length);
}
public override void Close()
{
sinkStream.Close();
isClosed = true;
}
public override void Flush()
{
sinkStream.Flush();
}
// For streamed responses (i.e. not buffered) there will be more than one Response (but the id will match the Request)
public override void Write(byte[] buffer, int offset, int count)
{
sinkStream.Write(buffer, offset, count);
AppendToFile(String.Format("at {0} --------------------------------------------", DateTime.Now));
AppendToFile(id);
AppendToFile(buffer);
}
}
}
요청 및 응답 XML이 포함 된 LogPath 폴더에 로그 파일을 만들어야합니다.
XML SOAP- custom MessageEncoder 를 보는 또 다른 방법이 있습니다 . IClientMessageInspector와의 주요 차이점은 하위 수준에서 작동하므로 잘못된 형식의 xml을 포함한 원본 바이트 콘텐츠를 캡처한다는 것입니다.
이 접근 방식을 사용하여 추적을 구현하려면 사용자 지정 메시지 인코더 를 새 바인딩 요소 로 사용 하여 표준 textMessageEncoding 을 래핑하고 해당 사용자 지정 바인딩을 config의 끝점에 적용해야합니다 .
Also you can see as example how I did it in my project - wrapping textMessageEncoding, logging encoder, custom binding element and config.
'program tip' 카테고리의 다른 글
대화 용 소프트 키보드 표시 (0) | 2020.11.10 |
---|---|
Android 개발을 위해 Eclipse에서 IntelliJ IDEA로 전환 할 때의 이점 (0) | 2020.11.10 |
CSS Calc 대안 (0) | 2020.11.10 |
Tomcat 클래스 경로에 디렉토리 추가 (0) | 2020.11.10 |
`NSManagedObject`가 삭제되었는지 어떻게 알 수 있습니까? (0) | 2020.11.10 |