2011-10-26 53 views
5

很難找到有關用於https的XMLRPC.net庫的信息。通過HTTPS實現C#XMLRPC.NET客戶端和服務器

可以設置「https」URL的唯一文檔在這裏:http://xml-rpc.net/faq/xmlrpcnetfaq-2-5-0.html#2.3但它並不能準確解釋如何正確設置。

進行實驗在下載http://xmlrpcnet.googlecode.com/files/xml-rpc.net.2.5.0.zip我想這提供的樣品的基礎上:

變化的StateNameServer解決方案client.cs文件:

IStateName svr = (IStateName)Activator.GetObject(
typeof(IStateName), "https://localhost:5678/statename.rem"); 

是服務器的代碼看起來像

IDictionary props = new Hashtable(); 
    props["name"] = "MyHttpChannel"; 
    props["port"] = 5678; 
    HttpChannel channel = new HttpChannel(
    props, 
    null, 
    new XmlRpcServerFormatterSinkProvider() 
    ); 

    ChannelServices.RegisterChannel(channel, false); 

    RemotingConfiguration.RegisterWellKnownServiceType(
    typeof(StateNameServer), 
    "statename.rem", 
    WellKnownObjectMode.Singleton); 

該客戶名稱已關閉嘗試使用HTTPS聯繫服務器時發生異常,因爲我不知道如何配置它。無論如何,有人可以幫忙嗎?我應該尋找什麼樣的東西?

非常感謝!

回答

3

首先,我要感謝Charles Cook對此問題的幫助以及開發XMLRPC。淨。

其次,這個樣本是基於XMLRPC.NET StateNameServer樣品可在這裏下載: http://xml-rpc.net/download.html

所以這裏是解決方案:

1.生成或獲得[自簽名]證書(例如使用makecert.exe)

2.將此證書添加到您的服務器配置中,並使用httpcf指定要用於XMLRPC.NET服務器(在本例中爲5678)的端口

using System; 
using System.Collections; 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Channels; 
using System.Runtime.Remoting.Channels.Http; 

using CookComputing.XmlRpc; 

using System.Net; 
using System.IO; 

public class _ 
{ 
    static void Main(string[] args) 
    { 
     HttpListener listener = new HttpListener(); 
     listener.Prefixes.Add("https://127.0.0.1:5678/"); 
     listener.Start(); 
     while (true) 
     { 
      HttpListenerContext context = listener.GetContext(); 
      ListenerService svc = new StateNameService(); 
      svc.ProcessRequest(context); 
     } 

     Console.WriteLine("Press <ENTER> to shutdown"); 
     Console.ReadLine(); 
    } 
} 

public class StateNameService : ListenerService 
{ 
    [XmlRpcMethod("examples.getStateName")] 
    public string GetStateName(int stateNumber) 
    { 
     if (stateNumber < 1 || stateNumber > m_stateNames.Length) 
      throw new XmlRpcFaultException(1, "Invalid state number"); 
     return m_stateNames[stateNumber - 1]; 
    } 

    string[] m_stateNames 
     = { "Alabama", "Alaska", "Arizona", "Arkansas", 
     "California", "Colorado", "Connecticut", "Delaware", "Florida", 
     "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", 
     "Kansas", "Kentucky", "Lousiana", "Maine", "Maryland", "Massachusetts", 
     "Michigan", "Minnesota", "Mississipi", "Missouri", "Montana", 
     "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
     "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", 
     "Oregon", "Pennsylviania", "Rhose Island", "South Carolina", 
     "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", 
     "Washington", "West Virginia", "Wisconsin", "Wyoming" }; 
} 

public abstract class ListenerService : XmlRpcHttpServerProtocol 
{ 
    public virtual void ProcessRequest(HttpListenerContext RequestContext) 
    { 
     try 
     { 
      IHttpRequest req = new ListenerRequest(RequestContext.Request); 
      IHttpResponse resp = new ListenerResponse(RequestContext.Response); 
      HandleHttpRequest(req, resp); 
      RequestContext.Response.OutputStream.Close(); 
     } 
     catch (Exception ex) 
     { 
      // "Internal server error" 
      RequestContext.Response.StatusCode = 500; 
      RequestContext.Response.StatusDescription = ex.Message; 
     } 
    } 
} 

