Using a WCF service to share information across clients - c#

I'm trying to develop a system to share information across 2 windows applications with different update loops.
I developed a solution that uses a WCF service to store and retrieve data. However this data is different across clients and therefore showing different values for each applications.
The service I tried to implement are similar to this
namespace TEST_Service_ServiceLibrary
{
[ServiceContract]
public interface TEST_ServiceInterface
{
[OperationContract]
string GetData();
[OperationContract]
void StoreData(string data);
}
}
namespace TEST_Service_ServiceLibrary
{
// Core service of the application, stores and provides data:
public class TEST_Service : TEST_ServiceInterface
{
string TEST_string;
// Used to pull stored data
public string GetData()
{
return TEST_string;
}
// Used to store data
public void StoreData(string data)
{
TEST_string = data;
}
}
}
Each of the applications creates a TEST_Service client.
I tested the GetData and StoreData functions and they work fine independently, however when I use StoreData on one application and test the GetData method from the other the data appears to be empty.
I have looked around but haven't found a solution to this problem, is there a work around for this? or should I change my approach? I thought of using a local data base but I'm not sure this is the best way to solve it
Thanks a lot

You have more than one instance of your service class. If you want to have your data in memory, you will need to run it in single instance mode:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
Now keeping your data in memory might not be the best option anyway. You should look for a data store of some kind and then make that store a persistent instance with a single interface. Then it does not matter how many of your service instances are used.

If your WCF service was storing information in a database, then information stored on one request would go to the database, and when another request retrieved it, the result would come from that database. So if one client stored something, another could retrieve it.
The reason why this isn't working is because in response to each request your application is creating a new instance of the TEST_Service class. That means TEST_string, where you are storing values between requests, is a new string. It doesn't contain the previous value.
For experimentation you could try changing the string to static:
static string TEST_string;
...and then the value would persist between instances of the service class. But that still wouldn't be effective because your WCF service could be deployed to multiple servers, and then each one would have a separate instance of the class. Updating one wouldn't update the others. Or, if the service application restarted then the value would be lost. (From the context I assume that you're just experimenting with this.)
So ultimately you'd want some way to persist data that wouldn't depend on any of those factors, but would "survive" even when the instance of the service class goes out of scope or the application shuts down.

Related

How to deal with WCF connection failing

Let's imagine I have WCF service and a client that consumes some methods from a given service.
There are tons of posts of how to handle various exceptions during the client and service communication. Only thing which is still confusing me is a following case:
Service:
[ServiceContract]
public interface IService1
{
[OperationContract]
bool ExportData(object data);
}
public class Service1 : IService1
{
public bool ExportData(object data)
{
// Simulate long operation (i.e. inserting data to the DB)
Thread.Sleep(1000000);
return true;
}
}
Client:
class Program
{
static wsService1.Service1Client client1 = new wsService1.Service1Client();
static void Main(string[] args)
{
object data = GetRecordsFromLocalDB();
bool result = client1.ExportData(data);
if (result)
{
DeleteRecordsFromLocalDB();
}
}
}
Client gets some data from local db and sending it to the server. If result is successful, then client is going to remove exported rows from local DB. Now imagine, when data is already sent to the server, suddenly connection failed (i.e. WiFi was disconnected). In this case data is successfully processed on a server side, but client is never know about it. And yes, I can catch connection exception, but still I don't know what should I do with a records in my local DB. I can send this data again later, but I'll get some duplication on a server DB (i.e. duplication is allowed on remote DB), but I don't want to send same data multiple times.
So, my question is how to handle such cases? What is the best practices?
I checked some info about asynchronous operations. But still this is about when I have stable connection.
As a workaround I can store my export operation under some GUID remotelly and check status for this GUID later. Only thing I can't change remote DB. So, please, suggest what would be better in my case?
Here are some points to consider
On server side you can catch all kinds of error (custom class deriving IErrorHandler) and provide specific error to client letting him know about error's reason.
The concept of service is that it is kind of intermediary between client and database so why would client retrieve data and then send it to service?
One way out is to use transaction which assures that if error occurres then no changes are going to be retained.
By the way, If you expect service to throw an exception do not create global service object since it will end up being in faulted state. Create new instance for every single call instead (make use of using statement so as to dispose its instance). Bool return type does not provide extensive information about the error if any takes place. Let it have void return type and wrap in try/catch block which gives a change to learn more about the source and nature of error.

Does WCF Run the session on more than one thread?

I have a wcf service (hosted in IIS) that is setup to use sessions. It seems to work. When Application_PostAcquireRequestState is called I have a session ID.
I end up using it like this (in my Global.asax):
if (Context.Handler is IRequiresSessionState)
{
log4net.ThreadContext.Properties["sessionId"] = Session.SessionID;
}
That seems to work fine. The value is stored off into my log4net property.
But when my service operation begins (my actual WCF service code) the log4net property is null again.
Since the property is stored per thread (ThreadContext), I can only assume that this means that the session is setup on one thread then executed on another thread. Am I right?
Is there anyway to get my log4net property set on the on the correct thread (without having to remember to make the above call at the start of every single service operation)?
Yes, IIS may use multiple thread to service multiple WCF requests. See http://msdn.microsoft.com/en-us/library/cc512374.aspx for more detail.
You might consider using different instances of a logger for each WCF request.
There are multiple scenarios where WCF might change threads on you:
The Global.asx thread is not guaranteed to be used for a service call (in fact its unlikely).
If there are multiple calls during the same session, the thread may also change between calls to the same service instance.
In theory state information like this should be stored in an Operation Context object. However because log4net uses thread local storage it becomes an awkward solution.
Is there anyway to get my log4net property set on the on the correct
thread (without having to remember to make the above call at the start
of every single service operation)?
Yes. Create a custom IOperationInvoker. The best example I know of is Carlos Figueira's blog. If you apply this as a service behavior your log4net property should always be defined for the service code.
One warning: When adding to thread local storage be sure to clean up. That's why log4net.ThreadContext.Stacks[].Push() returns a IDisposable. In other words your Invoke method should look like (incomplete and untested):
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
using (log4net.ThreadContext.Stacks[key].Push(value))
{
return this.originalInvoker.Invoke(instance, inputs, out outputs);
}
}
See Carlos' blog to understand why you are calling the "originalInvoker". Note that if you want to support async operations that you need to implement additional methods.
Custom properties do not need to be strings. So you could store an instance of the following class in the global context:
public class SessionIdProperty
{
public override string ToString()
{
// error handling omitted
return Session.SessionID;
}
}
This way log4net can access the Session object directly when it logs a message. Log4net calls the ToString() method on non-string properties.

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.

