WCF, ServiceHost - CreateChannel, don't create new remote instance - c#

I got a usual WCF service set up like this:
private ServiceHost serviceHost = null;
protected override void OnStart(string[] args)
{
if (serviceHost != null)
serviceHost.Close();
Uri[] baseAddress = new Uri[]{
new Uri("net.pipe://localhost")};
string PipeName = "DatabaseService";
serviceHost = new ServiceHost(typeof(Kernel), baseAddress); // Kernel implements IDatabase
serviceHost.AddServiceEndpoint(typeof(IDatabase), new NetNamedPipeBinding(), PipeName);
serviceHost.Open();
}
protected override void OnStop()
{
if (serviceHost != null && serviceHost.State != CommunicationState.Closed)
{
serviceHost.Close();
serviceHost = null;
}
}
From this code, i guess, one instance of "Kernel" is created, because I got this service running only once.
I create a proxy Object using the ChannelFactory like this:
pipeFactory = new ChannelFactory<IDatabase>(new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/DatabaseService"));
m_Database = pipeFactory.CreateChannel();
I have to say, that my Kernel instance access a local file, and therefore it's very important I got only once physical instance of this class. I want my service to take care of that but here come's my problem.
While the service is running and a single channel is created and active, a second client comes up and wants to create a channel too. That works properly but if I start using the proxy Object a FaultException is thrown because a second instance of my Kernel class is created.
Therefore I'm guessing that an instance of the Kernel class is created by every CreateChannel call.
Is it possible to avoid the creation of a new instance and return always a reference to a single Kernel class instance when CreateChannel is called?
Regards,
inva

Yes, by default, WCF uses the per-session or per-call calling convention, e.g. each incoming service request from a client gets a new, separate instance of your service (implementation) class.
You can control this, of course, using things like the InstanceContextMode (PerSession is the default - at least on bindings that support it -, PerCall the recommended best practice, and Single is the Singleton) and the ConcurrencyMode settings on your service.
You can define these either in config, or directly on your service class.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class CalculatorService : ICalculatorInstance
{
...
}
See the MSDN documentation on WCF Sessions, Instancing and Concurrency for a great and extensive explanation of all details. Also read the excellent MSDN Magazine article Discover Mighty Instance Management Techniques For Developing WCF Apps by Juval Lowy, a great resource always!
If you do switch your service class to be a singleton (InstanceContextMode=InstanceContextMode.Single), you need to be aware of the two trade-offs:
either you define the ConcurrencyMode to also be Single, which effectively means only one single request can ever be handled at once; requests will be serialized, that is, if handling the request takes a fairly long time, subsequent requests will have to start waiting and might end up timing out
the other option is to set the ConcurrencyMode to Multiple, then your singleton service class can handle multiple requests at once; but this also means, you have to write your service class in a fully thread-safe manner and you need to synchronize and protect any concurrent access to shared data members - typically a very tricky and hard-to-do-right programming exercise

Related

Multiple WCF service contracts to share same session

I have two service contracts and they get implemented as one. Naturally, I'm creating two client proxies for those contracts. Is it possible to maintain session between these two proxies. (btw I'm just starting with WCF so cut me some slack if I'm being too dumb)
As an example,
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IFoo
{
[OperationContract]
void DoFoo(int something);
}
[ServiceContract(SessionMode = SessionMode.Required)]
public interface IBoo
{
[OperationContract]
int DoBoo();
}
[ServiceBehavior(InstanceContextMode =InstanceContextMode.PerSession)]
public class myservice: IFoo, IBoo
{
int somevalue;
void DoFoo(int something)
{
somevalue = something;
}
int DoBoo()
{
return somevalue;
}
}
Client Side Code:
using ServiceReference1;
static void main()
{
DoFooServiceClient fooproxy = new DoFooServiceClient();
DoBooServiceClient booproxy = new DoBooServiceClient();
fooproxy.DoFoo(5);
Console.WriteLine(booproxy.DoBoo());
}
I want it to return 5 but it returns 0. I know what's wrong, it is indeed creating two instances but is it possible to force them to use same instance? If I used static wouldn't it be the same value for all clients?
Since WCF instancing operates at the service contract level, you are going to struggle to share memory between only these two services.
Yes you could use a some static type but, as you say, the value would be synchronized across all service instances regardless, which is not the behavior you require.
An option would be to use some persistent resource like a database, or a singleton service instance, to store this shared data.
Another option may be possible, if you were to define Doo and Foo as singleton services for instancing. This would mean that you could access the state of each service directly from the service host, but would require some mediation logic to synchronize values between them.
I will try the mediation logic to sync values but that would require
additional client side code, wouldn't it?
It does not require client side code, but something on the service host to sync values between two service instances. I can only think of a way to do this if the services are both singleton instances. This becomes more complicated if you are using IIS for hosting, as this means you are not exposed to the actual ServiceHost instances.

WCF channel Factory caching

A WCF service will consume another Wcf service. Now, i want to create channel factory object and cache it manually. I know performance will be good but concern any other issue will be raised or not.
I have found info as follows:
"Using ChannelFactory you can still achieve channel factory caching with your own custom MRU cache. This still implies an important restriction: calls to the same service endpoint that share the channel factory must also share the same credentials. That means you can t pass different credentials for each thread calling application services from the Web server tier. One scenario where this is not an issue is if you use the same certificate or Windows credential to authenticate to downstream services. In this case, if you need to pass information about the authenticated user, you can use custom headers rather than a security token."
Link: http://devproconnections.com/net-framework/wcf-proxies-cache-or-not-cache
I have found a sample code in Google as follows.
internal delegate void UseServiceDelegate<in T>(T proxy);
internal static class Service<T>
{
private static readonly IDictionary<Type, string>
cachedEndpointNames = new Dictionary<Type, string>();
private static readonly IDictionary<string, ChannelFactory<T>>
cachedFactories =
new Dictionary<string, ChannelFactory<T>>();
internal static void Use(UseServiceDelegate<T> codeBlock)
{
var factory = GetChannelFactory();
var proxy = (IClientChannel)factory.CreateChannel();
var success = false;
try
{
using (proxy)
{
codeBlock((T)proxy);
}
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
private static ChannelFactory<T> GetChannelFactory()
{
lock (cachedFactories)
{
var endpointName = GetEndpointName();
if (cachedFactories.ContainsKey(endpointName))
{
return cachedFactories[endpointName];
}
var factory = new ChannelFactory<T>(endpointName);
cachedFactories.Add(endpointName, factory);
return factory;
}
}
private static string GetEndpointName()
{
var type = typeof(T);
var fullName = type.FullName;
lock (cachedFactories)
{
if (cachedEndpointNames.ContainsKey(type))
{
return cachedEndpointNames[type];
}
var serviceModel =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None)
.SectionGroups["system.serviceModel"] as ServiceModelSectionGroup;
if ((serviceModel != null) && !string.IsNullOrEmpty(fullName))
{
foreach (var endpointName in
serviceModel.Client.Endpoints.Cast<ChannelEndpointElement>()
.Where(endpoint => fullName.EndsWith(endpoint.Contract)).Select(endpoint
=> endpoint.Name))
{
cachedEndpointNames.Add(type, endpointName);
return endpointName;
}
}
}
throw new InvalidOperationException("Could not find endpoint element
for type '" + fullName + "' in the ServiceModel client
configuration section. This might be because no configuration file
was found for your application, or because no endpoint element
matching this name could be found in the client element.");
}
}
I am totally confused what should i do. Can anyone give me a best practice guideline?
This is a complex topic with a lot of details to go over, but here it goes.
First, as a general rule you should be caching a ChannelFactory and not an individual Channel. A ChannelFactory is expensive to construct as well as thread-safe so it is a great candidate for caching. A Channel is cheap to construct and it is generally recommended to only create channels on an as-needed basis and to close them as early as possible. Additionally, when you cache a Channel then you have to worry about it timing out which will cause it to fault which invalidates the entire benefit of caching it in the first place.
The article you linked to by Michele Leroux Bustamante is one of the best resources out there. As she states, there are differences to consider between Windows clients and server-side clients. Mostly only Windows clients benefit from caching as typically the credentials differ from thread to thread on server-side clients. For your typical Windows clients, there are two main options: Caching the references yourself or leveraging the MRU cache.
Leveraging the MRU cache: Essentially this means that you are letting Microsoft take the wheel. The ClientBase class will use an MRU cache for the internal ChannelFactory instance. The caching behavior is controlled via a CacheSetting property and by default caching will be disabled if any of the "security-sensitive" properties are accessed. ClientBase properties which will invalidate and remove a ChannelFactory from the MRU cache when accessed include the Endpoint, ClientCredentials or the ChannelFactory itself. There is a way to override this behavior by setting the CacheSettings property to CacheSettings.AlwaysOn. Additionally, if the Binding is run-time defined then the ChannelFactory is no longer a candidate for the MRU cache. See more details here.
Caching the references yourself: This means that you are going to keep a collection of ChannelFactory references yourself. The snippet you provide in your question uses this approach. The best approach I have ever seen and admittedly use a modified version of at work is by Darin Dimitrov via this related SO question. For those of us who like to have more fine-grained control over the caching mechanism then this is the approach to use. This is typically used when credentials must be set at run-time like is often required by internet services.
Quite similarly, client proxies can be cached to improve performance - Wenlong Dong has an article about this topic.
(Update) Server-side clients as noted before are quite limited in their options when it comes to ChannelFactory caching. For this brief discussion, we will assume that our deployment scenario looks like this:
Client -> Service A -> Service B
The most likely method to use in order to leverage ChannelFactory caching in this scenario is to cache the references yourself for the session between the Client and Service A. This way Service A does not have to construct a different ChannelFactory instance every time Service A needs to call into Service B. However, if the properties of the ChannelFactory need change for each call, then this is no longer going to be appropriate.
Of course this also holds if Service A is a Singleton and each call to the downstream service (Service B) does not require new credentials, but Singleton services have their own set of performance problems.

wcf interface: why doesn't it 'just' go to the methode but to the whole class

I have WCF service implemented and the connection works just fine. I use BasicHttpBinding.
[ServiceContract]
public interface IScannerInput
{
[OperationContract]
string ScannedPRX(string barcode, string user, int color);
}
public class ProcessPRX : IScannerInput
{
ProcessClass c = new ProcessClass(); // every time a call ScannedPRX() this class is made again
public string ScannedPRX(string barcode, string user, int color)
{
c.PrxScannedInput(barcode, user, color);
return "Bussy processing: " + barcode;
}
}
In a normal class I can just make ProcessClass c one time. But now it is made again and again every time a call the methode ScannedPRX(). What am I doing wrong? It is not just going to the methode but to the whole class.
There is three ways of instantiating WCF service object:
PerCall: A new InstanceContext (and therefore service object) is created for each client request.
PerSession: A new InstanceContext (and therefore service object) is created for each new client session and maintained for the lifetime of that session (this requires a binding that supports sessions).
Single: A single InstanceContext (and therefore service object) handles all client requests for the lifetime of the application.
PerCall is default one, and that is what you are having.
If you want other behaviour read article below.
http://msdn.microsoft.com/en-us/library/ms731193.aspx
Take into account concurrent request that are made to your service, as if you are choosing for instance Single instantiation mode, you need to take care on your own that all your methods are thread safe.
Because the default instancing behavior for WCF services is to create a new instance for every call. You generally want this to avoid sharing state between different callers of your service or multiple invocations by the same client. Unless ProcessClass is expensive to create or you need to maintain state between calls, I would stick with this model.

Dealing with concurrency and complex WCF services interacting with objects of the overall application

I am enjoying creating and hosting WCF services.
Up until now I can create services defining contracts for the service and data (interfaces) and defining hosts and configuration options to reach them (endpoint specifications).
Well, consider this piece of code defining a service and using it (no mention for endpoints that are defined in app.config not shown here):
[ServiceContract]
public interface IMyService {
[OperationContract]
string Operation1(int param1);
[OperationContract]
string Operation2(int param2);
}
public class MyService : IMyService {
public string Operation1(int param1) { ... }
public string Operation2(int param2) { ... }
}
public class Program {
public static void Main(stirng[] args) {
using (ServiceHost host = new ServiceHost(typeof(MyService))) {
host.Open();
...
host.Close();
}
}
}
Well, this structure is good when creating something that could be called a Standalone service.
What if I needed my service to use objects of a greater application.
For example I need a service that does something basing on a certain collection defined somewhere in my program (which is hosting the service). The service must look into this collection and search and return a particular element.
The list I am talking about is a list managed by the program and edited and modified by it.
I have the following questions:
1) How can I build a service able to handle this list?
I know that a possible option is using the overloaded ServiceHost constructor accepting an Object instead of a Type service.
So I could pass my list there. Is it good?
[ServiceContract]
public interface IMyService {
[OperationContract]
string Operation1(int param1);
[OperationContract]
string Operation2(int param2);
}
public class MyService : IMyService {
private List<> myinternallist;
public MyService(List<> mylist) {
// Constructing the service passing the list
}
public string Operation1(int param1) { ... }
public string Operation2(int param2) { ... }
}
public class Program {
public static void Main(stirng[] args) {
List<> thelist;
...
MyService S = new MyService(thelist)
using (ServiceHost host = new ServiceHost(S)) {
host.Open();
...
host.Close();
// Here my application creates a functions and other that manages the queue. For this reason my application will edit the list (it can be a thread or callbacks from the user interface)
}
}
}
This example should clarify.
Is it the good way of doing? Am I doing right?
2) How to handle conflicts on this shared resource between my service and my application?
When my application runs, hosting the service, my application can insert items in the list and delete them, the same can do the service too. Do I need a mutex? how to handle this?
Please note that the concurrency issue concerns two actors: the main application and the service. It is true that the service is singleton but the application acts on the list!!!
I assume that the service is called by an external entity, when this happens the application still runs right? Is there concurrency in this case???
Thankyou
Regarding point 2, you can use Concurrent Collections to manage most of the thread safety required.
I'm not sure what you mean by point 1. It sounds like you're describing basic polymorphism, but perhaps you could clarify with an example please?
EDIT: In response to comments you've made to Sixto's answer, consider using WCF's sessions. From what you've described it sounds to me like the WCF service should be sat on a seperate host application. The application you are using currently should have a service reference to the service, and using sessions would be able to call an operation mimicking your requirement for instantiating the service with a list defined by the current client application.
Combine this with my comment on exposing operations that allow interaction with this list, and you'll be able to run multiple client machines, working on session stored Lists?
Hope that's explained well enough.
Adding the constructor to MyService for passing the list certainly will work as you'd expect. Like I said in my comment to the question however, the ServiceHost will only ever contain a single instance of the MyService class so the list will not be shared because only one service instance will consume it.
I would look at a dependency injector (DI) container for WCF to do what you are trying do. Let the DI container provide the singleton list instance to your services. Also #Smudge202 is absolutely correct that using the Concurrent Collection functionality is what you need to implement the list.
UPDATE based on the comments thread:
The DI approach would works by getting all of an object's dependencies from the DI container instead of creating them manually in code. You register all the types that will be provided by the container as part of the application start up. When the application (or WCF) needs a new object instance it requests it from the container instead of "newing" it up. The Castle Windsor WCF integration library for example implements all the wiring needed to provide WCF a service instance from the container. This posts explains the details of how to use the Microsoft Unity DI container with WCF if you want to roll your own WCF integration.
The shared list referenced in this question would be registered in the container as an already instantiated object from your application. When a WCF service instance is spun up from the DI container, all the constructor parameters will be provided including a reference to the shared list. There is a lot of information out there on dependency injection and inversion of control but this Martin Fowler article is a good place to start.

How do I get a reference to a WCF service object from the code that creates it?

I'm modifying the code in this tutorial to build some basic subscribe push wcf client/server classes, and I've just hit a bit of a brick wall.
The server class in the tutorial is created using the following code:
class Program
{
static void Main(string[] args)
{
using (ServiceHost host = new ServiceHost(
typeof(StringReverser),
new Uri[]{
new Uri("net.pipe://localhost")
}))
{
host.AddServiceEndpoint(typeof(IStringReverser),
new NetNamedPipeBinding(),
"PipeReverse");
host.Open();
Console.WriteLine("Service is available. " +
"Press <ENTER> to exit.");
Console.ReadLine();
host.Close();
}
}
}
Which I assume publishes an instance of StringReverser my problem is I need a reference to that instance so I can call a method on it to push data back to the client.
In the tutorial the server just replies to the client using a callback method, instead I'm storing a reference to the client in a list of subscribers. When I need to push data back to the clients I need a reference to the Service object so I can actually utilize do the callback.
Is there a way to publish a Service using WCF that lets you have a reference to the service object? or can I get a reference to the service object from the host object?
Any help would be appreciated...
You can use the singleton pattern in your StringReverser class and pass the instance of it to the ServiceHost constructor:
ServiceHost host = new ServiceHost(
StringReverser.Instance,
new Uri[]{new Uri("net.pipe://localhost")}
);
I agree that Julien's answer is the correct approach, but it is incomplete (at least for .NET 4.5). After you pass in the instance of the service, you have to set the instance context mode for the ServiceHost to Single. If you don't do that, you'll get an error when the ServiceHost Open() method is called.
The way to set the context mode was not at all obvious. Here is a fragment from one of my programs, taken from a different SO answer:
var baseAddress = new Uri("http://localhost:15003/MockGateway");
using (var host = new ServiceHost(new MockGatewayService(), baseAddress))
{
// Since we are passing an instance of the service into ServiceHost (rather
// than passing in the type) we have to set the context mode to single.
var behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>();
behavior.InstanceContextMode = InstanceContextMode.Single;
// Continue to use the service here. If you ever need to get a reference
// to the service object you can do so with...
MockGatewayService myService = host.SingletonInstance as MockGatewayService;
// ...
}
in your servicecontract you can call
OperationContext.Current.GetCallbackChannel());
in any method that is called after the service connects, and then pass it out of the service contract. I typically have a join method where I get a guid for the client and grab the callback there. This is harder than it seems. You either need a singleton/global variable to get it out (easy), or you need to make it so that WCF can use parameterized constructors (hard). For the latter, more correct way of doing it, you need to roll your own classes that implement IInstanceProvider and IEndPointBehavior and add your behavior to the endpoint you are interested in. This has the added benefit of allowing you to use different constructors with different endpoints without redefining your contract. There is unfortunately no typesafe way to do this as you will have to use reflection. Sorry I can't provide a sample, but everything I have is proprietary.

Categories

Resources