以下是我目前使用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);
}
}
答案 0 :(得分:1)
问题在于我指的是ServiceEndpoint中类的类型。 这应该是ServiceContract的接口。
我最初拥有的东西:
ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(serviceType, binding, string.Empty);
应该是:
ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(serviceInterfaceType, binding, string.Empty);
其中serviceInterfaceType是包含ServiceContract的接口的类型。