简体   繁体   English

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

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

It's pretty hard to find information about XMLRPC.net library used with https. 很难找到与https一起使用的XMLRPC.net库的信息。

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. 可以设置“https”URL的唯一文档是: http//xml-rpc.net/faq/xmlrpcnetfaq-2-5-0.html#2.3但是它没有准确解释如何正确设置。

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 : 在下载http://xmlrpcnet.googlecode.com/files/xml-rpc.net.2.5.0.zip中提供的样本基础上试验我试过这个:

Changes in the client.cs file of StateNameServer solution : StateNameServer解决方案的client.cs文件中的更改:

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. 当尝试使用HTTPS联系服务器时,客户端显然会丢弃异常,因为我不知道如何配置它。 Could someone help in anyway please ? 无论如何,有人可以帮忙吗? What kind of stuff should I look for ? 我应该寻找什么样的东西?

Thanks a lot ! 非常感谢 !

First, I would like to thank warmly Charles Cook for his help on this problem and for developing XMLRPC.NET. 首先,我要热烈感谢Charles Cook对此问题的帮助以及开发XMLRPC.NET。

Second, this sample is based on the XMLRPC.NET StateNameServer sample available for download here : http://xml-rpc.net/download.html 其次,此示例基于可在此处下载的XMLRPC.NET StateNameServer示例: http ://xml-rpc.net/download.html

So here is the solution : 所以这是解决方案:

1. Generate or get a [self-signed] certificate (using makecert.exe for example) 1.生成或获取[自签名]证书(例如使用makecert.exe)

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) 2.将此证书添加到服务器配置中,并使用httpcfg.exe或其他工具(如HttpSysConfig (开源))指定要与XMLRPC.NET服务器(在本例中为5678)一起使用的端口

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

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. 当然,我不在这里给出ServerStateName的接口实现,但你可以使用顶部的下载链接在示例文件中找到它。

Remark : 备注

System.Net.ServicePointManager.CertificatePolicy = new TrustAllCertificatePolicy() ; 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. 如果您发现任何可以改进的内容并且不正确,我们将不胜感激。

Create a client proxy using XmlRpcProxyGen.Create, specifying the https url (your interface should derive from IXmlRpcProxy). 使用XmlRpcProxyGen.Create创建客户端代理,指定https url(您的接口应该从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. 如果需要提供客户端证书,则代理具有ClientCertificates属性,该属性的使用方式与System.Net.HttpWebRequest类中的相应属性相同。

I don't think Remoting can support HTTPS. 我不认为Remoting可以支持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 您可以使用XML-RPC.NET FAQ中描述的HttpListener,但您需要配置证书,例如本博客中所述

Great article! 好文章! Helps me a lot. 帮助了我很多。 But item 1 and 2 took me a day to figure out. 但是第1项和第2项花了我一天才弄明白。 So here is my experience: 所以这是我的经验:

  1. To generate self-signed certificate I used openssl tool. 为了生成自签名证书,我使用了openssl工具。 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. 服务器代码使用没有Certificates属性的HttpListener类。 There is no way how to apply specific certificate to instance of HttpListener class. 如何将特定证书应用于HttpListener类的实例是没有办法的。 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. 要执行此操作,请在cmd->文件 - >添加/删除管理单元 - >证书 - >添加 - >计算机帐户 - >本地计算机 - >确定中键入“mmc”。 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). 下一步 - >下一步 - >选择Web服务器 - >单击蓝色链接 - >基本上你只需要在这里感受到Common Name(放置所需的证书名称)。 Ok->Enroll. 确定 - >报名。 Now you have yours certificate in the local storage. 现在您在本地存储中拥有您的证书。
    • Bind created certificate to specific ip/port pair. 将创建的证书绑定到特定的IP /端口对。 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; 要执行此操作,请在cmd中运行以下字符串: netsh http add sslcert ipport=192.168.111.195:4022 certhash=c8973a86141a7a564a6f509d1ecfea326a1852a2 appid={0a582a74-fc2d-476c-9281-c73b2e4bfb26} ,其中'ipport'是将使用的ip / port对用于ssl连接; 'certhash' is a certificate hash (open certificate that you created in previous step->go to Details->look for Thumbprint); 'certhash'是证书哈希(您在上一步中创建的开放证书 - >转到详细信息 - >查找Thumbprint); 'appid' could be any. 'appid'可以是任何。

If you you specify 'https' in your HttpListener url this class will automatically look for binded certificates. 如果您在HttpListener URL中指定“https”,则此类将自动查找绑定证书。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM