Imagine for a second that you are writing an application like Outlook… let's call it MiMail.exe! This application is very basic and has 3 views that are relevant to me! I want to be able to see my mail, contacts and calendar! There are also 3 specific tasks that I want to be able to execute: new mail, new contact and new appointment!
At any given time, I only want one instance of this application running but I want to be able to execute these tasks by using the command line arguments, i.e.:
MiMail.exe /mail
MiMail.exe /newContact
I am going to use a variation of the mediator pattern to facilitate the inter process communication via named pipes!
Mediator Pattern
The mediator pattern, one of the 23 design patterns described in Design Patterns: Elements of Reusable Object-Oriented Software, provides a unified interface to a set of interfaces in a subsystem. This pattern is considered to be a behavioral pattern due to the way it can alter the program's running behavior.
Usually a program is made up of a (sometimes large) number of classes. So the logic and computation is distributed among these classes. However, as more classes are developed in a program, especially during maintenance and/or refactoring, the problem of communication between these classes may become more complex. This makes the program harder to read and maintain. Furthermore, it can become difficult to change the program, since any change may affect code in several other classes.
With the mediator pattern communication between objects is encapsulated with a mediator object. Objects no longer communicate directly with each other, but instead communicate through the mediator. This reduces the dependencies between communicating objects, thereby lowering the coupling.
Ok, so variation is maybe an under statement… more like abuse the mediator pattern!
Named Pipes
In computing, a named pipe (also known as a FIFO for its behavior) is an extension to the traditional pipe concept on Unix and Unix-like systems, and is one of the methods of inter-process communication. MacOS calls it a socket, which should not be confused with a TCP socket. The concept is also found in Microsoft Windows, although the semantics differ substantially. A traditional pipe is "unnamed" because it exists anonymously and persists only for as long as the process is running. A named pipe is system-persistent and exists beyond the life of the process and must be deleted once it is no longer being used. Processes generally attach to the named pipe (usually appearing as a file) to perform inter-process communication (IPC).
A good friend and fellow MVP, Mario Lionello, helped me out getting the asynchronous named pipes to work! I included his MaLio.AsyncPipes
library!!!
Here is my updated App.xaml.cs:
public partial class App : Application
{
const string appName = "MiMail";
private void OnStartup(object sender, StartupEventArgs e)
{
if (SingleInstanceManager.IsApplicationRunning())
{
foreach (var arg in e.Args)
{
Mediator.Notify(appName, arg);
}
App.Current.Shutdown();
return;
}
Views.MainView view = new Views.MainView();
view.DataContext = new ViewModels.MainViewModel();
view.Show();
}
}
MiMail
is using a very simple mutex to detect if there is an instance of this application running. If the application is already running, use the Mediator to notify the listeners that a new instance was started and pass the command line arguments as messages!
Now I can just wait for new messages!
mediator = new Mediator(appName);
mediator.Register("contacts", ShowContacts);
mediator.Register("calendar", ShowCalendar);
mediator.Register("mail", ShowMail);
Here is an example of the Action<>
:
void ShowContacts(object message)
{
this.Dispatcher.Invoke(
DispatcherPriority.Normal,
new Action(() =>
{
viewHost.Children.Clear();
viewHost.Children.Add(new ContactsView());
}));
}
And that is it!!!
Launching “MiMail.exe contacts” will call the ShowContacts
action!!!
CodeProject