Preventing simultaneous calls to a WCF function - c#

I have a WCF service running as a windows service. This service references a DLL containing a class X with a public method func1. func1 calls another method func2(private) asynchronously using tasks(TPL). func2 performs a long running task independently. The setup is :
WCF
public string wcfFunc()
{
X obj = new X();
return obj.func1();
}
DLL
public class X
{
static bool flag;
public X()
{
flag = true;
}
public string func1()
{
if (!flag)
return "Already in action";
Task t = null;
t = Task.Factory.StartNew(() => func2(),TaskCreationOptions.LongRunning);
return "started";
}
void func2()
{
try
{
flag = false;
//Does a long running database processing work through .Net code
}
catch (Exception)
{
}
finally
{
flag = true;
}
}
}
The WCF function is called from a website. The website is used by multiple users. No two execution of the database processing func2 is allowed. Any user can trigger it. But during an execution, if any other user attempts to trigger it, it should show that the processing is already running.
I tried to use a static variable 'flag' to check it, but it does not seem to be working.
Any solutions? Thanks in advance.

You can read the following article, to prevent multiple calls to the WCF service method, you will need to first ensure that only one instances of your service can be created in addition to setting the concurrency mode.
In short, Make the following changes to your ServiceBehavior:
[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode=InstanceContextMode.Single)]
public class YourService: IYourService
{...}
NOTE : This will disable concurrency in all the methods exposed by your service, If you do not want that you will have to move the needed method to a separate service and then configure it as above.

Related

.NET client-side WCF with queued requests

Background
I'm working on updating legacy software library. The legacy code uses an infinitely looping System.Threading.Thread that executes processes in the queue. These processes perform multiple requests with another legacy system that can only process one request at a time.
I'm trying to modernize, but I'm new to WCF services and there may be a big hole in my knowledge that'd simplify things.
WCF Client-Side Host
In modernizing, I'm trying to move to a client-side WCF service. The WCF service allows requests to be queued from multiple a applications. The service takes a request and returns a GUID back so that I can properly associate via the callbacks.
public class SomeService : ISomeService
{
public Guid AddToQueue(Request request)
{
// Code to add the request to a queue, return a Guid, etc.
}
}
public interface ISomeCallback
{
void NotifyExecuting(Guid guid)
void NotifyComplete(Guid guid)
void NotifyFault(Guid guid, byte[] data)
}
WCF Client Process Queues
The problem I'm having is that the legacy processes can include more than one request. Process 1 might do Request X then Request Y, and based on those results follow up with Request Z. With the legacy system, there might be Processes 1-10 queued up.
I have a cludgy model where the process is executed. I'm handling events on the process to know when it's finished or fails. But, it just feels really cludgy...
public class ActionsQueue
{
public IList<Action> PendingActions { get; private set; }
public Action CurrentAction { get; private set; }
public void Add(Action action)
{
PendingAction.Add(action)
if (CurrentAction is null)
ExecuteNextAction();
}
private void ExecuteNextAction()
{
if (PendingActions.Count > 0)
{
CurrentAction = PendingActions[0];
PendingActions.RemoveAt(0);
CurrentAction.Completed += OnActionCompleted;
CurrentAction.Execute();
}
}
private OnActionCompleted(object sender, EventArgs e)
{
CurrentAction = default;
ExecuteNextAction();
}
}
public class Action
{
internal void Execute()
{
// Instantiate the first request
// Add handlers to the first request
// Send it to the service
}
internal void OnRequestXComplete()
{
// Use the data that's come back from the request
// Proceed with future requests
}
}
With the client-side callback the GUID is matched up to the original request, and it raises a related event on the original requests. Again, the implementation here feels really cludgy.
I've seen example of Async methods for the host, having a Task returned, and then using an await on the Task. But, I've also seen recommendations not to do this.
Any recommendations on how to untangle this mess into something more usable are appreciated. Again, it's possible that there's a hole in my knowledge here that's keeping me from a better solutiong.
Thanks
Queued communication between the client and the server of WCF is usually possible using a NetMsmqbinding, which ensures persistent communication between the client and the server. See this article for specific examples.
If you need efficient and fast message processing, use a non-transactional queue and set the ExactlyOnce attribute to False, but this has a security impact. Check this docs for further info.
In case anyone comes along later with a similar issue, this is a rough sketch of what I ended up with:
[ServiceContract(Name="MyService", SessionMode=Session.Required]
public interface IMyServiceContract
{
[OperationContract()]
Task<string> ExecuteRequestAsync(Action action);
}
public class MyService: IMyServiceContract
{
private TaskQueue queue = new TaskQueue();
public async Task<string> ExecuteRequestAsync(Request request)
{
return await queue.Enqueue(() => request.Execute());
}
}
public class TaskQueue
{
private SemaphoreSlim semaphore;
public TaskQueue()
{
semaphore = new SemaphoreSlim(1);
}
Task<T> Enqueue<T>(Func<T> function)
{
await semaphore.WaitAsync();
try
{
return await Task.Factory.StartNew(() => function.invoke();)
}
finally
{
semaphore.Release();
}
}
}

Correct way to kill service in C#, to be always recovered by SCM

We have a service that needs to kill itself (reason: we use a third party lib, that has unpredictable behavior in shutdown scenarios ...). Sometimes the service is not restarted by the Windows Service Control manager. The service recovery actions, in the SCM, are set to "Restart the Service" (for the first, the second and subsequent failures).
That's the way we kill our service:
public static void TerminateProcess(string message)
{
Log.ErrorFormat("Terminating Process becauses of: {0}", message);
Process.GetCurrentProcess().Kill();
}
Does anybody knows if this Process.GetCurrentProcess().Kill(); is a good way to kill the service?
I also read some threads, where the following combination was suggested:
class MyService : ServiceBase
{
void KillMe()
{
this.ExitCode = 1; // ServiceBase.ExitCode
System.Environment.Exit(1);
}
}
I also found this stackoverflow thread, but it doesn't state anything about service recovery.
What's the preferred/safe way to kill a service, so that the SCM will restart it?
Thx
Make a singleton instance of your service. And then you you can stop your service using stop() method.
public partial class ABCService : ServiceBase
{
public static ABCService ServiceInstance;
private void InitService()
{
ServiceInstance = this;
}
}
public static void StopService()
{
if(ABCService.ServiceInstance != null)
{
ABCService.ServiceInstance.Stop();
}
}
And you don't want the to restart automatically
public static void ChangeServiceMode(bool serviceAutoEnable)
{
RegistryKey key = Registry.LocalMachine.OpenSubKey("SYSTEM\\CurrentControlSet\\Services\\NixService", true);
if (key != null)
{
//Set service to manual / Automatic (Automatic = 2, manual = 3)
int serviceMode = serviceAutoEnable ? 2 : 3;
key.SetValue("Start", serviceMode, RegistryValueKind.DWord);
key.Close();
}
}
}
I think that it is necessary to understand: in what cases it is necessary to disable the service.
The first method you describe allows you to kill a service from a third-party code base. And the second option is in the service itself, but I think that the last option is not realizable, because the question arises: what circumstances should there be for the service to kill itself ???
IMHO the first option is more practical.

Where to Break the Chain with Task, ContinueWith, Lock

I have MVP application C#, .NET 4, WinForms. It uses Bridge class which communicate with third party app via NamedPipe.
The command flow is like this: View → Presenter → Manager → Bridge → Client
And back in the reverse order. View is prepared for multitasking. I split reverse chain in Manager by rising event with the result, but it doesn't help.
// View class
public void AccountInfo_Clicked() { presenter.RequestAccountInfo(); }
public void UpdateAccountInfo(AccountInfo info)
{
if (pnlInfo.InvokeRequired)
pnlInfo.BeginInvoke(new InfoDelegate(UpdateAccountInfo), new object[] {info});
else
pnlInfo.Update(info);
}
// Presenter class
public void RequestAccountInfo() { manager.RequestAccountInfo(); }
private void Manager_AccountInfoUpdated(object sender, AccountInfoEventArgs e)
{
view.UpdateAccountInfo(e.AccountInfo);
}
// Manager class
public void RequestAccountInfo()
{
AccountInfo accountInfo = bridge.GetAccountInfo();
OnAccountInfoUpdated(new AccountInfoEventArgs(accountInfo));
}
// Bridge class
public AccountInfo GetAccountInfo() { return client.GetAccountInfo(); }
// Client class
public AccountInfo GetAccountInfo()
{
string respond = Command("AccountInfo");
return new AccountInfo(respond);
}
private string Command(string command)
{
var pipe = new ClientPipe(pipeName);
pipe.Connect();
return pipe.Command(command);
}
I want to unfreeze the UI during command processing. There are also other commands that can be executed. Finally all commands reach Command(string command) method in Client.
I tried to break the chain in Manager by using task and ContinueWith but it results to pipe failing to connect. The reason is that client is not thread safe.
// Manager class
public void RequestAccountInfo()
{
var task = Task<AccountInfo>.Factory.StartNew(() => bridge.GetAccountInfo());
task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); });
}
My question is: Where to use Task, ContinueWith and where to Lock?
I assume I can lock only Command(string command) because it is the ultimate method.
private string Command(string command)
{
lock (pipeLock)
{
var pipe = new ClientPipe(pipeName);
pipe.Connect();
return pipe.Command(command);
}
}
Can I use Task, Wait in Command in Client class?
I think the problem you are having is that bridge.GetAccountInfo() is trying to extract information from the UI itself - hence the UI thread. This code
public void RequestAccountInfo()
{
var task = Task<AccountInfo>.Factory.StartNew(() => bridge.GetAccountInfo());
task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); });
}
is attempting to execute the bridge.GetAccountInfo() method (accessing the UI) from a background thread-pool thread.
My first question here would be how expensive is the call to bridge.GetAccountInfo()? If it is not expensive, it makes no sense to put working into multi-threading this aspect. If it is expensive, you will have to think about a way to make this operation thread safe (I can't advise without more information).
Another thing to do would assess the expense of a move to WCF. This handles most synchronisation problems for you... I am sorry I can't be of more help. I wrote the above before I read your last comment.
I hope this is of some use.
Aside: something to be aware of is SynchronizationContext. Using a TaskScheduler you can launch a Task on the UI thread (this is not what you want here as this again will just block the UI - however, this can be good to know when reporting [in .NET 4.0]. To launch your code above on the UI thread you can do
public void RequestAccountInfo()
{
var task = Task<AccountInfo>.Factory.StartNew(() =>
bridge.GetAccountInfo(),
TaskScheduler.FromCurrentSynchronizationContext());
task.ContinueWith(t => { OnAccountInfoUpdated(new AccountInfoEventArgs(t.Result)); });
}
I locked Command in Client class. It appears that it works perfectly in that way. No blocking UI, no pipe errors. I lock on pipeName because each copy of View is using a unique pipe name.
I applied Task<Type>, ContinueWith to all commands in Manager class.
// Manager class
public void RequestSomeInfo()
{
var task = Task<SomeInfo>.Factory.StartNew(() => bridge.GetSomeInfo());
task.ContinueWith(t => { OnInfoUpdated(new InfoEventArgs(t.Result)); });
}
// Client class
private string Command(string command)
{
lock (pipeName)
{
var pipe = new ClientPipe(pipeName);
pipe.Connect();
return pipe.Command(command);
}
}

System.Web.Services.WebService - Is it possible to isolate the service per client

I have an legacy System.Web.Services.WebService (not WCF) that I have to maintain.
Ocassionly I run into some wired behaviours that I would describe as race conditions.
Either the service hangs and has to be restarted.
Sometimes I get this exception:
System.NotSupportedException: Multiple simultaneous connections
or connections with different connection strings inside the same
transaction are not currently supported.
at MySql.Data.MySqlClient.MySqlConnection.Open()
...
I know whats the root cause. The service utilizes a lib that talks to mysql and was not designed with webservices in mind. Unfortunatly I cannot change this lib.
One example webmethod looks like this:
[WebMethod(EnableSession = true)]
public void DoSomething()
{
var login = this.Session["login"] as LoginDetails;
ExternalLib.SetLoginData(login.Schema, login.User, login.Pass);
ExternalLib.PerformTask();
}
So the problem here is this:
ExternalLib.SetLoginData just set's some global vars
ExternalLib.PerformTask performs database calls, some inside a transaction.
The process is like 1. Create MySqlConnection or take it from cache 2. Create MySqlCommand 3. Execute Command 4. Dispose command
Client a) calls DoSomething() and I init his connection. Half way done with his job Client b) calls DoSomething() which apparently changes the Login-Data for client a and the next call inside the transaction will use the login from client b) which causes the transaction.
Anyway, I know this is a bad design but my question is how to workaround this.
Currently (since I only have 10 clients) I created a dedicated Website on a differnet port which all point to the same root directory but this is an akward solution.
Maybe there is a possibility to run every session inside its on realm. Any suggestions. If I understand this page correctly for WCF is is the default behaviour: http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
Per-Call Services
Per-call services are the Windows Communication
Foundation default instantiation mode. When the service type is
configured for per-call activation, a service instance, a common
language runtime (CLR) object, exists only while a client call is in
progress. Every client request gets a new dedicated service instance.
Seeing as this is probably a threading issue you can lock the ExternalLib to prevent separate instances from calling the code.
public class ExtenalLibWrapper
{
private static object Locker = new object();
public void DoSomething(LoginDetails details)
{
lock(Locker)
{
ExternalLib.SetLoginData(login.Schema, login.User, login.pass);
ExternalLib.PerformTask();
}
}
}
I already wrapped all my public methods in a neat execute wrapper to provide global exception logging.
This forces my webservice to process one request after another, but like I mentioned, the max. number of simultanious clients is 10
public class MyService : System.Web.Services.WebService
{
[WebMethod(EnableSession = true)]
public static int Add(int value1, int value2)
{
return Execute(() =>
{
var calculator = new Calculator();
return calculator.Add(value1, value2);
});
}
private static Logger logger =
LogManager.GetLogger(typeof(MyService).Name);
private static System.Threading.SemaphoreSlim ss =
new System.Threading.SemaphoreSlim(1, 1);
private void Execute(Action method)
{
ss.Wait();
try { method.Invoke(); }
catch (Exception ex)
{
logger.FatalException(method.Method + " failed", ex); throw;
}
finally { ss.Release(); }
}
private T Execute<T>(Func<T> method)
{
ss.Wait();
try { return method.Invoke(); }
catch (Exception ex)
{
logger.FatalException(method.Method + " failed", ex); throw;
}
finally
{
ss.Release();
}
}
}

