簡體   English   中英

通過HTTPS實現C#XMLRPC.NET客戶端和服務器

[英]Implementation of C# XMLRPC.NET client and server over HTTPS

很難找到與https一起使用的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聯系服務器時,客戶端顯然會丟棄異常,因為我不知道如何配置它。 無論如何,有人可以幫忙嗎? 我應該尋找什么樣的東西?

非常感謝 !

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

其次,此示例基於可在此處下載的XMLRPC.NET StateNameServer示例: http ://xml-rpc.net/download.html

所以這是解決方案:

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

2.將此證書添加到服務器配置中,並使用httpcfg.exe或其他工具(如HttpSysConfig (開源))指定要與XMLRPC.NET服務器(在本例中為5678)一起使用的端口

3.使用以下代碼實現XMLRPC.NET服務器:

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客戶端(代碼還創建新的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);
    }
}

當然,我不在這里給出ServerStateName的接口實現,但你可以使用頂部的下載鏈接在示例文件中找到它。

備注

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

如果您發現任何可以改進的內容並且不正確,我們將不勝感激。

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

我不認為Remoting可以支持HTTPS。 您可以使用XML-RPC.NET FAQ中描述的HttpListener,但您需要配置證書,例如本博客中所述

好文章! 幫助了我很多。 但是第1項和第2項花了我一天才弄明白。 所以這是我的經驗:

  1. 為了生成自簽名證書,我使用了openssl工具。 只需按照鏈接中的說明操作即可。 我需要客戶端申請的證書。
  2. 對於服務器應用,我需要另一個證書 服務器代碼使用沒有Certificates屬性的HttpListener類。 如何將特定證書應用於HttpListener類的實例是沒有辦法的。 還有另一種策略:
    • 在本地證書存儲中創建新證書。 要執行此操作,請在cmd->文件 - >添加/刪除管理單元 - >證書 - >添加 - >計算機帳戶 - >本地計算機 - >確定中鍵入“mmc”。 轉到個人 - >證書 - >右鍵單擊 - >所有任務 - >申請新證書。 下一步 - >下一步 - >選擇Web服務器 - >單擊藍色鏈接 - >基本上你只需要在這里感受到Common Name(放置所需的證書名稱)。 確定 - >報名。 現在您在本地存儲中擁有您的證書。
    • 將創建的證書綁定到特定的IP /端口對。 要執行此操作,請在cmd中運行以下字符串: netsh http add sslcert ipport=192.168.111.195:4022 certhash=c8973a86141a7a564a6f509d1ecfea326a1852a2 appid={0a582a74-fc2d-476c-9281-c73b2e4bfb26} ,其中'ipport'是將使用的ip / port對用於ssl連接; 'certhash'是證書哈希(您在上一步中創建的開放證書 - >轉到詳細信息 - >查找Thumbprint); 'appid'可以是任何。

如果您在HttpListener URL中指定“https”,則此類將自動查找綁定證書。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM