我有两个完全独立的服务(以及他们的合同),这些服务具有完全不同的依赖关系以及完全不同的职责。然而,他们共同的事情是:
虚拟合同:
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 :(得分:4)
您可以托管多个ServiceHost,每个ServiceHost都有自己的服务和端点,所有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 = $@"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);
答案 1 :(得分:-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
}
希望它有所帮助。