How to write c# service that I can also run as a winforms program?

I have a windows service written in C# that acts as a proxy for a bunch of network devices to the back end database. For testing and also to add a simulation layer to test the back end I would like to have a GUI for the test operator to be able run the simulation. Also for a striped down version to send out as a demo. The GUI and service do not have to run at the same time. What is the best way to achieve this duel operation?
Edit:
Here is my solution combing stuff from this question , Am I Running as a Service and Install a .NET windows service without InstallUtil.exe using this excellent code by Marc Gravell
It uses the following line to test if to run the gui or run as service.
if (arg_gui || Environment.UserInteractive || Debugger.IsAttached)
Here is the code.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.ComponentModel;
using System.ServiceProcess;
using System.Configuration.Install;
using System.Diagnostics;
namespace Form_Service
{
static class Program
{
///
/// The main entry point for the application.
///
[STAThread]
static int Main(string[] args)
{
bool arg_install = false;
bool arg_uninstall = false;
bool arg_gui = false;
bool rethrow = false;
try
{
foreach (string arg in args)
{
switch (arg)
{
case "-i":
case "-install":
arg_install = true; break;
case "-u":
case "-uninstall":
arg_uninstall = true; break;
case "-g":
case "-gui":
arg_gui = true; break;
default:
Console.Error.WriteLine("Argument not expected: " + arg);
break;
}
}
if (arg_uninstall)
{
Install(true, args);
}
if (arg_install)
{
Install(false, args);
}
if (!(arg_install || arg_uninstall))
{
if (arg_gui || Environment.UserInteractive || Debugger.IsAttached)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
else
{
rethrow = true; // so that windows sees error...
ServiceBase[] services = { new Service1() };
ServiceBase.Run(services);
rethrow = false;
}
}
return 0;
}
catch (Exception ex)
{
if (rethrow) throw;
Console.Error.WriteLine(ex.Message);
return -1;
}
}
static void Install(bool undo, string[] args)
{
try
{
Console.WriteLine(undo ? "uninstalling" : "installing");
using (AssemblyInstaller inst = new AssemblyInstaller(typeof(Program).Assembly, args))
{
IDictionary state = new Hashtable();
inst.UseNewContext = true;
try
{
if (undo)
{
inst.Uninstall(state);
}
else
{
inst.Install(state);
inst.Commit(state);
}
}
catch
{
try
{
inst.Rollback(state);
}
catch { }
throw;
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.Message);
}
}
}
[RunInstaller(true)]
public sealed class MyServiceInstallerProcess : ServiceProcessInstaller
{
public MyServiceInstallerProcess()
{
this.Account = ServiceAccount.NetworkService;
}
}
[RunInstaller(true)]
public sealed class MyServiceInstaller : ServiceInstaller
{
public MyServiceInstaller()
{
this.Description = "My Service";
this.DisplayName = "My Service";
this.ServiceName = "My Service";
this.StartType = System.ServiceProcess.ServiceStartMode.Manual;
}
}
}
You basically have two choices. Either expose an API on the service which you can then call from the UI app OR enable the service to run either as a winforms app or a service.
The first option is pretty easy - use remoting or WCF to expose the API.
The second option can be achieved by moving the "guts" of your app into a separate class then create a service wrapper and a win-forms wrapper that both call into your "guts" class.
static void Main(string[] args)
{
Guts guts = new Guts();
if (runWinForms)
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
FormWrapper fw = new FormWrapper(guts);
System.Windows.Forms.Application.Run(fw);
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new ServiceWrapper(guts) };
ServiceBase.Run(ServicesToRun);
}
}
If you use the below code:
[DllImport("advapi32.dll", CharSet=CharSet.Unicode)]
static extern bool StartServiceCtrlDispatcher(IntPtr services);
[DllImport("ntdll.dll", EntryPoint="RtlZeroMemory")]
static extern void ZeroMemory(IntPtr destination, int length);
static bool StartService(){
MySvc svc = new MySvc(); // replace "MySvc" with your service name, of course
typeof(ServiceBase).InvokeMember("Initialize", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod,
null, svc, new object[]{false});
object entry = typeof(ServiceBase).InvokeMember("GetEntry",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, svc, null);
int len = Marshal.SizeOf(entry) * 2;
IntPtr memory = Marshal.AllocHGlobal(len);
ZeroMemory(memory, len);
Marshal.StructureToPtr(entry, memory, false);
return StartServiceCtrlDispatcher(memory);
}
[STAThread]
static void Main(){
if(StartService())
return;
Application.Run(new MainWnd()); // replace "MainWnd" with whatever your main window is called
}
Then your EXE will run as either a service (if launched by the SCM) or as a GUI (if launched by any other process).
Essentially, all I've done here is used Reflector to figure out what the meat of ServiceBase.Run does, and duplicate it here (reflection is required, because it calls private methods). The reason for not calling ServiceBase.Run directly is that it pops up a message box to tell the user that the service cannot be started (if not launched by the SCM) and doesn't return anything to tell the code that the service cannot be started.
Because this uses reflection to call private framework methods, it may not function correctly in future revisions of the framework. Caveat codor.
Create a new winforms app the references the assembly of your service.
There is also FireDaemon. This allows you to run any windows application as a service.
See Am I running as a service for some further useful information.
The most important thing covered is how to reliably determine whether we are running interactively or via a service.
you have to implement a separate process that can communicate with your service. While it is possible on XP and earlier systems to have a service showing an UI, that's no longer possible on Vista and later.
Another possibility is to NOT use a service, but to use an application which resides in the Taskbar (think Roxio Drag-to-Disc, & most likely your Anti-virus software lives down there) which has an icon down by the clock, which launches a menu, when it is right-clicked, and a UI when double-clicked.
If your service is modulated properly, you could host the service either in a executable as a service, or with an executable with gui for the test.
We use this method with our service too, the standalone service-executable hosts the service in productive environment, but we have a console-app for hosting the service, too.
Separate your code into different components: one component to manage the service aspects and one to perform the actual business logic. Create and interact with the business logic from the service component. For testing (of your business logic) you can create a WinForm or console application that uses the business logic component without the service component. Better yet, use a unit testing framework for the bulk of your testing. Many of the methods in the service component will undoubtedly be unit testable as well.
If you encapsulate your business logic in service classes and then use a factory pattern to create those services, you can use the same set of services for a desktop application (desktop factory) and as web services (host in WCF).
Service definition:
[ServiceContract]
public interface IYourBusinessService
{
[OperationContract]
void DoWork();
}
public class YourBusinessService : IYourBusinessService
{
public void DoWork()
{
//do some business logic here
}
}
Factory for desktop WinForms to get at services to do business:
public class ServiceFactory
{
public static IYourBusinessService GetService()
{
//you can set any addition info here
//like connection string for db, etc.
return new YourBusinessService();
}
}
You host this either with the WCF ServiceHost class, or in IIS. Both allow you the ability to specify how to instantiate each instance of the service so that you can do initialization like connection strings, etc.
You can create the service to call another executable with a command line argument so it is run without the form. When that exe is called without the command line argument it shows the form and act as normal.

Categories

Resources