2016-06-14 5 views
1

У меня есть клиент, которому требуется TLS 1.2 для соответствия PCI. Xamarin Android не поддерживает TLS 1.2 очень хорошо. В соответствии с этим Native HttpClientHandler и этим Transport Layer Security вы можете использовать HttpClient со своим специальным механизмом для доступа к встроенной поддержке Java на Android 5 и выше, или вы можете использовать ModernHttpClient.Xamarin Android - Может ли веб-служба WCF SOAP использовать HttpClient для TLS 1.2?

Однако прокси-серверы WCF SOAP, созданные с помощью SvcUtil, как представляется, используют HttpWebRequest, а не HttpClient.

Каков рекомендуемый способ вызова служб WCF SOAP с использованием HttpClient (или ModernHttpClient)? Должен ли я вручную писать свои собственные интерфейсы или я могу использовать классы прокси и самостоятельно сериализовать/десериализовать их? Я бы не стал полностью начинать с нуля, тем более, что в настоящее время TLS 1.2 добавляется в Mono.

ответ

0

Я использовал этот вид обслуживания, и он работает здесь. У меня есть соответствующий код, пожалуйста, попробуйте.

static void TryByWebRequest(string soapMethod) 
     { 
XmlDocument soapEnvelopeXml = new XmlDocument(); 

      soapEnvelopeXml.LoadXml(@" 
         <s:Envelope xmlns:s=""http://schemas.xmlsoap.org/soap/envelope/""> 
          <s:Body> 
           <" + soapMethod + @" 
           xmlns=""your URI"" 
           xmlns:i=""http://www.w3.org/2001/XMLSchema-instance""> 
            <InputXMLString> 
             " + 
            System.Security.SecurityElement.Escape(inputXML) 
            + @"     
            </InputXMLString>        
            <OutputXMLString/> 
           </" + soapMethod + @"> 
          </s:Body> 
         </s:Envelope>"); 


      using (Stream stream = request.GetRequestStream()) 
      { 
       soapEnvelopeXml.Save(stream); 
      } 

      using (WebResponse response = request.GetResponse()) 
      { 
       using (StreamReader rd = new StreamReader(response.GetResponseStream())) 
       { 
        string soapResult = rd.ReadToEnd(); 
        Console.WriteLine(soapResult); 
       } 
      } 
} 
    static HttpWebRequest CreateWebRequest(string soapMethod) 
      { 
       HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(@"Your .asmx URL "); 
       webRequest.Headers.Add(@"SOAPAction", "your URI \" + soapMethod); 
       webRequest.ContentType = "text/xml;charset=\"utf-8\""; 
       webRequest.Accept = "text/xml"; 
       webRequest.Method = "POST"; 

       return webRequest; 
      } 
0

Я получил эту работу. Поскольку это временное решение (надеюсь), моя цель состояла в том, чтобы создавать замены для сгенерированных Proxy-классов, и я получил довольно близко. Ключ должен был выяснить, как использовать DataContractSerializer для создания конверта SOAP для отправки и десериализации результатов.

У меня было все, кроме сериализации конверта SOAP, который отправляется на веб-службу. Я закончил вручную обматывание XML в тегах <envelope> и <body>. Ничто из того, что я сделал, не может заставить DataContractSerializer создать их правильно, хотя содержимое Body было в порядке. Однако Deserializer смог обработать ответ от веб-службы без каких-либо проблем. Услуги WCF очень придирчивы к формату конверта SOAP, и получение классов, аннотированных только в порядке, было проблемой.

Для каждого вызова функции мне пришлось создать объект Request, который обертывает параметры, отправляемые в веб-службу, и объект Response, который обертывает параметры out и код возврата.

Они выглядят примерно так, где FunctionName - это имя вызова функции WCF, сгенерированного прокси.

// request envelope 
    [System.Runtime.Serialization.DataContractAttribute(Name = "FunctionName", Namespace = "http://tempuri.org/")] 
    public class FunctionName_Request 
    { 
     [System.Runtime.Serialization.DataMemberAttribute()] 
     public NameSpaceFunctionNameObject1 CallingObject1; 

     [System.Runtime.Serialization.DataMemberAttribute()] 
     public NameSpaceFunctionNameObject2 CallingObject2; 
    } 

    // response envelope 
    [System.Runtime.Serialization.DataContractAttribute(Name = "Envelope", Namespace = "http://schemas.xmlsoap.org/soap/envelope/")] 
    public class FunctionName_ResponseEnvelope 
    { 
     [System.Runtime.Serialization.DataContractAttribute(Name = "Body", Namespace = "http://tempuri.org/")] 
     public class FunctionName_ResponseBody 
     { 
      [System.Runtime.Serialization.DataContractAttribute(Name = "FunctionNameResponse", Namespace = "http://tempuri.org/")] 
      public class FunctionName_Response 
      { 
       [System.Runtime.Serialization.DataMemberAttribute()] 
       public FunctionNameReturnCodes Result; 

       [System.Runtime.Serialization.DataMemberAttribute()] 
       public FunctionNameResponseObject Response; 
      } 

      [System.Runtime.Serialization.DataMemberAttribute()] 
      public FunctionName_Response FunctionNameResponse; 
     } 

     [System.Runtime.Serialization.DataMemberAttribute()] 
     public FunctionName_ResponseBody Body; 
    } 

Тогда я могу написать функцию замены, что мой код клиента может позвонить, который имеет точно такую ​​же сигнатуру, что и исходный прокси-генерироваться функции.

// FunctionName 
    public FunctionNameReturnCodes FunctionName(out FunctionNameResponseObject Response, NameSpaceFunctionNameObject1 CallingObject1, NameSpaceFunctionNameObject2 CallingObject2) 
    { 
     // create the request envelope 
     FunctionName_Request req = new FunctionName_Request(); 
     req.CallingObject1 = CallingObject1; 
     req.CallingObject2 = CallingObject2; 

     // make the call 
     FunctionName_ResponseEnvelope resp = MakeWCFCall<FunctionName_ResponseEnvelope>(_EndpointAddress, _ServerName, req); 

     // get the response object 
     Response = resp.Body.FunctionName_Response.Response; 

     // result 
     return resp.Body.FunctionName_Response.Result; 
    } 

Наконец, это функция, которая на самом деле упорядочивает и десериализует объект в HttpClient. В моем случае они синхронны, но вы можете легко адаптировать их для работы в стандартном асинхронном случае. Это шаблон, поэтому он работает с любым из созданных прокси-типов.

///////////////////////////////////////////////////////////////////// 
    // make a WCF call using an HttpClient object 
    // uses the DataContractSerializer to serialze/deserialze the messages from the objects 
    // 
    // We manually add the <s:Envelope> and <s:Body> tags. There should be a way to get 
    // the DataContractSerializer to write these too, but everything I tried gave a message 
    // that was not able to be procesed by the service. This includes the Message object. 
    // Deserializing works fine, but serializing did not. 
    private T MakeWCFCall<T>(string strEndpoint, string strServerName, object SourceObject) 
    { 
     T Response = default(T); 
     string strSoapMessage = ""; 
     string strSoapAction = ""; 

     // get the Soap Action by using the DataContractAttribute's name 
     // start by getting the list of custom attributes. 
     // there should only be the one 
     object[] oaAttr = SourceObject.GetType().GetCustomAttributes(false); 
     if (oaAttr.Length > 0) 
     { 
      // iterate just in case there are more 
      foreach (DataContractAttribute oAttr in oaAttr) 
      { 
       // make sure we got one 
       if (oAttr != null) 
       { 
        // this is the action! 
        strSoapAction = oAttr.Name; 
        break; 
       } 
      } 
     } 

     // serialize the request into a string 
     // use a memory stream as the source 
     using (MemoryStream ms = new MemoryStream()) 
     { 
      // create the DataContractSerializer 
      DataContractSerializer ser = new DataContractSerializer(SourceObject.GetType()); 

      // serialize the object into the memory stream 
      ser.WriteObject(ms, SourceObject); 

      // seek to the beginning so we can read back out of the stream 
      ms.Seek(0, SeekOrigin.Begin); 

      // create the stream reader 
      using (var streamReader = new StreamReader(ms)) 
      { 
       // read the message back out, adding the Envelope and Body wrapper 
       strSoapMessage = @"<s:Envelope xmlns:s = ""http://schemas.xmlsoap.org/soap/envelope/""><s:Body>" + streamReader.ReadToEnd() + @"</s:Body></s:Envelope>"; 
      } 
     } 

     // now create the HttpClient connection 
     using (var client = new HttpClient(new NativeMessageHandler())) 
     { 
      //specify to use TLS 1.2 as default connection 
      System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; 

      // add the Soap Action header 
      client.DefaultRequestHeaders.Add("SOAPAction", "http://tempuri.org/" + strServerName + "/" + strSoapAction); 

      // encode the saop message 
      var content = new StringContent(strSoapMessage, Encoding.UTF8, "text/xml"); 

      // post to the server 
      using (var response = client.PostAsync(new Uri(strEndpoint), content).Result) 
      { 
       // get the response back 
       var soapResponse = response.Content.ReadAsStringAsync().Result; 

       // create a MemoryStream to use for serialization 
       using (MemoryStream memoryStream = new MemoryStream(Encoding.UTF8.GetBytes(soapResponse))) 
       { 
        // create the reader 
        // set the quotas 
        XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader(
         memoryStream, 
         Encoding.UTF8, 
         new XmlDictionaryReaderQuotas() { MaxArrayLength = 5000000, MaxBytesPerRead = 5000000, MaxStringContentLength = 5000000 }, 
         null); 

        // create the Data Contract Serializer 
        DataContractSerializer serializer = new DataContractSerializer(typeof(T)); 

        // deserialize the response 
        Response = (T)serializer.ReadObject(reader); 
       } 
      } 
     } 

     // return the response 
     return Response; 
    } 

Этот подход позволил мне быстро написать обертки для всех моих сервисных функций WCF, и он работает до сих пор.

 Смежные вопросы

  • Нет связанных вопросов^_^