public class ListenerRequest : CookComputing.XmlRpc.IHttpRequest 
{ 
    public ListenerRequest(HttpListenerRequest request) 
    { 
     this.request = request; 
    } 

    public Stream InputStream 
    { 
     get { return request.InputStream; } 
    } 

    public string HttpMethod 
    { 
     get { return request.HttpMethod; } 
    } 

    private HttpListenerRequest request; 
} 

public class ListenerResponse : CookComputing.XmlRpc.IHttpResponse 
{ 
    public ListenerResponse(HttpListenerResponse response) 
    { 
     this.response = response; 
    } 

    string IHttpResponse.ContentType 
    { 
     get { return response.ContentType; } 
     set { response.ContentType = value; } 
    } 

    TextWriter IHttpResponse.Output 
    { 
     get { return new StreamWriter(response.OutputStream); } 
    } 

    Stream IHttpResponse.OutputStream 
    { 
     get { return response.OutputStream; } 
    } 

    int IHttpResponse.StatusCode 
    { 
     get { return response.StatusCode; } 
     set { response.StatusCode = value; } 
    } 

    string IHttpResponse.StatusDescription 
    { 
     get { return response.StatusDescription; } 
     set { response.StatusDescription = value; } 
    } 

    private HttpListenerResponse response; 
} 

public class StateNameServer : MarshalByRefObject, IStateName 
{ 
    public string GetStateName(int stateNumber) 
    { 
    if (stateNumber < 1 || stateNumber > m_stateNames.Length) 
     throw new XmlRpcFaultException(1, "Invalid state number"); 
    return m_stateNames[stateNumber-1]; 
    } 

    public string GetStateNames(StateStructRequest request) 
    { 
    if (request.state1 < 1 || request.state1 > m_stateNames.Length) 
     throw new XmlRpcFaultException(1, "State number 1 invalid"); 
    if (request.state2 < 1 || request.state2 > m_stateNames.Length) 
     throw new XmlRpcFaultException(1, "State number 1 invalid"); 
    if (request.state3 < 1 || request.state3 > m_stateNames.Length) 
     throw new XmlRpcFaultException(1, "State number 1 invalid"); 
    string ret = m_stateNames[request.state1-1] + " " 
     + m_stateNames[request.state2-1] + " " 
     + m_stateNames[request.state3-1]; 
    return ret; 
    } 

    string[] m_stateNames 
    = { "Alabama", "Alaska", "Arizona", "Arkansas", 
     "California", "Colorado", "Connecticut", "Delaware", "Florida", 
     "Georgia", "Hawaii", "Idaho", "Illinois", "Indiana", "Iowa", 
     "Kansas", "Kentucky", "Lousiana", "Maine", "Maryland", "Massachusetts", 
     "Michigan", "Minnesota", "Mississipi", "Missouri", "Montana", 
     "Nebraska", "Nevada", "New Hampshire", "New Jersey", "New Mexico", 
     "New York", "North Carolina", "North Dakota", "Ohio", "Oklahoma", 
     "Oregon", "Pennsylviania", "Rhose Island", "South Carolina", 
     "South Dakota", "Tennessee", "Texas", "Utah", "Vermont", "Virginia", 
     "Washington", "West Virginia", "Wisconsin", "Wyoming" }; 
} 

4.使用實現你XMLRPC.NET客戶端:g.exe或類似HttpSysConfig其他工具(開源)

3.使用下面的代碼實現你XMLRPC.NET服務器下面的代碼(代碼還創建了一個新的X509客戶端證書)

using System; 
using System.Collections; 
using System.Runtime.Remoting; 
using System.Runtime.Remoting.Channels; 
using System.Runtime.Remoting.Channels.Http; 

using CookComputing.XmlRpc; 
using System.Net; 
using System.Security.Cryptography.X509Certificates; 

