Another option: Store the data in the ServiceHost instead.
I tried various solutions suggested here, but I realized that if the data that you need to pass to your service instance is the same for all instances (as it is in the examples above), you might as well store that data in a subclass of ServiceHost instead of in your service class, and access the data via OperationContext.Current.Host
.
Here's an example that implements a generic custom service host class that takes a single item at construction time.
public class CustomServiceHost<CustomDataType> : ServiceHost
{
public readonly CustomDataType CustomData;
public CustomServiceHost(
CustomDataType customData,
Type serviceType,
params Uri[] baseAddresses)
: base(serviceType, baseAddresses)
{
CustomData = customData;
}
/// <summary>
/// Get the host data from the host that belongs to the current session.
/// </summary>
/// <remarks>
/// Notice that the "as" operator will return null if the
/// actual type of the host custom data doesn't match
/// and the attempt at accessing the custom data will
/// cause a null reference exception. Dealing with this
/// is left as an exercise for the reader. :-)
/// <remarks>
public static CustomDataType MyHostData()
=> (OperationContext.Current.Host as CustomServiceHost<CustomDataType>).CustomData;
}
Partial example of a service using the above custom service host:
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IMyService
{
// ...
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]
public class MyService : IMyService
{
/// <summary>
/// Parameter-less constructor required by WCF
/// <summary>
public MyService()
{
// Retrieve the custom data passed to the host constructor
// Note: The generic type (in this case string) must match
// the actual type that was used to create this service's
// host, otherwise a null reference exception will occur
var hostData = CustomServiceHost<string>.GetMyHostData();
Console.WriteLn($"{hostData}}");
}
}
public MyApplication
{
private readonly Binding _binding; // Initialization omitted
private readonly Uri _bindAddress; // Initialization omitted
public ServiceEndpoint SetupEndpoint<CustomDataType>(
CustomDataType customData,
Type serviceType,
Type implementedContract,
string address)
{
ServiceEndpoint result;
var serviceHost = new CustomServiceHost<CustomDataType>(
customData, serviceType, _bindAddress);
result = serviceHost.AddServiceEndpoint(
implementedContract, _binding, address);
serviceHost.Open();
return result;
}
public static int Main(string[] args)
{
// ...
// Clients that connect to the endpoint with URI ending in
// "myservice1" will get a service instance that sees
// "Hello from endpoint 1" as custom data in its host.
// Note that the C# container automatically infers
// string as the generic type of the first parameter.
var stringEndpoint1 = SetupEndpoint(
"Hello from endpoint 1", typeof(MyService), typeof(IMyService), "myservice1");
// Clients that connect to the endpoint with URI ending in
// "myservice2" will get a service instance that sees
// "Hello from endpoint 2" as custom data in its host.
var stringEndpoint2 = SetupEndpoint(
"Hello from endpoint 2", typeof(MyService), typeof(IMyService), "myservice2");
// ...
}
}