c# - 在一台服务主机中托管多个服务?

标签 c# .net wcf soap service

我有两个完全独立的服务(及其契约(Contract)),它们具有完全不同的依赖关系以及完全不同的职责。然而,他们的共同点是:

  • 它们需要一起打开/关闭
  • 它们共享相同的基址
  • 它们具有相同的绑定(bind)/传输

虚拟合约:

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();

这样我就可以让我的服务实现保持良好和整洁,每个服务都有自己的依赖项,而不是一个神对象来处理所有事情。

有人知道如何实现这一目标吗?

最佳答案

您可以托管多个 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);

关于c# - 在一台服务主机中托管多个服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36472319/

相关文章:

c# - 如何用一个字符替换文本文件中的所有空格?

c# - Rijndael 加密在 Windows Server 2012 上不起作用

c# - 在 .NET 中将数组转换为 HashSet<T>

.net - 在 WPF 中绑定(bind)对象的 List 属性的首选方法是什么?

wcf - WCF优质书籍推荐

c# - WCF 返回包含派生类的基类对象列表

c# - 错误 : 'this._targetEl.value.length' is null or not an object ASP. 网络

c# - 未绑定(bind)模型项时如何添加 ModelState.AddModelError 消息

javascript - OpenTok Api 广播视频在网页中的位置

wcf - 如何构建一个暴露业务层的 WCF 服务?