class _ 
{ 
    public class TrustAllCertificatePolicy : System.Net.ICertificatePolicy 
    { 
     public TrustAllCertificatePolicy() { } 
     public bool CheckValidationResult(ServicePoint sp, 
      X509Certificate cert, 
      WebRequest req, 
      int problem) 
     { 
      return true; 
     } 
    } 
    static void Main(string[] args) 
    { 
     System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); 
     IStateName proxy = XmlRpcProxyGen.Create<IStateName>(); 
     XmlRpcClientProtocol cp = (XmlRpcClientProtocol)proxy; 
     cp.Url = "https://127.0.0.1:5678/"; 
     cp.ClientCertificates.Add(new System.Security.Cryptography.X509Certificates.X509Certificate(@"C:\path\to\your\certificate\file\my.cer")); 
     cp.KeepAlive = false; 
     //cp.Expect100Continue = false; 
     //cp.NonStandard = XmlRpcNonStandard.All; 

     string stateName = ((IStateName)cp).GetStateName(13); 
    } 
} 

當然,我不給這裏的接口implem但是你可以在示例文件中使用頂部的下載鏈接找到它。

備註

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy();將允許服務器實現接受您自己生成的自簽名證書。我認爲這對證書頒發機構頒發的證書沒有必要。

如果你發現任何可以改進和不正確的東西,將不勝感激。

+0

經過測試,我可以確認該實現在兩臺獨立的Windows機器上運行。 – virrea

2

使用XmlRpcProxyGen.Create創建客戶端代理,並指定https url(您的接口應該從IXmlRpcProxy派生)。如果您需要提供客戶端證書,則代理具有ClientCertificates屬性,該屬性可以與System.Net.HttpWebRequest類中相應的屬性相同的方式使用。

我不認爲Remoting可以支持HTTPS。您可以按XML-RPC.NET FAQ中所述使用HttpListener,但您需要配置證書,例如,如上所述blog

+0

謝謝Charles。我嘗試使用XmlRpcProxyGen,但客戶端在嘗試發送數據時繼續丟棄異常。服務器不需要某種證書嗎? – virrea

+0

添加了關於實現服務器的段落。 –

+0

謝謝您的幫助Charles,您的鏈接幫助我找出解決方案。我將證書添加到服務器(實際上是我的本地計算機)......我的回覆中的解決方案的其餘部分。 – virrea

1

好文章!幫助我很多。 但項目1和2花了我一天的時間來弄清楚。所以這裏是我的經驗:

  1. 要生成自簽證書我使用openssl工具。只需按照鏈接中的說明操作即可。這是我需要的客戶端應用程序證書。
  2. 對於服務器應用程序,我需要另一個證書。服務器代碼使用沒有Certificates屬性的HttpListener類。沒有辦法如何將特定的證書應用於HttpListener類的實例。還有另一種策略:
    • 在本地證書存儲中創建新證書。 在cmd-> File-> Add/Remove Snap-in-> Certificates-> Add-> Computer account-> Local computer-> OK中輸入'mmc'。進入個人 - >證書 - >右鍵 - >所有任務 - >申請新證書。下一步 - >下一步 - >選擇Web服務器 - >點擊藍色鏈接 - >基本上你只需要在這裏感受到公用名稱(把所需的證書名稱)。確定 - >報名。現在你在本地存儲器中擁有你的證書。
    • 將創建的證書綁定到特定的IP /端口對。 爲此,請在cmd中運行以下字符串:netsh http add sslcert ipport=192.168.111.195:4022 certhash=c8973a86141a7a564a6f509d1ecfea326a1852a2 appid={0a582a74-fc2d-476c-9281-c73b2e4bfb26},其中'ipport'是將用於ssl連接的ip/port對; 'certhash'是證書散列(在上一步中創建的打開證書 - >轉到詳細信息 - >查找指紋); 'appid'可以是任何。

如果你指定的「https」在HttpListener網址該類會自動尋找綁定證書。

+0

給它幫助! :)我會嘗試你的筆記。 – virrea