On my team, we have been working with wcf in service fabric these days. Firstly, We tried to use WcfCommunicationListener form Microsoft.ServiceFabric.Services.Wcf but finally we decide to use our own implementation of ICommunicationListener in order to have a better control over the service host. We also use net.tcp as binding instead of http. We defined behaviors and endpoints programatically, not using app.config.
I am going to share our approach. Hope this can help you.
First step, the ICommunicationListener implementation:
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;
});
}
}
Second step, create instance of the listener inside CreateServiceInstanceListeners inside our Service Fabric Service. Here is where I created a service host instance, its endpoints and behaviours.
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);
}
Here is the configuration file, in case you have any doubts about it. We storage it inside PackageRoot-Config folder.
{
"Network": {
"BaseAddress": "localhost:1020/SampleService/",
"ServiceAddress": "service",
"MetadataAddress": "mex"
},
"ServiceBehavior": {
"ServerCertificate": {
"Store": "LocalMachine",
"FindType": "FindBySubjectDistinguishedName",
"FindValue": "CN=mycert.deploy.com"
},
"ServerDebug": {
"IncludeExceptionDetailInFaults": true
}
}
}