2010-01-25 1 views
5

으로 와이어에 이동 -얻기 따옴표 "

짧은 버전 (경고 XML 아래 불필요한 문자 인코딩의 신성 혼합물.) : 왜 내가 얻을 수없는 내 서비스 참조 호출 (C#을 , .net 3.5, VS2008에 추가 된 automagic 서비스 참조 코드)이 와이어와 같은 모양의 매개 변수를 올바르게 인코딩하려면 다음과 같이하십시오. 비트를 찾습니다. 내 비트입니다 ...

(기타 명확성을 위해 soap-y 비트 삭제)

<SOAP-ENV:Body><SOAPSDK4:SetCondition xmlns:SOAPSDK4="http://tempuri.org/message/"> 
<sharedSecret>buggerall</sharedSecret> 

<xmlData>&lt;SEARCHINFO_LIST&gt;&lt;SEARCH_INFO action=&quot;add&quot; status=& 
quot;3&quot; name=&quot;TestProfile2&quot; mask=&quot;0&quot; campaign_id=&quot;33&quot; 
campaign_protected=&quot;N&quot; condition_protected=&quot;N&quot;&gt;&lt;CONDITIONS/& 
gt;&lt;EXPRESSIONS/&gt;&lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt;</xmlData> 
</SOAPSDK4:SetCondition></SOAP-ENV:Body> 

매개 변수를 설정하고 전화를 걸면 "NO SOU SOAP for YOU!"라는 멋진 메시지가 반환됩니다.

action=\"add\" 

와이어 날이 준 (피들러를 통해) : action="add"

action=&quot;add&quot; 

했다

은 내 통과 - 투 - 웹 서비스 매개 변수 문자열에서 여러 가지 다른 형식을 시도 나 wire on this : action=&amp;quot;add&amp;quot;

그리고 다양한 조합 (action = ""add ""?!)과 html.encode, url.encode가 거의 비슷하다. 폭탄을 투하하거나 전선에 큰 따옴표로 표시했습니다.

아, 나는 심지어 주위에 <![CDATA[&quot;]]을 시도했습니다. 그것도 작동하지 않았다.

soap 메시지의 innerHtml 비트에 큰 따옴표 인코딩을 강제 적용하는 방법이 있습니까?

* (즉, 서비스를 원하는 방법 때문에 질문을하지 않는 이들은 당신이 찾고있는 드로이드 수 없습니다..)

* * * 길고 고통스러운 버전 :

현재 (winform) 관리 GUI 응용 프로그램에서 처리하는 절차를 자동화하는 앱을 작성하고 있습니다. (실제로는 의 mmc 스냅인입니다.)

작업을 수행하기 위해 winform 앱은 표준 웹 서비스 호출을 통해 서버와 통신합니다.

VS2008의 멋진 "웹 서비스 참조"자동 생성자 인 (기술적 인 설명)을 사용하고 있으며 웹 서비스 에 성공적으로 인증되었습니다. 내가 올바르게 작업하고 있는지 확인하기 위해 GUI 응용 프로그램에서 호출을 캡처 한 다음 해당 번호를 와이어와 비교했습니다. 모두 좋았어요. 그런 다음 나는 앰퍼샌드의 악으로 빠져 들었다. 이

<?xml version="1.0" encoding="UTF-8" standalone="no"?><SOAP-ENV:Envelope 
xmlns:SOAPSDK1="http://www.w3.org/2001/XMLSchema" xmlns:SOAPSDK2=" 
http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAPSDK3=" 
http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV=" 
http://schemas.xmlsoap.org/soap/envelope/"><SOAP-ENV:Body><SOAPSDK4:SetCondition 
xmlns:SOAPSDK4="http://tempuri.org/message/"><sharedSecret>0500001007C3525F3-F315-460D- 
AF5C-D84767130126094</sharedSecret><xmlData>&lt;SEARCHINFO_LIST&gt;&lt;SEARCH_INFO 
action=&quot;add&quot; status=&quot;3&quot; name=&quot;TestProfile2&quot; mask=& 
quot;0&quot; campaign_id=&quot;33&quot;campaign_protected=&quot;N&quot; 
condition_protected=&quot;N&quot;&gt;&lt;CONDITIONS/&gt;&lt;EXPRESSIONS/&gt;& 
lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt;</xmlData></SOAPSDK4:SetCondition></SOAP- 
ENV:Body></SOAP-ENV:Envelope> 
(내가 피들러를 통해이를 보내는 응용 프로그램을 캡처) : (더 제대로, 일을 제대로 인코딩하는 얻는 방법을 ) 통화 중 하나를 들어

, 웹 서비스는이 같은 것을 볼 것으로 예상

관련 비트를 표시하기 위해 모든 추가 SOAP-y 항목을 제거합니다.이 부분은 전달 된 <xmlData> 섹션입니다. &quot; 주변의 매개 변수를 주목하라 :

var serviceParams = "<SEARCHINFO-LIST><SEARCH_INFO action=\"add\" 
status=\"3\" name=\"TestProfileFromExternApp\" mask=\"0\" campaign_id=\"33\" 
campaign_protected=\"N\" 
condition_protected=\"N\"><CONDITIONS/><EXPRESSIONS/></SEARCH_INFO></SEARCHINFO_LIST>"; 

내 앱이 와이어에 그것을 발송, 바이올린 켜는 사람이 캡처 : 내 코드에서

&lt;SEARCHINFO_LIST&gt;&lt;SEARCH_INFO action=&quot;add&quot; 
status=&quot;3&quot; name=&quot;TestProfile2&quot; mask=&quot;0&quot; 
campaign_id=&quot;33&quot; campaign_protected=&quot;N&quot; 
condition_protected=&quot;N&quot;&gt;&lt;CONDITIONS/&gt;&lt;EXPRESSIONS/&gt;& 
lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt; 

를, 그래서처럼 내장 문자열을 (다시 , 는)

&lt;SEARCHINFO-LIST&gt;&lt;SEARCH_INFO action="add" status="3" 
name="TestProfileFromExternApp" mask="0" campaign_id="33" 
campaign_protected="N" condition_protected="N"&gt;&lt;CONDITIONS/&gt; 
&lt;EXPRESSIONS/&gt;&lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt; 

을 모든 SOAP 물건을 제거 및 수신 서비스는 그것을 좋아하지 않는 오류를 다시 보냅니다. 그것은 &quot;을 원합니다.

꺾쇠 괄호는 올바르게 인코딩되지만 인용 부호는 HTTP 문자열에서 유효하며 인코딩되지 않습니다.

"Ah-ha!" "나는 단지 수동으로 인코딩 할 것입니다!"라고 말합니다. (피들러를 통해 다시)로 발송 내 모든 앰퍼샌드합니다 ( &quot;에서) 한

var serviceParams = "<SEARCHINFO-LIST><SEARCH_INFO action=&quot;add&quot; 
status=&quot;3&quot; name=&quot;TestProfileFromExternApp&quot; 
mask=&quot;0&quot; campaign_id=&quot;33&quot; 
campaign_protected=&quot;N&quot; 
condition_protected=&quot;N&quot;><CONDITIONS/><EXPRESSIONS/></SEARCH_INFO></SEARCHINFO_LIST>"; 

지금처럼 &amp;quot;로 변환됩니다 :

&lt;SEARCHINFO-LIST&gt;&lt;SEARCH_INFO action=&amp;quot;add&amp;quot; 
status=&amp;quot;3&amp;quot; 
name=&amp;quot;TestProfileFromExternApp&amp;quot; mask=&amp;quot;0&amp;quot; 
campaign_id=&amp;quot;33&amp;quot; campaign_protected=&amp;quot;N&amp;quot; 
condition_protected=&amp;quot;N&amp;quot;&gt;&lt;CONDITIONS/&gt;&lt;EXPRESSIONS/&gt;&lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt; 
나는 같은 것을 할 에 시도

짐작할 수 있듯이 수신 웹 서비스가 "BZZT! 재생 해 주셔서 감사합니다!"로 돌아 왔습니다.

비슷한 결과를 내고 모든 종류의 이스케이프 및 인코딩 시퀀스를 시도했습니다. 효과적으로 조작 한 후에 HttpUtility.HtmlEncode 오른쪽과 같은 코드를 사용하고, 문자열에있는 앰퍼샌드를 &amp;으로 변환합니다. 따옴표 (single 또는 double)는 변환시 무시됩니다. 그리고 수신 웹 서비스 &quot;로 표현되는 그 따옴표를으로 나타내거나 으로 가고 싶어합니다.

내 마지막 절망적 인 희망 ...는 BeforeSendRequest 이벤트 IClientMessageInspector to implement message inspection를 사용하여 와이어에 가기 전에 (생각) 메시지 권리를 잡으려고했고 수동으로는 와이어에 가기 전에 그 일을 설정합니다.

메시지를 잘 캡처합니다. 심지어 수동으로 넣을 수 &quot;.

wireshark와 fiddler가 모두 전송되면 멋지게 형식이 지정됩니다. 따옴표를 사용하면 필사적으로 제거하려고합니다.

<xmlData xsi:type="xsd:string" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
&lt;SEARCHINFO-LIST&gt;&lt;SEARCH_INFO action="add" status="3" 
name="TestProfileFromExternApp" mask="0" campaign_id="33" campaign_protected="N" 
condition_protected="N"&gt;&lt;CONDITIONS/&gt;&lt;EXPRESSIONS/&gt; 
&lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt;</xmlData> 

나는 현명하다. 나는 [작은 귀여워서][신성한] 또는 내 [영혼/심장/아들의 bionacle collection]을 바꿔서 희생시키는 것을 포함한 모든 제안을 받아 들일 것입니다. 저를 믿으십시오, 그것은 더 나쁜 것이 아닙니다.

public int SetCondition(string sharedSecret, string xmlData, out string resultValue) 
{ 
    tzGui.tzCampaign.SetConditionRequest inValue = new tzGui.tzCampaign.SetConditionRequest(); 
    inValue.sharedSecret = sharedSecret; 
    inValue.xmlData = xmlData; 
    tzGui.tzCampaign.SetConditionResponse retVal = ((tzGui.tzCampaign.CampaignSoapPort)(this)).SetCondition(inValue); 
    resultValue = retVal.resultValue; 
    return retVal.Result; 
} 

(이것은 당신이 ... 요구 한 것입니다 내가 생각 ) 그리고 여기가 호출 점점 방법은 다음과 같습니다 :

아래의 요청에 따라

, 여기에 생성 된 메시지 스텁의

void SetConditionTask() 
{ 
    //ok, now we *try* and create a new profile 
    var tzCampaignCxn = new tzCampaign.CampaignSoapPortClient("CampaignSoapBinding"); 
    //no worky 
    //string xmlData = "<SEARCHINFO-LIST><SEARCH_INFO action=\"add\" status=\"3\" name=\"TestProfileFromExternApp\" mask=\"0\" campaign_id=\"33\" campaign_protected=\"N\" condition_protected=\"N\"><CONDITIONS/><EXPRESSIONS/></SEARCH_INFO></SEARCHINFO_LIST>"; 

    //this one doesn't work 
    //string xmlData = "<SEARCHINFO-LIST><SEARCH_INFO action=<![CDATA[ &quot; ]]>add<![CDATA[ &quot; ]]> status=<![CDATA[ &quot; ]]>3<![CDATA[ &quot; ]]> name=<![CDATA[ &quot; ]]>TestProfileFromExternApp<![CDATA[ &quot; ]]> mask=<![CDATA[ &quot; ]]>0<![CDATA[ &quot; ]]> campaign_id=<![CDATA[ &quot; ]]>33<![CDATA[ &quot; ]]> campaign_protected=<![CDATA[ &quot; ]]>N<![CDATA[ &quot; ]]> condition_protected=<![CDATA[ &quot; ]]>N<![CDATA[ &quot; ]]>><CONDITIONS/><EXPRESSIONS/></SEARCH_INFO></SEARCHINFO_LIST>"; 

    //this one doesn't either 
    string xmlData = "<SEARCHINFO-LIST><SEARCH_INFO action=&quot;add&quot; status=&quot;3&quot; name=&quot;TestProfileFromExternApp&quot; mask=&quot;0&quot; campaign_id=&quot;33&quot; campaign_protected=&quot;N&quot; condition_protected=&quot;N&quot;><CONDITIONS/><EXPRESSIONS/></SEARCH_INFO></SEARCHINFO_LIST>"; 

    string createProfileResultVal = string.Empty; 
    tzCampaignCxn.SetCondition(SharedSecret, xmlData, out createProfileResultVal); 
    txtResults.AppendText(Environment.NewLine + Environment.NewLine + createProfileResultVal); 
    } 
+1

문제는 ' ...'입니다.'은 완벽하게 유효한 XML입니다. XML 텍스트 노드에서는 큰 따옴표를 이스케이프 할 필요가 없습니다. 웹 서비스가 표준 XML을 사용하지 않는다면이 표준 XML을 사용하지 마십시오. – dtb

+0

당신은 절대적으로 옳습니다. 그들은 완벽하게 유효합니다. 하지만 내게는 "을 연결하는 방법이 있어야합니다 ... 맞습니까? (아, 그리고 불행히도 그것은 내 웹 서비스가 아닙니다 ... 오, 그렇다면 ...!) :) –

+0

방법이 있습니다. 당신은 WCF의 모든면을 엉망으로 만들 수 있고 자신 만의 구현으로 부품을 대체 할 수 있습니다 ... 생성 된 메소드 선언을 어떻게 표시 할 수 있습니까? 나는 간단한 해결책에 대한 아이디어가 있지만 확인을해야합니다. – dtb

답변

0

SOAP 메시지에 해당 문자열을 CDATA 섹션으로 가져와서 원하는대로 정확하게 포맷 할 수 있어야하며 WCF가이를 만지지 않도록해야합니다.

현재 문제는 서비스가 xml과 html 사이의 인코딩을 기대하기 때문에 - 따라서 Soap 포맷터가 사용하는 형식으로 제대로 처리되지 않으므로 항상 이스케이프 처리해야합니다. 따옴표.

나는 당신이 당신의 문자열 매개 변수에서 CDATA 태그 <![CDATA[*yourstring*]]>에서 그것을 둘러싸고있는 경우 그이 있다면, 그것을위한 마크 업 와이어를 통해 탈출 &lt;![[*yourstring-XML-element-encoded*]]&gt;

등의 다른 쪽 끝을 도달 할 것이라고하지만, 직감을 가지고 예를 들어, VS 서비스 참조 생성기에 의해 자동으로 생성 된 코드를 변경하여 프록시에서 메서드 호출의 매개 변수 형식이 인 형식을 기본적으로 문자열과 동일하게 받아들이지만 자체적으로 직렬화합니다. CDATA 섹션으로. 이러한 유형은 Marc Gravell이 another question here에 응답하는 코드를 기반으로 제공됩니다. 이 문제는 누군가가 해당 서비스 참조에서 VS의 '참조 업데이트'명령을 사용하면 변경 한 사항을 모두 잃게됩니다.

그렇기 때문에 svcutil 명령 줄 유틸리티를 사용하여 참조를 생성하십시오 (VS는이 도구를 사용하지 않습니다 - 더 유연하기 때문에 수치 스럽습니다). 프로젝트를 수동으로 수행하고 '서비스 참조'를 제거하십시오. 그렇게하면 코드를 해킹 할 수 있지만 VS의 프로젝트 트리에서 코드를 쉽게 볼 수 있습니다.

+0

나는 전체 문자열을 의미했습니다. 그냥 따옴표 주위에 -하지만 어느 쪽이든 내가 생각하는대로, 그것은 여전히 ​​문자를 서식 지정 중입니다. 어떤 경우에는 내가 연결된 다른 예제에서 CDataWrapper 클래스를 사용하여 시도 할 수 있습니다. 명시 적으로 IXmlSerializable을 구현하여 문자열을 다음과 같이 보내도록 할 수 있습니다. CDATA - 이렇게하면 해당 매개 변수의 데이터에 대한 기본 WCF 메시지 서식을 모두 막을 수 있습니다. e WCF 포맷터는 CDataWrapper 클래스와 같으며 문자열이 아닙니다. 따라서 생성 된 프록시 코드를 변경할 필요가 있습니다. –

+0

음 ... 이제는 내가 원하는 것처럼 보입니다. 나는 그것을 시도해 보겠다. –

+0

문자열 xmlData에 대한 모든 참조를 CDataWrapper로 변경하려고 시도했지만 다음과 같이 보였다. 그러나 { " 'xmlData'를 반영하는 동안 오류가 발생했습니다.}} " tzGui.CDataWrapper 유형은 SOAP로 인코딩 된 메시지로 직렬화 할 수 없습니다. 메시지 용도로 리터럴로 설정하십시오. " Campaign.WSDL에서 use = literal = encoded로 변경했습니다. *** *** 같은 오류가 발생했습니다. 올바른 위치에서 변경하지 않았을 수 있습니까? –

2

나는 긴 게시물을 이해하면 문자열을 사용하여 XML의 일부분을 구성하는 것으로 보입니다. 그러지 마. 항상 XML API 중 하나를 사용하여 XML을 작성하십시오. 인용 규칙을 알고 있습니다.

0

나는 이것이 어떻게 작동하는지 완전히 이해하지 못했습니다. 그러나 해결책을 찾았습니다. 내가 자랑스럽지 않은 추악하고 해킹 된 솔루션. 그러나 효과가있었습니다.

후세의 이익을 위해, 내가 마침내 한 일은 여기에 있습니다. 제 (10ish)의 각 내가 만드는 데 필요한 호출, 나는이는 HTTP 호출을하는 간단한 루틴을 호출

public string Newrule(string ruleName, DecisionSet decisionSet) 
    { 
     var soapString = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?><SOAP-ENV:Envelope " + 
         "xmlns:SOAPSDK1=\"http://www.w3.org/2001/XMLSchema\" xmlns:SOAPSDK2=\"http://www.w3.org/2001/XMLSchema-instance\" " + 
         "xmlns:SOAPSDK3=\"http://schemas.xmlsoap.org/soap/encoding/\" xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\">" + 
         "<SOAP-ENV:Body><SOAPSDK4:SetCondition xmlns:SOAPSDK4=\"http://tempuri.org/message/\"><sharedSecret></sharedSecret>" + 
         "<xmlData>&lt;SEARCHINFO_LIST&gt;&lt;SEARCH_INFO action=&quot;add&quot; status=&quot;3&quot; " + 
         "name=&quot;" + ruleName + "&quot; mask=&quot;0&quot; DecisionSet_id=&quot;" + decisionSet.Id + 
         "&quot; DecisionSet_protected=&quot;N&quot; " + 
         "condition_protected=&quot;N&quot;&gt;&lt;CONDITIONS/&gt;&lt;EXPRESSIONS/&gt;&lt;/SEARCH_INFO&gt;&lt;/SEARCHINFO_LIST&gt;" + 
         "</xmlData></SOAPSDK4:SetCondition></SOAP-ENV:Body></SOAP-ENV:Envelope>"; 

     var headerUrl = "http://tempuri.org/action/DecisionSet.SetCondition"; 
     var serviceUrl = "/webservice/DecisionSet.WSDL"; 
     var result = sender.MakeRequest(soapString, serviceUrl, headerUrl,null); 
     var idSearch = @"SEARCH_INFO id=&quot;(\d+)&quot;"; 

     var ruleId = Regex.Match(result, idSearch).Groups[1].Value; 

     return ruleId; 
    } 

루틴 검색, n은-교체 단순히 피들러를 통해 SOAP 호출을 캡처 한 다음 빠른 썼다 적절한 헤더와 함께. 부끄럽지 않지만 효과가있었습니다.

public string MakeRequest(string requestString, string serviceUrl, string headerUrl, string useragent) 
    { 
     string query = requestString.Replace(@"<sharedSecret></sharedSecret>", "<sharedSecret>"+secret+"</sharedSecret>"); 
     query = query.Replace(@"<SessionID></SessionID>", "<SessionID>" + secret + "</SessionID>"); 
     HttpWebRequest req = (HttpWebRequest)WebRequest.Create(server + serviceUrl); 
     //if (proxy != null) req.Proxy = new WebProxy(proxy, true); 
     req.Headers.Add("SOAPAction", headerUrl); 
     if (useragent == null) 
      req.UserAgent = "SOAP Toolkit 3.0"; 
     else 
     { 
      req.UserAgent = useragent; 
     } 
     req.ContentType = "text/xml;charset=\"utf-8\""; 
     req.Accept = "text/xml"; 
     req.Method = "POST"; 
     Stream stm = req.GetRequestStream(); 

     StreamWriter sw = new StreamWriter(stm); 
     sw.Write(query); 
     sw.Flush(); 
     stm.Close(); 
     WebResponse resp = req.GetResponse(); 
     stm = resp.GetResponseStream(); 
     StreamReader r = new StreamReader(stm); 
     string response = (r.ReadToEnd()); 

     return response; 
    }