How to share static object across processes in WCF?

Background:
I asked this question about creating a cached provider structure for my WCF service. I've implemented that design now, but what I've noticed in testing, is that the providers aren't actually being cached. How do I know this? I added the following debug-level logging to my service:
private static readonly IDictionary<string, XmlLoaderProviderBase> _providerDictionary =
new Dictionary<string, XmlLoaderProviderBase>();
public void Load(LoadRequest loadRequest)
{
XmlLoaderProviderBase xmlLoader;
if (_providerDictionary.ContainsKey(loadRequest.TransferTypeCode))
{
// Use cached provider...
xmlLoader = _providerDictionary[loadRequest.TransferTypeCode];
Logger.Log.DebugFormat("Found cached provider: {0} for transfer type: {1}",
xmlLoader.GetType(), loadRequest.TransferTypeCode);
}
else
{
// Instantiate provider for the first time; add provider to cache...
xmlLoader = XmlLoaderProviderFactory.CreateProvider(loadRequest.TransferTypeCode);
_providerDictionary.Add(loadRequest.TransferTypeCode, xmlLoader);
Logger.Log.DebugFormat("Instantiating provider: {0} for transfer type: {1}",
xmlLoader.GetType(), loadRequest.TransferTypeCode);
}
xmlLoader.Load(loadRequest);
}
And what I notice, is that no matter how many times I call the service, a provider is always instantiated (it never finds the cached version). Thankfully log4net is pretty helpful, and it shows that each call to the service runs in it's own unique process (i.e. it has a unique process ID). So as is, the providers will never be cached. How can I get this to actually cache providers, and read that dictionary across processes? Is this even possible?
I also read similar questions to this here on SO, and I notice the InstanceContextMode setting. I don't think I want this, because I think that will hurt performance (am I wrong? way off?) In a nut shell, my desire is to share the _providerDictionary across all processes/service instances... please help!
I'm going to steal #slfan's comment:
Use
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode=InstanceContextMode.Single)]
Default InstanceContextMode is PerSession.
I would look into creating a custom caching framework using System.Runtime.Caching.ObjectCache / MemoryCache. To my knowledge this should be accessible across processes. It is also threadsafe.
See the following links:
http://technovivek.blogspot.com/2013/08/c-in-memory-cache-using-net-40-object.html
http://www.codeproject.com/Articles/290935/Using-MemoryCache-in-Net

