2016-04-07 69 views
1

我有两个完全不同的服务(以及他们的合同),它们具有完全不同的依赖关系以及完全不同的职责。然而,事情他们共同得到的都是:在一个服务主机内托管多个服务?

  • 他们需要打开/关闭一起
  • 它们共享相同的基地址
  • 它们具有相同的结合/运输

假合同:

public class IFoo { 
    void Foo(); 
} 

public class IBar { 
    void Bar(); 
} 

现在,我想要做的就是将它们托管在同一个服务主机中。我知道,它可能为端点暴露两种服务,并在这样的同种服务类型实现它们:

public class FooBar : IFoo, IBar { } 

var host = new ServiceHost(typeof(FooBar)); 

但是我正在寻找一个方式做这样的事情:

public class FooImpl : IFoo { } 

public class BarImpl : IBar { } 

var host = new ServiceHost(); 
host.AddEndpoint(typeof(FooImpl); 
host.AddEndpoint(typeof(BarImpl); 
host.Open(); 

所以我可以保持我的服务实现很好和整齐,每个都有自己的依赖关系,而不是一切的神对象。

任何人都有如何完成这个想法?

+0

您是否必须在同一个ServiceHost中托管两个服务,或者您是否愿意拥有多个ServiceHost实例,每个实例都有自己的服务和端点? –

+0

@WicherVisser不幸的是,并不是因为所有的服务都需要在同一个端口上运行。 – artganify

+0

[运行WCF ServiceHost与多个合同]可能的重复(http://stackoverflow.com/questions/334472/run-wcf-servicehost-with-multiple-contracts) –

回答

4

您可以托管多个ServiceHost,每个都有自己的服务和端点,全部共享相同的基地址和端口。下面是我的实现,封装到ServiceHosting类:

public class ServiceHosting<T1, T2> 
{ 
    //Declaration 
    protected ServiceHost SelfHost; 
    protected string BaseUrlString; 
    protected int Port; 
    protected string HostUrlString = ""; 
    protected bool ExtendedBinding; 

    //Constructor 
    public ServiceHosting(string url, int port, bool extendedBinding = false) 
    { 
     BaseUrlString = url; 
     Port = port; 
     ExtendedBinding = extendedBinding; 
    } 

    //Properties 
    protected int Max => int.MaxValue; 

    public virtual bool StartService(int port) 
    { 
     try 
     { 
      var hostName = System.Net.Dns.GetHostName(); 

      HostUrlString = [email protected]"net.tcp://{hostName}:{port}{BaseUrlString}"; //GM 10.09.2012: 

      try 
      { 
       SelfHost = new ServiceHost(typeof(T1), new Uri(HostUrlString)); 

       var smb = SelfHost.Description.Behaviors.Find<ServiceMetadataBehavior>() ?? 
          new ServiceMetadataBehavior() { }; 
       smb.MetadataExporter.PolicyVersion = PolicyVersion.Policy15; 

       SelfHost.Description.Behaviors.Add(smb); 

       var throttleBehavior = new ServiceThrottlingBehavior(); 
       SelfHost.Description.Behaviors.Add(throttleBehavior); 

       var mexUrlString = String.Format(@"net.tcp://{0}:{1}{2}/mex", hostName, port, BaseUrlString); 

       // Add MEX endpoint 
       SelfHost.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexTcpBinding(), new Uri(mexUrlString)); 

       // Add binding 
       var binding = ConfigureBinding(); 

       // Add application endpoint 
       SelfHost.AddServiceEndpoint(typeof(T2), binding, ""); 

       if (ExtendedBinding) 
       { 
        foreach (ServiceEndpoint ep in SelfHost.Description.Endpoints) 
        { 
         foreach (OperationDescription op in ep.Contract.Operations) 
         { 
          var dataContractBehavior = op.Behaviors[typeof(DataContractSerializerOperationBehavior)] as DataContractSerializerOperationBehavior; 

          if (dataContractBehavior != null) 
          { 
           dataContractBehavior.MaxItemsInObjectGraph = Max; 
          } 
         } 
        } 
       } 

       // Open the service host to accept incoming calls 
       SelfHost.Open(); 
      } 
      catch (CommunicationException) 
      { 
       // log 
       SelfHost.Abort(); 
       return false; 
      } 
      catch (Exception) 
      { 
       // log 
       SelfHost.Abort(); 
       return false; 
      } 

     } 
     catch (Exception) 
     { 
      // log 
      return false; 
     } 
     return true; 
    } 

    private NetTcpBinding BaseConfigureBinding() 
    { 
     return new NetTcpBinding 
     { Security = { Mode = SecurityMode.None }, CloseTimeout = new TimeSpan(0, 0, 0, 5) }; 
    } 

    protected virtual NetTcpBinding ConfigureBinding() 
    { 
     var binding = BaseConfigureBinding(); 

     if (ExtendedBinding) 
     { 
      binding.MaxBufferPoolSize = Max; 
      binding.MaxReceivedMessageSize = Max; 
      binding.MaxBufferSize = Max; 
      binding.MaxConnections = 200; //rdoerig 12-03-2013 default value is 10: 
      binding.ListenBacklog = 200; //rdoerig 12-03-2013 default value is 10 : buffer of pending connections 

      binding.ReaderQuotas.MaxDepth = Max; 
      binding.ReaderQuotas.MaxStringContentLength = Max; 
      binding.ReaderQuotas.MaxArrayLength = Max; 
      binding.ReaderQuotas.MaxBytesPerRead = Max; 
      binding.ReaderQuotas.MaxNameTableCharCount = Max; 

      binding.CloseTimeout = new TimeSpan(0, 0, 10, 0); 
      binding.OpenTimeout = new TimeSpan(0, 0, 10, 0); 
      binding.ReceiveTimeout = new TimeSpan(0, 0, 10, 0); 
      binding.SendTimeout = new TimeSpan(0, 0, 10, 0); 

     } 

     return binding; 
    } 

    public bool StopService() 
    { 
     try 
     { 
      SelfHost?.Close(); 
     } 
     catch (Exception) 
     { 
      // log 
      return false; 
     } 
     return true; 
    } 
} 

这可以被实例化,像这样:

 private readonly ServiceHosting<LoginService, ILoginService> _serviceHostLogin = new ServiceHosting<LoginService, ILoginService>(LoginUrl, true); 

启动/停止,就像这样:

  _serviceHostLogin.StartService(); 
      _serviceHostLogin.StopService(); 

为了确保您在托管多个服务时不会出错,您应该将服务的URI配置为不同,例如

new ServiceHosting<LoginService, ILoginService>("/Services/LoginService", true); 
new ServiceHosting<ConfigService, IConfigService>("/Services/ConfigService", true); 
+0

不知道这是如何解决OP的问题 - 仍然只有一个服务主机 –

+0

它不直接。从他的评论中我了解到OP他认为他不能为相同的地址+端口托管多个ServiceHost。我的例子表明这实际上是可能的。 –

+0

当您尝试在同一物理地址和端口上打开第二个服务主机时,您是否会收到错误消息?如果这个工作,我会非常惊讶 –

-1

您可以实现在同一个服务类两种接口,并有一个终点,而是用单独的合同:

[ServiceBehavior] 
public partial class IntegratedService 
{ 
    // You can implement "base" methods here 
} 

然后,实现每个接口:

public partial class IntegratedService : IFoo 
{ 
    // Implement IFoo interface 
} 

public partial class IntegratedService : IBar 
{ 
    // Implement IBar interface 
} 

希望它能帮助。

+0

正如我的问题所述,这正是我不想要的。在你的例子中,你基本上只是“分裂”这些类,但最终它仍然只是一个类。我需要有不同的类型,因为我需要为每个服务注入不同的依赖关系。 – artganify

+0

@artifyify允许每个端点只有一个服务,你想要的就像有两个不同的站点在IIS中具有相同的dns和相同的端口,你不能。我只是建议实现,因为在“基础”类中,您可以根据需要为这两种服务提供控制,例如同时启动一些代码,如果不是您正在寻找的对话,则很抱歉。 –

+0

@artganify我不得不同意RicardoPontual在这一个。根据您的要求,共享单个实施是WCF为您提供的唯一受支持的路线。你声明这些服务完全是意识形态上的独立,但你却在对它们施加人为限制,比如它们需要一起打开/关闭等。无论你的托管机制如何,这些都是单独的服务,应该这样对待。您可以将它们分开托管,然后将您的外围设备要求作为单独的问题处理 –