自托管WCF服务,带有MEF和NetTcpBinding,用于推拉机制

时间:2014-03-11 21:21:40

标签: c# wcf mef publish-subscribe self-hosting

以下是我目前使用NetTcpBinding和MEF在Windows服务中用于自托管WCF服务的所有代码。到目前为止,这适用于提取数据。但是,当我尝试添加推送数据的服务时,此代码不起作用。该问题是由包含WCF服务的程序集引起的。对于推送机制,我需要在接口而不是类本身上使用ServiceContract和OperationContract属性。

不幸的是,该服务不接受该接口,并且需要在该类上设置属性。其他不起作用的是在特定接口的接口上继承默认接口。

我目前对如何解决这个问题感到有些困惑。我的编程技巧不是那么先进。有人可以帮助我或指出一篇可以给我一些指导的文章吗?

在进行一些搜索时,我遇到了一些关于创建自定义ServiceHost和ServiceHostFactory的文章。这是如何运作的?大多数文章似乎更复杂,然后我需要。

我希望我已经提供了所需的所有信息。如果没有,我将很乐意尝试回答更多信息的请求。

用于加载WCF服务的BootStrapper:

    internal class Bootstrapper
    {
        [ImportMany(typeof(IWcfSvc))]
        internal IEnumerable<IWcfSvc> Services { get; set; }
    }

这是每个WCF服务应具有的默认接口:

    [InheritedExport]
    public interface IWcfSvc
    {
        string Name { get; }
        void Init();
    }

加载WCF服务的MEF类:

        private void Load()
        {
            Bootstrapper bootStrapper = new Bootstrapper();
            AggregateCatalog catalog = new AggregateCatalog();

            catalog.Catalogs.Add(new DirectoryCatalog(this.PluginPath));
            CompositionContainer container = new CompositionContainer(catalog, CompositionOptions.DisableSilentRejection);

            try
            {
                container.ComposeParts(bootStrapper);
            }
            catch (CompositionException ex)
            {
                this.log.Error("CompositionException", ex);
            }

            List<string> svcNames = new List<string>();
            foreach (var service in bootStrapper.Services)
            {
                if (svcNames.Count(c => c == service.Name) == 0)
                {
                    service.Init();
                    Type serviceType = service.GetType();
                    Uri address = new Uri(string.Format(URI, this.Host, this.Port, service.Name));
                    this.wcfLoader.CreateWcfService(serviceType, address);
                    svcNames.Add(service.Name);
                }
                else
                {
                    this.log.Warn(string.Format("Tried to load {0} multiple times, which was refused.", service.Name));
                }
            }
        }
    }

启动WCF服务的类:

        private NetTcpBinding netTcpBinding
        {
            get
            {
                return new NetTcpBinding()
                {
                    MaxBufferSize = int.MaxValue,
                    MaxReceivedMessageSize = int.MaxValue,
                    MaxBufferPoolSize = long.MaxValue,
                    CloseTimeout = new TimeSpan(0, 2, 0),
                    OpenTimeout = new TimeSpan(0, 2, 0),
                    ReceiveTimeout = new TimeSpan(0, 2, 0),
                    SendTimeout = new TimeSpan(0, 2, 0),
                    Security = new NetTcpSecurity()
                    {
                        Mode = SecurityMode.TransportWithMessageCredential,
                        Transport = new TcpTransportSecurity() { ClientCredentialType = TcpClientCredentialType.Certificate },
                        Message = new MessageSecurityOverTcp() { ClientCredentialType = MessageCredentialType.UserName }
                    }
                };
            }
        }

        internal void CreateWcfService(Type serviceType, Uri address)
        {
            Action<string> StoreAddress = delegate(string addr)
            {
                string addrLine = string.Format(ADDRLINE, addr.EndsWith(URLSEPARATOR + MEX, StringComparison.CurrentCultureIgnoreCase) ? MEXBINDING : BINDING, addr);
                this.log.Info(addrLine);
            };

            try
            {
                CustomBinding binding = new CustomBinding(this.netTcpBinding);
                BindingElementCollection bec = binding.Elements;
                foreach (var be in bec)
                    if (be is TcpTransportBindingElement)
                        (be as TcpTransportBindingElement).ConnectionPoolSettings.LeaseTimeout = TimeSpan.FromSeconds(this.LeaseTimeOut);

                ServiceHost serviceHost = new ServiceHost(serviceType, address);
                serviceHost.Credentials.ServiceCertificate.SetCertificate(StoreLocation.LocalMachine, StoreName.My, X509FindType.FindByIssuerName, this.CertIssuerName);
                ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(serviceType, binding, string.Empty);
                endpoint.Address = new EndpointAddress(address, EndpointIdentity.CreateDnsIdentity(this.Host));

                ServiceMetadataBehavior serviceMetadataBehavior = new ServiceMetadataBehavior();
                serviceHost.Description.Behaviors.Add(serviceMetadataBehavior);
                serviceHost.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexTcpBinding(), MEX);

                ServiceDebugBehavior svcDebugBehavior = serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
                if (svcDebugBehavior == null)
                    serviceHost.Description.Behaviors.Add(new ServiceDebugBehavior());
                svcDebugBehavior.IncludeExceptionDetailInFaults = this.Debug;

                serviceHost.Opening += (sender, e) => this.serviceHost_State(sender, e, serviceHost, ActionState.Opening);
                serviceHost.Opened += (sender, e) => this.serviceHost_State(sender, e, serviceHost, ActionState.Open);
                serviceHost.Closing += (sender, e) => this.serviceHost_State(sender, e, serviceHost, ActionState.Closing);
                serviceHost.Closed += (sender, e) => this.serviceHost_State(sender, e, serviceHost, ActionState.Closed);

                serviceHost.Open();

                serviceHost.Description.Endpoints.ToList().ForEach(f => StoreAddress(f.Address.Uri.AbsoluteUri));
                this.serviceHosts.Add(serviceHost);
            }
            catch (Exception ex)
            {
                this.log.Error("Could not load WCF service...", ex);
            }
        }

使用提取机制的WCF服务示例:

        [OperationContract]
        public List<BillOfMaterials> GetBillOfMaterials(int startProductID, DateTime checkDate)
        {
            using (DbAccess db = new DbAccess())
            {
                List<SqlParameter> parms = new List<SqlParameter>();
                parms.Add(new SqlParameter()
                {
                    DbType = DbType.Int32,
                    Direction = ParameterDirection.Input,
                    ParameterName = "StartProductID",
                    Value = startProductID
                });
                parms.Add(new SqlParameter()
                {
                    DbType = DbType.DateTime,
                    Direction = ParameterDirection.Input,
                    ParameterName = "CheckDate",
                    Value = checkDate
                });

                return db.GetData<BillOfMaterials>("uspGetBillOfMaterials", parms);
            }
        }

1 个答案:

答案 0 :(得分:1)

问题在于我指的是ServiceEndpoint中类的类型。 这应该是ServiceContract的接口。

我最初拥有的东西:

    ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(serviceType, binding, string.Empty);

应该是:

    ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(serviceInterfaceType, binding, string.Empty);

其中serviceInterfaceType是包含ServiceContract的接口的类型。