C# 在没有HttpClient的情况下,从同一站点上的另一个解耦WCF服务调用WCF服务

C# 在没有HttpClient的情况下,从同一站点上的另一个解耦WCF服务调用WCF服务,c#,.net,wcf,C#,.net,Wcf,我有一个插件模型架构来创建我的Restful WCF服务 (在我们从WCF转向Web Api之前需要几年的时间,因此,转向Web Api并不是一个完全的解决方案。) 我已经解耦了互不引用的WCF微服务 实体Web服务 EntityBWebService EnityAWebService知道服务EntityBWebService存在于配置中,但不引用它 EntityAWebService和EntityBWebService是插件。因此,它们可以在同一站点上加载 EntityAWebServic

我有一个插件模型架构来创建我的Restful WCF服务

(在我们从WCF转向Web Api之前需要几年的时间,因此,转向Web Api并不是一个完全的解决方案。)

我已经解耦了互不引用的WCF微服务

  • 实体Web服务
  • EntityBWebService
EnityAWebService知道服务EntityBWebService存在于配置中,但不引用它

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

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

下面是架构。橙色是我想要创造的

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

建筑中的橙色是尚不存在的

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

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


示例项目:

结果表明,我不需要使用命名管道。然而,调查如何使用命名管道教会了我需要知道的东西。我只需要使用反射和通道工厂。由于IIS宿主的ChannelFactory已经存在,因此命名管道将是多余的

此处的示例项目:

下面是相应的代码片段(解决方案的核心部分)

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;
        }
    }
}
使用系统;
使用System.Collections.Specialized;
使用System.ServiceModel;
使用System.ServiceModel.Description;
使用System.ServiceModel.Web;
命名空间解耦DWCFServices
{
/// 
///服务1和服务2在此项目中位于同一命名空间中
/// 
公共类消息总线
{
公共字符串CallOtherWcfService(字符串url、对象内容、NameValueCollection标头)
{
var service=GetServiceName(url);
尝试
{
var netPipeUrl=$”http://localhost:54412/{service}/{service}.svc”;
var serviceContractType=typeof(IService2);
var genericChannelFactoryType=typeof(WebChannelFactory)。MakeGenericType(serviceContractType);
var binding=新的WebHttpBinding();
var channelFactory=Activator.CreateInstance(genericChannelFactoryType,binding,new Uri(netPipeUrl))作为WebChannelFactory;//我实际上不知道它在我的项目中是一个IService2,但走这么远应该足够了
var proxy=channelFactory.CreateChannel()作为IService2;
使用(新OperationContextScope((IContextChannel)代理))
{
var task=proxy.GetData(“某些数据”);//这里可能需要更多的工作才能知道基于Url调用哪个方法
task.Wait();
return task.Result;//序列化的JSON
}
}
捕获(例外)
{
投掷;
}
}
内部字符串GetServiceName(字符串url)
{
var index=url.IndexOf(“.svc”);
var sub=url.Substring(0,索引);
索引=sub.LastIndexOf(“/”)+1;
var sub2=url.Substring(索引,sub.Length-index);
返回sub2;
}
}
}

结果表明,我不需要使用命名管道。然而,调查如何使用命名管道教会了我需要知道的东西。我只需要使用反射和通道工厂。由于IIS宿主的ChannelFactory已经存在,因此命名管道将是多余的

此处的示例项目:

下面是相应的代码片段(解决方案的核心部分)

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;
        }
    }
}
使用系统;
使用System.Collections.Specialized;
使用System.ServiceModel;
使用System.ServiceModel.Description;
使用System.ServiceModel.Web;
命名空间解耦DWCFServices
{
/// 
///服务1和服务2在此项目中位于同一命名空间中
/// 
公共类消息总线
{
公共字符串CallOtherWcfService(字符串url、对象内容、NameValueCollection标头)
{
var service=GetServiceName(url);
尝试
{
var netPipeUrl=$”http://localhost:54412/{service}/{service}.svc”;
var serviceContractType=typeof(IService2);
var genericChannelFactoryType=typeof(WebChannelFactory)。MakeGenericType(serviceContractType);
var binding=新的WebHttpBinding();
var channelFactory=Activator.CreateInstance(genericChannelFactoryType,binding,new Uri(netPipeUrl))作为WebChannelFactory;//我实际上不知道它在我的项目中是一个IService2,但走这么远应该足够了
var proxy=channelFactory.CreateChannel()作为IService2;
使用(新OperationContextScope((IContextChannel)代理))
{
var task=proxy.GetData(“某些数据”);//这里可能需要更多的工作才能知道基于Url调用哪个方法
task.Wait();
return task.Result;//序列化的JSON
}
}
猫