通过WCF堆栈发送请求消息

时间:2019-06-13 08:12:28

标签: c# .net wcf

我们有一个WCF服务(ServiceContact + Implementation类)。该服务最初是使用ServiceHost和BasicHttpBinding通过TransportWithMessageCredential自托管的。

已将客户端配置为使用此服务,除非指向新的URL,否则无法更改。

现在,我们要更改服务的托管方式。新主机(不是IIS)上的入口点是Http请求消息(标头和正文)。这个想法是,我们将客户端指向新主机,并弥合Http请求和WCF堆栈之间的差距。

理论上,这听起来像我们必须创建一个新的TransportBindingElement,然后创建一个CustomBinding才能使用此传输。事实证明,这令人难以置信。

或者,听起来更容易的是,如果可能的话,从http请求创建WCF消息实例,然后以某种方式通过BasicHttpBinding使用的各种现有绑定元素将其发送(主要是处理所有Security标头),以及某种方式最终进入我们的WCF服务实施。

有人对是否可能以及如何实现有任何想法吗?

2019-06-14:添加示例以演示挑战:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace ConsoleApp5
{

    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string Invert(string s);
    }

    public interface IServiceChannel : IService, IClientChannel
    {
    }

    public class Service : IService
    {
        public string Invert(string s)
        {
            char[] charArray = s.ToCharArray();
            Array.Reverse(charArray);
            return new string(charArray);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            ServicePointManager.ServerCertificateValidationCallback = (a, b, c, d) => true;

            Console.WriteLine("Enter 1 for WCF Listene, anything else for HttpListener");
            var option = Console.ReadLine();

            if(option == "1")
            {
                Task.Run(() => StartWCFHost());
            }
            else
            {
                Task.Run(() => StartHttpListenerHost());
            }

            Console.WriteLine("hosting");
            Console.WriteLine("Enter string to invert");
            var streingToInvert = Console.ReadLine();
            var binding = new BasicHttpsBinding();
            binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
            binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
            var cf = new ChannelFactory<IService>(binding, new EndpointAddress("https://localhost:20443/myservice"));
            cf.Credentials.ClientCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "dc72486676c5e983589897fca5051a360376777d");

            var client = cf.CreateChannel();
            try
            {
                var r = client.Invert(streingToInvert);
                Console.WriteLine(r);
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            Console.ReadLine();
        }


        private static void StartHttpListenerHost()
        {
            var web = new HttpListener();
            web.Prefixes.Add("https://localhost:20443/");
            Console.WriteLine("Listening..");
            web.Start();
            while(true)
            {
                var context = web.GetContext();
                var soapMessage = Message.CreateMessage(XmlReader.Create(context.Request.InputStream), int.MaxValue, MessageVersion.Soap11);

                //TODO: How do we process request security related headers and give a proper response to client?
                //Ideally we want to use Service implementation class and WCF Bindings/BindingElements to process headers and generate response message
                //For the time being just read body write it to console

                var body = soapMessage.GetReaderAtBodyContents().ReadOuterXml();

                Console.WriteLine(soapMessage.ToString());

                Console.WriteLine(body);

                context.Response.Close();
            }
        }

        private static void StartWCFHost()
        {
            ServiceHost sh = new ServiceHost(typeof(Service), new Uri("https://localhost:20443/myservice"));
            var binding = new BasicHttpsBinding();
            binding.Security.Mode = BasicHttpsSecurityMode.TransportWithMessageCredential;
            binding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
            var se = sh.AddServiceEndpoint(typeof(IService), binding, "https://localhost:20443/myservice");
            sh.Description.Behaviors.Add(new ServiceMetadataBehavior { HttpsGetEnabled = true });
            sh.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByThumbprint, "dc72486676c5e983589897fca5051a360376777d");
            sh.Credentials.ClientCertificate.Authentication.CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None;
            sh.Open();
        }
    }
}

0 个答案:

没有答案