通过 HTTPS 实现 C# XMLRPC.NET 客户端和服务器

发布于 2024-12-11 21:59:31 字数 1198 浏览 0 评论 0原文

很难找到有关与 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 联系服务器时,客户端显然会抛出异常,因为我不知道如何配置它。无论如何有人可以帮忙吗?我应该寻找什么样的东西?

多谢 !

It's pretty hard to find information about XMLRPC.net library used with https.

The only documentation where an "https" URL can be set is here : http://xml-rpc.net/faq/xmlrpcnetfaq-2-5-0.html#2.3 but yet it does not explain exactly how can one setup correctly.

Experimenting on the base of samples provided in the downloads http://xmlrpcnet.googlecode.com/files/xml-rpc.net.2.5.0.zip I tried this :

Changes in the client.cs file of StateNameServer solution :

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

What the server code looks like

    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);

The client obviously drops an exception when trying to contact the server using HTTPS because I don't know how to configure it. Could someone help in anyway please ? What kind of stuff should I look for ?

Thanks a lot !

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

空城之時有危險 2024-12-18 21:59:31

首先,我要热烈感谢 Charles Cook 对这个问题的帮助以及对 XMLRPC.NET 的开发。

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

所以这是解决方案:

<强>1。生成或获取[自签名]证书(例如使用makecert.exe)

2.将此证书添加到您的服务器配置中,并使用 httpcfg.exe 或 HttpSysConfig(开源)

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();将允许服务器实现接受您自己生成的自签名证书。我认为对于认证机构颁发的证书来说这是没有必要的。

如果您发现任何可以改进且不正确的地方,我们将不胜感激。

First, I would like to thank warmly Charles Cook for his help on this problem and for developing XMLRPC.NET.

Second, this sample is based on the XMLRPC.NET StateNameServer sample available for download here :
http://xml-rpc.net/download.html

So here is the solution :

1. Generate or get a [self-signed] certificate (using makecert.exe for example)

2. Add this certificate to your server configuration and specify the port you want to use with your XMLRPC.NET server (in this case 5678) using httpcfg.exe or another tool like HttpSysConfig (Open Source)

3. Implement your XMLRPC.NET server using the following code :

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. Implement your XMLRPC.NET client using the following code (the code also creates a new X509 client certificate)

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);
    }
}

Of course, I don't give here the interface implementation for the ServerStateName but you'll find it in the sample files using the download link at the top.

Remark :

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy(); will allow the server implementation to accept the self-signed certificate you generated by yourself. I think this is not necessary with certificates issued by certification authorities.

If you find anything that could be improved and is incorrect it will be much appreciated.

嘿哥们儿 2024-12-18 21:59:31

使用 XmlRpcProxyGen.Create 创建客户端代理,指定 https url(您的接口应派生自 IXmlRpcProxy)。如果您需要提供客户端证书,则代理具有 ClientCertificates 属性,该属性的使用方式与 System.Net.HttpWebRequest 类上的相应属性相同。

我认为 Remoting 不支持 HTTPS。您可以按照 XML-RPC.NET FAQ< 中所述使用 HttpListener /a> 但您需要配置证书,例如此 博客

Create a client proxy using XmlRpcProxyGen.Create, specifying the https url (your interface should derive from IXmlRpcProxy). If you need to supply client certificate(s) the proxy has a ClientCertificates property which can be used in the same way as the corresponding property on the System.Net.HttpWebRequest class.

I don't think Remoting can support HTTPS. You can use HttpListener as described in the XML-RPC.NET FAQ but you will need to configure a certificate, for example as described in this blog

简美 2024-12-18 21:59:31

很棒的文章!对我有很大帮助。
但第 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”是将用于 ssl 连接的 IP/端口对; 'certhash' 是证书哈希(打开您在上一步中创建的证书 -> 转到详细信息 -> 查找指纹); “appid”可以是任意值。

如果您在 HttpListener url 中指定“https”,此类将自动查找绑定的证书。

Great article! Helps me a lot.
But item 1 and 2 took me a day to figure out. So here is my experience:

  1. To generate self-signed certificate I used openssl tool. Just follow the instruction in the link. This certificate I needed for client application.
  2. For server application I needed another certificate. Server code uses HttpListener class which has no Certificates property. There is no way how to apply specific certificate to instance of HttpListener class. There is another strategy:
    • Create new certificate in local certificate storage.
      To do this type 'mmc' in cmd->File->Add/Remove Snap-in->Certificates->Add->Computer account->Local computer->OK. Go to Personal->Certificates->Right click->All tasks->Request new certificate. Next->Next->select Web Server->click the blue link->basically you need to feel only Common Name here (put desired certificate name). Ok->Enroll. Now you have yours certificate in the local storage.
    • Bind created certificate to specific ip/port pair.
      To do this run following string in cmd: netsh http add sslcert ipport=192.168.111.195:4022 certhash=c8973a86141a7a564a6f509d1ecfea326a1852a2 appid={0a582a74-fc2d-476c-9281-c73b2e4bfb26}, where 'ipport' is ip/port pair which will be used for ssl connection; 'certhash' is a certificate hash (open certificate that you created in previous step->go to Details->look for Thumbprint); 'appid' could be any.

If you you specify 'https' in your HttpListener url this class will automatically look for binded certificates.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文