How to separate the layer of the communication and processing?

I created an application that provides several services. Each service provides a specific processing capabilities, except one service (that is the main service) that returns true or false to the clients which request if the specified processing capabilities is available or not.
Now I would modify the application, leaving the main service unchanged and adding the support for the installation of plugin with new processing capabilities: each plugin should add new processing capabilities without the need of implement a new service, but after installing the new plugin, a new service should be avaible. In this way, a plugin should not handle the communication layer. In other words, I would like to separate the layer of the communication and processing, in order to simplify the creation of new plugins.
Is it possible?
I could create two services: the main service and the service for processing.
The first service may be used by clients to know if a certain feature is present on the server (for example, clients may ask the server if it has installed the plugin that provides the functionality for solving differential equations).
The second service could be used to send a generic task and to receive a general result, for example:
Result executeTask(Task task);
where Result and Task are abstract classes...
For example, if I develop a plugin to solve the differential equations, I first create the classes for transferring data:
public class DifferentialEquationTask : Task
// This class contains the data of the differential equation to be solved.
...
public class DifferentialEquationResult : Result
// This class contains the the result.
...
Therefore, the client should instantiate a new object DifferentialEquationTask and pass it to the method of the second service:
DifferentialEquationTask myTask = new DifferentialEquationTask(...);
...
Result result = executeTask(myTask); // called by basic application
// The second service receives myTask as a Task object.
// This Task object also contains the destination plugin, so myTask is send
// to the correct plugin, which converts it to DifferentialEquationTask
...
myResult = result as DifferentialEquationResult;
// received by the client
Moreover, each plugin should have a version for the application server and a version for the client application.
An alternative would be to include the service in the plugin itself: in this way, a new plugin should implement a new functionality and expose it via an additional service.
In summary, I thought the following two alternatives:
a main service to ask the server if it has a plugin or not, and a second service to deliver tasks at the correct plugin;
a main service to ask if the server has a plugin or not, and various additional services (an additional service for each plugin installed).
In order to choose the best approach, I could use the following requirements:
Which of the two alternatives may provide better performance?
What advantages would be obtained using a new service for each plugin than using a single service that delivers tasks at the correct plugin?
Which of the two alternatives simplifies the development of a new plugin?
Being a novice, I was wondering if there was a better approach...
Thanks a lot!
It seems like the main service could maintain a dictionary of plugins, indexed by name. Then for a client to see if the server provides a particular service, all the main service has to do is look up the name in the dictionary. And to process, the service just has to call a method on the object that's in the value portion of the dictionary entry. An example:
You have three abstract classes: Service, ServiceResult, and ServiceTask. The contents of ServiceTask and ServiceResult aren't really important for this discussion. Service must have a parameterless constructor and a method called Process that takes a ServiceTask as its sole parameter. So your differential equation solver would look like:
public class DiffeqSolver : Service
{
public DiffeqSolver()
{
// do any required initialization here
}
public ServiceResult Process(ServiceTask task)
{
DiffeqTask dtask = task as DiffeqTask;
if (dtask == null)
{
// Error. User didn't pass a DiffeqTask.
// Somehow communicate error back to client.
}
// Here, solve the diff eq and return the result.
}
}
The main service is somehow notified of existing plugins. It maintains a dictionary:
Dictionary<string, Service> Services = new Dictionary<string, Service>();
I assume you have some idea how you're going to load the plugins. What you want, in effect, is for the dictionary to contain:
Key = "DiffeqSolver", Value = new DiffeqSolver();
Key = "ServiceType1", Value = new ServiceType1();
etc., etc.
You can then have two methods for the main service: ServiceIsSupported and Process:
bool ServiceIsSupported(string serviceName)
{
return Services.ContainsKey(serviceName);
}
ServiceResult Process(string serviceName, ServiceTask task)
{
Service srv;
if (Services.TryGetValue(serviceName, out srv))
{
return srv.Process(task);
}
else
{
// The service isn't supported.
// Return a failure result
return FailedServiceResult;
}
}
I've simplified that to some extent. In particular, I'm using a Dictionary, which is not thread safe. You'd want to use a ConcurrentDictionary, or use locks to synchronize access to your dictionary.
The more difficult part, I think, will be loading the plugins. But there are many available examples of creating a plugin architecture. I think you can find what you need.

Categories

Resources