program tip

WCF 웹 서비스 요청의 XML SOAP 요청은 어떻게 받습니까?

radiobox 2020. 11. 10. 08:00
반응형

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.

참고URL : https://stackoverflow.com/questions/5493639/how-do-i-get-the-xml-soap-request-of-an-wcf-web-service-request

반응형