从没有HttpClient的同一站点上的另一个解耦WCF服务调用WCF服务

时间:2019-06-21 16:05:33

标签: c# .net wcf

我有一个插件模型体系结构,可以创建我的Restful WCF服务。

(从WCF迁移到Web Api还需要几年时间,因此,迁移到Web Api并不是完全解决方案。)

我已经解耦了彼此不引用的WCF微服务。

  • EntityAWebService
  • EntityBWebService

EnityAWebService从配置中知道服务EntityBWebService存在,但未引用它。

EntityAWebService和EntityBWebService是插件。这样,它们可以在同一站点上加载。

EntityAWebService使用配置信息来调用EntityBWebService。 EntityBWebService可以在同一服务器上,也可以在其他服务器上。  -如果在其他服务器上,代码将继续使用HttpClient。  -如果在同一台服务器上,则发送消息并通过通道发送,而无需通过HttpClient,操作系统的网络和IIS。

下面是体系结构。橙色是我想要创建的。

enter image description here

使用HttpClient表示EntityAWebService发送一条消息,该消息将进入操作系统网络层并通过IIS。两者都不是必需的。这会导致性能问题,并且随着Entity插件的增加,套接字的数量也会增加,即使使用单例httpclient,套接字也会泄漏。

体系结构中的橙色是尚不存在的。

代码知道要为实体B Web服务调用的Url,消息内容和标头。我将如何在橙色框表示的代码中模拟IIS通过行为将呼叫转发到端点的功能?

仅供参考,我当前的项目太复杂而无法发布,因此我将创建一个示例并尽快发布。

示例项目:https://github.com/rhyous/DecoupledWcfServices

1 个答案:

答案 0 :(得分:0)

原来,我不需要使用命名管道。但是,研究如何使用命名管道教会了我需要知道的知识。我只需要使用反射和ChannelFactory。由于用于IIS托管的ChannelFactory已经存在,因此命名管道将是多余的。

示例项目在这里:https://github.com/rhyous/DecoupledWcfServices

下面是适当的代码段(解决方案的内容)。

using System;
using System.Collections.Specialized;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.ServiceModel.Web;

namespace DecoupledWcfServices
{
    /// <summary>
    /// Service 1 and Service 2 are in the same namespace in this project
    /// </summary>
    public class MessageBus
    {
        public string CallOtherWcfService(string url, object content, NameValueCollection headers)
        {
            var service = GetServiceName(url);
                try
            {
                var netPipeUrl = $"http://localhost:54412/{service}/{service}.svc";
                var serviceContractType = typeof(IService2);
                var genericChannelFactoryType = typeof(WebChannelFactory<>).MakeGenericType(serviceContractType);
                var binding = new WebHttpBinding();

                var channelFactory = Activator.CreateInstance(genericChannelFactoryType, binding, new Uri(netPipeUrl)) as WebChannelFactory<IService2>; // I actually won't know it is an IService2 in my project, but getting this far should be enough
                var proxy = channelFactory.CreateChannel() as IService2; 
                using (new OperationContextScope((IContextChannel)proxy))
                {
                    var task = proxy.GetData("some data"); // Might need more work here to know which method to call based on the Url
                    task.Wait();
                    return task.Result; // Serialized JSON
                }
            }
            catch (Exception)
            {
                throw;
            }
        }

        internal string GetServiceName(string url)
        {
            var index = url.IndexOf(".svc");
            var sub = url.Substring(0, index);
            index = sub.LastIndexOf("/") + 1;
            var sub2 = url.Substring(index, sub.Length - index);
            return sub2;
        }
    }
}