Share data between main app and periodic task - c#

I post this specific question after the other one I wasn't able to solve.
Briefly: even if I create a static class (with static vars and/or properties), main app and background agent don't use the same static class, but both create a new instance of it; so it's impossible to share data between these projects!!
To test it:
Create a new Windows Phone application (called AppTest)
Add a ScheduledTask project (called Agent)
In AppTest put a reference to project Agent
Create a new Windows Phone Library project (called Shared)
Both in AppTest and Agent put a reference to project Shared
Then use this basic test code.
AppTest
private readonly string taskName = "mytest";
PeriodicTask periodicTask = null;
public MainPage()
{
InitializeComponent();
Vars.Apps.Add("pluto");
Vars.Order = 5;
StartAgent();
}
private void RemoveTask()
{
try
{
ScheduledActionService.Remove(taskName);
}
catch (Exception)
{
}
}
private void StartAgent()
{
periodicTask = ScheduledActionService.Find(taskName) as PeriodicTask;
if (periodicTask != null)
RemoveTask();
periodicTask = new PeriodicTask(taskName)
{
Description = "test",
ExpirationTime = DateTime.Now.AddDays(14)
};
try
{
ScheduledActionService.Add(periodicTask);
ScheduledActionService.LaunchForTest(taskName,
TimeSpan.FromSeconds(10));
}
catch (InvalidOperationException exception)
{
}
catch (SchedulerServiceException)
{
}
}
Agent
protected override void OnInvoke(ScheduledTask task)
{
if (Vars.Apps.Count > 0)
Vars.Order = 1;
NotifyComplete();
}
Shared
public static class Vars
{
public static List<string> Apps = null;
public static int Order;
static Vars()
{
Apps = new List<string>();
Order = -1;
}
}
When you debug main app you can see that static constructor for static class is invoked (this is correct), but when agent is invoked Vars is not "used" but constructor is invoked another time, so creating a different instance.
Why? How can I share data between main app and background agent?
I've already tried to put Vars class in agent class and namespace, but the behaviour is the same.

Easiest thing is to use Isolated storage. For example, from the main app:
using (Mutex mutex = new Mutex(true, "MyData"))
{
mutex.WaitOne();
try
{
IsolatedStorageSettings.ApplicationSettings["order"] = 5;
}
finally
{
mutex.ReleaseMutex();
}
}
//...
and in the agent:
using (Mutex mutex = new Mutex(true, "MyData"))
{
mutex.WaitOne();
try
{
order = (int)IsolatedStorageSettings.ApplicationSettings["order"];
}
finally
{
mutex.ReleaseMutex();
}
}
// do something with "order" here...
You need to use Process-level synchronization and Mutex to guard against data corruption because the agent and the app are two separate processes and could be doing something with isolated storage at the same time.

Values of static variables are 'instanced' per loaded App Domain, which is a 'subset' of your running process. So static variables have different values per AppDomain, and therefore also per running process.
If you have to share data between processes, you need either to store it somewhere (e.g. a database), or you need to setup some communication between the processes (e.g. MSMQ or WCF).
Hope this helps.

After a long search, I finally found an article stating:
Since our EvenTiles application and its PeriodicTask are running in
separate processes, they are completely separated from each other,
meaning that they get their own copies of variables they both want to
access, even though these variables are defined in a separate project.
So it's impossible to share data between main app and periodic task using "simple" static variables/properties; we must read/write a database or the isolated storage or whatever we please.
I find this crazy, but this is the story.

MS recommends the following:
Communication Between Foreground Application and Background Agent
Passing information between the foreground application and background agents can be challenging because it is not possible to predict if the agent and the application will run simultaneously. The following are recommended patterns for this.
1.For Periodic and Resource-intensive Agents: Use LINQ 2 SQL or a file in isolated storage that is guarded with a Mutex. For one-direction communication where the foreground application writes and the agent only reads, we recommend using an isolated storage file with a Mutex. We recommend that you do not use IsolatedStorageSettings to communicate between processes because it is possible for the data to become corrupt.
2.For Audio Agents: Store custom data in the Tag property of the AudioTrack class. For notifications from the audio agent to the foreground application, read the Tag property in the PlayStateChanged event handler. To pass data from the foreground application to the audio agent, read the Tag property of the current track in the implementation of the OnPlayStateChanged(BackgroundAudioPlayer, AudioTrack, PlayState) method.
See here: http://msdn.microsoft.com/en-us/library/hh202944(v=vs.92).aspx

Related

Engage Azure Worker Role Background Service In Win Form

I have created a new winforms application. I am attempting to Create a class that listens to a storage queue for messages.
using System;
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Queue;
using System.Threading;
using Microsoft.WindowsAzure.ServiceRuntime;
using System.Configuration;
namespace PMonitor
{
public class QueueWorker : RoleEntryPoint
{
public override void Run()
{
CloudQueue queue = clnt.GetQueueReference("stuff");
while (true)
{
CloudQueueMessage qMessage = null;
do
{
qMessage = queue.GetMessage(TimeSpan.FromSeconds(10));
if (qMessage != null)
{
//handle message
}
}
while (qMessage != null);
Thread.Sleep(10000);
}
}
public override bool OnStart()
{
return base.OnStart();
}
}
}
How do I engage the worker to start running in the Form to run and tell me when it finds a message in the queue?
Currently instantiating this class and calling Run() in the Form Load locks up the form.
What is the pattern for doing this?
I suspect there's a basic misunderstanding about worker roles. These are not services that you instantiate like a class. Rather, these are definitions for stateless virtual machines that run in Azure. The code snippet you posted is the skeleton code that gets run after a worker role instance (a VM) is booted up, with code (such as queue consumption, in your case) running within the Run() method.
A WinForms application have zero need for RoleEntryPoint classes, since they are exclusively used within the stateless VM's running in Azure.
Queue processing (or any other tasks you might need to run) have no ties to worker roles; your app can consume queue messages just by working with the storage SDK (or by calling the REST API directly). How/where you set up your queue-processing logic is completely up to you.
Note: You can certainly call services running within worker role instances, from your WinForms application, but I don't think that's what you're asking.
There are several answers on StackOverflow which go into more detail about worker roles, such as this one.

c# windows service with filewatcher

First time posting long time reader.
I built a working filewatcher inside of a windows forms application functioning 100% properly before moving it to a windows Service and am now recieving two seperate issues. This file watcher reads a flatfile for line updates(lastwrite), deletes/recreates file(streamwriter), and finally parses through a strongly typed data set and then uploads to an SQL server.
(This is my first Windows Service)
Questions:
1. Does the double event trigger in filewatcher effect the service differently then a forms application?
2. Does anyone have an answer about why the thread will break if the class I am calling has no issue?
3. Are there any known issues with Windows Authentication through a windows service?
4. Does anyone have any strong debug methods for windows services?
Here is my code from the windows Service, thanks in advance and my apologies if there is a silly mistake in the code, again first time making a windows service.
FileMonitor m_FileMonitor;
public WindowsService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
try
{
Thread myThread = new Thread(DoTheWork);
myThread.Start();
}
catch
{
}
}
void DoTheWork()
{
m_FileMonitor = new FileMonitor(Properties.Settings.Default.PathToFileToWatch, Properties.Settings.Default.PathToErrorLog);
}
protected override void OnStop()
{
// TODO: Add code here to perform any tear-down necessary to stop your service.
}
For debugging, make sure your project type is Windows Application, and then use this:
[DllImport("kernel32")]
static extern bool AllocConsole();
private static void Main(string[] args)
{
var service = new MyService();
var controller = ServiceController.GetServices().FirstOrDefault(c => c.ServiceName == service.ServiceName);
if (null != controller && controller.Status == ServiceControllerStatus.StartPending)
{
ServiceBase.Run(service);
}
else
{
if (AllocConsole())
{
service.OnStart(args);
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
service.OnStop();
}
else
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
}
}
If the code is running because the Windows Service was started, it will run as a Windows Service. Otherwise it will allocate a console, run the service, then wait for a key press before exiting the service. You could build on this for testing pause and continue.
For debugging:
You have to use the ServiceBase.Run method in Main() to execute as a windows service, but you can make a switch in the main method to run the same application as a normal console application (e.g. --standalone). I'm using this on all my services to make them easy to debug.
Regarding the other problems:
I'm not completely sure which problems you encounter and what you mean by "class break" and "double event trigger".
Windows services run under a special service account, which might or might not have permissions to watch the directory you are interested in. You can change the service account or give it permission for the directory if you need to.
Links:
Here is a link to a codeproject article who seems to have implemented a file watcher windows service. Maybe it helps:
http://www.codeproject.com/Articles/18521/How-to-implement-a-simple-filewatcher-Windows-serv

sharing variables between running applications in C#

I am developing in C# two simple applications, running in the same local machine without network requirements.
The first application initializes an DLL (Class1) and set a variable. The second application just read it the data which was previously stored. Both applications instanciates the same Class1.
Code:
DLL (Class1):
public class Class1
{
private string variableName;
public string MyProperty
{
get { return variableName; }
set { variableName = value; }
}
}
Application A:
class Program
{
static void Main(string[] args)
{
Class1 class1 = new Class1();
string localReadVariable = Console.ReadLine();
class1.MyProperty = localReadVariable;
}
}
Application B:
class Program
{
static void Main(string[] args)
{
ClassLibraryA.Class1 localClass = new ClassLibraryA.Class1();
string z = localClass.MyProperty;
Console.WriteLine(z);
}
}
My problem is that I do not know how to read a variable from another thread.
Application B must read the "variableName" set by application B
Thank you
You need some sort of mechanism to communicate between the applications.
This can be through the registry, files, memory mapped files etc...
If both applications are expected to do write, you need to add synchronization logic to your code.
There is no simple way for Application B to read data created in Application A. Each application has its own address space and thus do not know of the others existence.
But, there are ways to do this!
See this question for one method..
I've successfully used two methods:
Use a database table to contain your common data. If you wrap your
calls to it in transactions then you also protection from
concurrency issues.
Use PersistentDictionary to store your data, protected by a mutex. You must have some interprocess locking since PersistentDictionary can only be open by one process at a time.
You can use .net Remoting to communicate between your two application.
Remoting also does not require a network address to communicate.

WCF Service Application - Using a C++ object call causes Visual Basic 6.0 DLL file to hang

We are currently in the process of moving a system to use WCF and ran into an issue that we can't figure out. The setup is there is a C# DLL file that wraps a C++ and a Visual Basic 6.0 DLL file. The C# DLL file has wrappers for both of these, and instantiates both objects. The C++ object is initialized (grabs data from files) and is then passed to a Visual Basic 6.0 object, that runs a report using the data in the C++ object. This is all happening as a WCF Service Application, and for the most part it works great, but when the Visual Basic 6.0 code calls a method in the C++ object, the whole thing hangs.
I tested out using just a simple application that calls the same C# DLL file (outside of WCF), and it works flawlessly. So, there is something going on with WCF and that C++ DLL file, but we can't figure out what. I've changed the Visual Basic 6.0 DLL file to use Run Unattended and Store in Memory (to be able to use it threaded), but that doesn't seem to matter.
Has anyone had any experience with this, or have any thoughts on why it would be hanging? My thought is that the WCF service is somehow locking the DLL file, and that's why when the Visual Basic 6.0 DLL file uses it, it can't access it, which causes it to deadlock.
C++ Wrapper
public interface ISummaryWrapper
{
void LoadInfo(Application info);
SummaryApp GetSummary();
}
public class SummaryWrapper : ISummaryWrapper
{
private SummaryApp _summary;
public SummaryWrapper()
{
_summary = new SummaryApp();
}
public SummaryWrapper(Application info)
{
_summary = new SummaryApp();
LoadInfo(info);
}
public void LoadInfo(Application info)
{
_summary.Initialize(info);
}
public SummaryApp GetSummary()
{
return _summary;
}
}
The info object contains information on what the Summary object needs to generate. It's only used in the Initialize method.
The Visual Basic 6.0 object is loaded through an interface:
public void LoadPageObject(Application info)
{
_pageInfo = new PageInformation();
_pageInfo.oInfo = info;
_pageInfo.oSummary = _summary;
}
So now the Visual Basic 6.0 object PageInformation has the summary object.
Next, we call the method to generate the report:
_pageInfo.BuildReport();
This goes inside the Visual Basic 6.0 DLL file, and at the point where the code tries to use the summary object, it hangs
// Omitted actual params for brevity, though all the params exist
double value = oSummary.GetData(string parm1, string parm2)
If I use this same call in C#, it pulls back the data just fine.
double value = _summary.GetData(string parm1, string parm2);
Again, when I use this wrapper outside of WCF, it goes through the code fine. It's only when it's running in WCF that it hangs.
It seems to be an issue running in MTA, and I'm not sure if a WCF Service Application running on IIS can be set to run in STA. Is this possible?
SOLVED:
I found my answer in this Stack Overflow question:
How to make a WCF service STA (single-threaded)
Which lead me to the article XXX.
Basically, I had to create a thread that is set to STA, and run the API (my C# DLL file) in it. Since I am running all of this with TaskFactory (so I can cancel calls, and run multiple requests), it was a little tricky. Now, I still have the ability to run multiple reports at the same time in MTA, but each report is run in STA. Also, I don't lose my cancellation functionality from WCF either.
Here is the code (I have some cleanup to do still):
public class Builder
{
public string OperationId { get; set; }
public IServiceCallback CallBack { get; set; }
public Dictionary<string, CancellationTokenSource> Queue { get; set; }
public void BuildReport()
{
OperationContext context = OperationContext.Current;
Thread thread = new Thread(
new ThreadStart(
delegate
{
using (OperationContextScope scope = new OperationContextScope(context))
{
try
{
CancellationToken token = Queue[OperationId].Token;
CallBack.SendStatus(OperationId, Status.Processing);
IAPI api = new API(token);
api.MessagingEvents += MessageEvent;
// Build Report
CallBack.SendStatus(OperationId, Status.BuildingReport);
if (!api.BuildReport())
return;
CallBack.SendStatus(OperationId, Status.Completed);
}
catch (OperationCanceledException oc)
{
// Sending this on the method that receives the cancel request, no need to send again
}
catch (Exception ex)
{
// May not be able to use callback if it's a Timeout Exception, log error first
// TODO: Log Error
CallBack.SendMessage(OperationId, MessageType.Error, ex.Message);
CallBack.SendStatus(OperationId, Status.Error);
}
finally
{
Queue.Remove(OperationId);
}
}
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
thread.Join();
}
}
And my service calls this via:
// I initialize taskfactory when the service is created, omitting other code for brevity
public void BuildReport(ReportRequest request)
{
CallBack.SendReportStatus(request.OperationId, Status.Received);
CancellationTokenSource cancelSource = new CancellationTokenSource();
Queue.Add(request.OperationId, cancelSource);
Builder builder = new Builder
{
OperationId = request.OperationId,
CallBack = CallBack,
Queue = _queue
};
_taskFactory.StartNew(builder.BuildReport, cancelSource.Token);
}
I hope this helps anyone else who comes across this problem!
VB6 (COM) needs to be run from an STA thread. Your WCF code is probably calling into the VB6 component on one or more MTA threads. I bet your your test (non WCF) app, the one that worked, was a desktop app. You will need to ensure that the VB6 component is not called from arbitrary .NET threads.

How to implement single instance per machine application?

I have to restrict my .net 4 WPF application so that it can be run only once per machine. Note that I said per machine, not per session.
I implemented single instance applications using a simple mutex until now, but unfortunately such a mutex is per session.
Is there a way to create a machine wide mutex or is there any other solution to implement a single instance per machine application?
I would do this with a global Mutex object that must be kept for the life of your application.
MutexSecurity oMutexSecurity;
//Set the security object
oMutexSecurity = new MutexSecurity();
oMutexSecurity.AddAccessRule(new MutexAccessRule(new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null), MutexRights.FullControl, AccessControlType.Allow));
//Create the global mutex and set its security
moGlobalMutex = new Mutex(True, "Global\\{5076d41c-a40a-4f4d-9eed-bf274a5bedcb}", bFirstInstance);
moGlobalMutex.SetAccessControl(oMutexSecurity);
Where bFirstInstance returns if this is the first instance of your application running globally. If you omited the Global part of the mutex or replaced it with Local then the mutex would only be per session (this is proberbly how your current code is working).
I believe that I got this technique first from Jon Skeet.
The MSDN topic on the Mutex object explains about the two scopes for a Mutex object and highlights why this is important when using terminal services (see second to last note).
I think what you need to do is use a system sempahore to track the instances of your application.
If you create a Semaphore object using a constructor that accepts a name, it is associated with an operating-system semaphore of that name.
Named system semaphores are visible throughout the operating system, and can be used to synchronize the activities of processes.
EDIT: Note that I am not aware if this approach works across multiple windows sessions on a machine. I think it should as its an OS level construct but I cant say for sure as i havent tested it that way.
EDIT 2: I did not know this but after reading Stevo2000's answer, i did some looking up as well and I think that the "Global\" prefixing to make the the object applicable to the global namespace would apply to semaphores as well and semaphore, if created this way, should work.
You could open a file with exclusive rights somewhere in %PROGRAMDATA%
The second instance that starts will try to open the same file and fail if it's already open.
How about using the registry?
You can create a registry entry under HKEY_LOCAL_MACHINE.
Let the value be the flag if the application is started or not.
Encrypt the key using some standard symmetric key encryption method so that no one else can tamper with the value.
On application start-up check for the key and abort\continue accordingly.
Do not forget to obfuscate your assembly, which does this encryption\decryption part, so that no one can hack the key in registry by looking at the code in reflector.
I did something similar once.
When staring up the application list, I checked all running processes for a process with identical name, and if it existed I would not allow to start the program.
This is not bulletproof of course, since if another application have the exact same process name, your application will never start, but if you use a non-generic name it will probably be more than good enough.
For the sake of completeness, I'd like to add the following which I just found now:
This web site has an interesting approach in sending Win32 messages to other processes. This would fix the problem of the user renaming the assembly to bypass the test and of other assemblies with the same name.
They're using the message to activate the main window of the other process, but it seems like the message could be a dummy message only used to see whether the other process is responding to it to know whether it is our process or not.
Note that I haven't tested it yet.
See below for full example of how a single instace app is done in WPF 3.5
public class SingleInstanceApplicationWrapper :
Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase
{
public SingleInstanceApplicationWrapper()
{
// Enable single-instance mode.
this.IsSingleInstance = true;
}
// Create the WPF application class.
private WpfApp app;
protected override bool OnStartup(
Microsoft.VisualBasic.ApplicationServices.StartupEventArgs e)
{
app = new WpfApp();
app.Run();
return false;
}
// Direct multiple instances.
protected override void OnStartupNextInstance(
Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e)
{
if (e.CommandLine.Count > 0)
{
app.ShowDocument(e.CommandLine[0]);
}
}
}
Second part:
public class WpfApp : System.Windows.Application
{
protected override void OnStartup(System.Windows.StartupEventArgs e)
{
base.OnStartup(e);
WpfApp.current = this;
// Load the main window.
DocumentList list = new DocumentList();
this.MainWindow = list;
list.Show();
// Load the document that was specified as an argument.
if (e.Args.Length > 0) ShowDocument(e.Args[0]);
}
public void ShowDocument(string filename)
{
try
{
Document doc = new Document();
doc.LoadFile(filename);
doc.Owner = this.MainWindow;
doc.Show();
// If the application is already loaded, it may not be visible.
// This attempts to give focus to the new window.
doc.Activate();
}
catch
{
MessageBox.Show("Could not load document.");
}
}
}
Third part:
public class Startup
{
[STAThread]
public static void Main(string[] args)
{
SingleInstanceApplicationWrapper wrapper =
new SingleInstanceApplicationWrapper();
wrapper.Run(args);
}
}
You may need to add soem references and add some using statements but it shoudl work.
You can also download a VS example complete solution by downloading the source code of the book from here.
Taken From "Pro WPF in C#3 2008 , Apress , Matthew MacDonald" , buy the book is gold. I did.

Categories