试图在服务结构中使用wcf建立一个有状态的可靠服务,我复制了以下示例代码:
protected override IEnumerable<ServiceReplicaListener> CreateServiceReplicaListeners()
{
return new[] { new ServiceReplicaListener((context) =>
new WcfCommunicationListener<IService1>(
wcfServiceObject:this,
serviceContext:context,
endpointResourceName: "ServiceEndpoint",
listenerBinding: WcfUtility.CreateTcpListenerBinding()
)
)};
在ServiceManifest.xml中,我声明了端点:
<Resources>
<Endpoints>
<Endpoint Name="ServiceEndpoint" Protocol="http" Port="8100" />
<Endpoint Name="ReplicatorEndpoint" />
</Endpoints>
</Resources>
但是,当我部署到本地集群,并在ServiceFabricExplorer中查看服务运行的节点时,端点的地址是:
net.tcp://localhost:8100/455d1c74-7734-449b-a567-47b749b3b822/88af6851-0285-4989-b0aa-c0cbe8c2d06a-131056235989980581
如何获取http地址?
在我的团队中,这些天我们一直在服务结构中使用wcf。首先,我们尝试使用Microsoft.ServiceFabric.Services.Wcf形式的WcfCommunicationListener,但最终我们决定使用我们自己的ICommunicationListener实现,以便更好地控制服务主机。我们还使用net.tcp作为绑定,而不是http。我们用程序定义了行为和端点,而不是使用app.config。我将分享我们的方法。希望这能帮助到你。
第一步,ICommunicationListener实现:
public class ServiceHostCommunicationListener : ICommunicationListener
{
private string baseAddress;
public ServiceHost Host { get; set; }
public ServiceHostCommunicationListener(ServiceHost host, string baseAddress)
{
Host = host;
this.baseAddress = baseAddress;
}
public void Abort()
{
Host.Abort();
}
public async Task CloseAsync(CancellationToken cancellationToken)
{
try
{
await Task.Factory.FromAsync(Host.BeginClose(null, null), ar =>
{
Host.EndClose(ar);
});
}
catch (Exception)
{
Host.Abort();
}
}
public Task<string> OpenAsync(CancellationToken cancellationToken)
{
return Task.Factory.FromAsync(Host.BeginOpen(null, null), ar =>
{
Host.EndOpen(ar);
return baseAddress;
});
}
}
第二步,在我们的Service Fabric Service中的CreateServiceInstanceListeners中创建侦听器的实例。这里是我创建服务主机实例的地方,它的端点和行为。
protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
{
yield return new ServiceInstanceListener(context =>
{
return CreateListener(context);
});
}
private ICommunicationListener CreateListener(StatelessServiceContext context)
{
Uri baseUri = new Uri($"net.tcp://{configuration.Network.BaseAddress}");
ServiceHost serviceHost = new ServiceHost(new SampleService(), baseUri);
InitServiceDebugBehavior(serviceHost);
if (configuration.Network.MetadataAddress != null)
{
AddMetadataEndpoint(baseUri, serviceHost);
}
InitServerCertificate(serviceHost);
AddServiceEndpoint(serviceHost);
return new ServiceHostCommunicationListener(serviceHost, baseUri.AbsoluteUri);
}
private void InitServiceDebugBehavior(ServiceHost host)
{
var serviceDebug = host.Description.Behaviors.Find<ServiceDebugBehavior>();
if (serviceDebug == null)
{
serviceDebug = new ServiceDebugBehavior();
host.Description.Behaviors.Add(serviceDebug);
}
serviceDebug.IncludeExceptionDetailInFaults = configuration.ServiceBehavior.ServerDebug.IncludeExceptionDetailInFaults;
}
private void AddMetadataEndpoint(Uri baseUri, ServiceHost serviceHost)
{
ServiceMetadataBehavior smb = serviceHost.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
serviceHost.Description.Behaviors.Add(smb);
}
serviceHost.AddServiceEndpoint(
ServiceMetadataBehavior.MexContractName,
MetadataExchangeBindings.CreateMexTcpBinding(),
configuration.Network.MetadataAddress
);
}
private void InitServerCertificate(ServiceHost host)
{
var serverCertificateConfig = configuration.ServiceBehavior.ServerCertificate;
host.Credentials.ServiceCertificate.SetCertificate(
serverCertificateConfig.Store,
StoreName.My,
serverCertificateConfig.FindType,
serverCertificateConfig.FindValue
);
}
private void AddServiceEndpoint(ServiceHost serviceHost)
{
var binding = new NetTcpBinding(SecurityMode.Transport);
binding.Security.Transport.ClientCredentialType = TcpClientCredentialType.Certificate;
serviceHost.AddServiceEndpoint(typeof(SampleService), binding, configuration.Network.ServiceAddress);
}
这是配置文件,以防您对此有任何疑问。我们将其存储在PackageRootConfig文件夹中。
{
"Network": {
"BaseAddress": "localhost:1020/SampleService/",
"ServiceAddress": "service",
"MetadataAddress": "mex"
},
"ServiceBehavior": {
"ServerCertificate": {
"Store": "LocalMachine",
"FindType": "FindBySubjectDistinguishedName",
"FindValue": "CN=mycert.deploy.com"
},
"ServerDebug": {
"IncludeExceptionDetailInFaults": true
}
}
}
在这个例子中,我唯一能想到的就是手动创建Http绑定:
BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.None)
{
SendTimeout = TimeSpan.MaxValue,
ReceiveTimeout = TimeSpan.MaxValue,
OpenTimeout = TimeSpan.FromSeconds(5),
CloseTimeout = TimeSpan.FromSeconds(5),
MaxReceivedMessageSize = 1024 * 1024
};
binding.MaxBufferSize = (int)binding.MaxReceivedMessageSize;
binding.MaxBufferPoolSize = Environment.ProcessorCount * binding.MaxReceivedMessageSize;
return binding;
通过该绑定,地址是服务结构浏览器中的http