How to use MediatR on Winform .net core - c#

I have a .net core winform application and am implementing n-tier architecture(ApplicationLayer(winform), BLL, DAL)
Installed MediatR and MediatR.Extensions.Microsoft.DependencyInjection
I am currently following this site:
https://dotnetcoretutorials.com/2019/04/30/the-mediator-pattern-part-3-mediatr-library/
Where do I put this code
public void ConfigureServices(IServiceCollection services)
{
services.AddMediatR(Assembly.GetExecutingAssembly());
//Other injected services.
}
I have tried putting it on Main() like so:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(IServiceCollection services)
{
services.AddMediatR(Assembly.GetExecutingAssembly());
services.AddTransient<IApplicationHandler, ApplicationHandler>();
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
and its giving me this error
Program does not contain a static 'Main' method suitable for an entry point

The Main() method is the entry point of your application and thus cannot be modified. As you were adding a parameter to it, the compiler tells that the it could not find the Main() (parameterless) method.
If you want to work with dependency injection + windows forms some additional steps are needed.
1 - Install the package Microsoft.Extensions.DependencyInjection. Windows Forms doesn't have DI capabilities natively so we need do add it.
2 - Change your Program.cs class to be like this
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
// This class will contains your injections
var services = new ServiceCollection();
// Configures your injections
ConfigureServices(services);
// Service provider is the one that solves de dependecies
// and give you the implementations
using (ServiceProvider sp = services.BuildServiceProvider())
{
// Locates `Form1` in your DI container.
var form1 = sp.GetRequiredService<Form1>();
// Starts the application
Application.Run(form1);
}
}
// This method will be responsible to register your injections
private static void ConfigureServices(IServiceCollection services)
{
// Inject MediatR
services.AddMediatR(Assembly.GetExecutingAssembly());
// As you will not be able do to a `new Form1()` since it will
// contains your injected services, your form will have to be
// provided by Dependency Injection.
services.AddScoped<Form1>();
}
}
3 - Create your Command Request
public class RetrieveInfoCommandRequest : IRequest<RetrieveInfoCommandResponse>
{
public string Text { get; set; }
}
4 - Create your Command Response
public class RetrieveInfoCommandResponse
{
public string OutputMessage { get; set; }
}
5 - Create your Command Handler
public class RetrieveInfoCommandHandler : IRequestHandler<RetrieveInfoCommandRequest, RetrieveInfoCommandResponse>
{
public async Task<RetrieveInfoCommandResponse> Handle(RetrieveInfoCommandRequest request, CancellationToken cancellationToken)
{
RetrieveInfoCommandResponse response = new RetrieveInfoCommandResponse();
response.OutputMessage = $"This is an example of MediatR using {request.Text}";
return response;
}
}
6 - Form1 implementation
public partial class Form1 : Form
{
private readonly IMediator _mediator;
public Form1(IMediator mediator)
{
_mediator = mediator;
InitializeComponent();
}
private async void button1_Click(object sender, EventArgs e)
{
var outputMessage = await _mediator.Send(new RetrieveInfoCommandRequest
{
Text = "Windows Forms"
});
label1.Text = outputMessage.OutputMessage;
}
}
Working code
I'd never thought about using MediatR along Windows Forms, it was a nice study case. Nice question =)

Related

Creating an Interface for a WinForm Form to use DI [duplicate]

How to define dependency injection in Winforms C#?
Interface ICategory:
public interface ICategory
{
void Save();
}
Class CategoryRepository:
public class CategoryRepository : ICategory
{
private readonly ApplicationDbContext _context;
public CategoryRepository(ApplicationDbContext contex)
{
_context = contex;
}
public void Save()
{
_context.SaveChanges();
}
}
Form1:
public partial class Form1 : Form
{
private readonly ICategury _ic;
public Form1(ICategury ic)
{
InitializeComponent();
_ic=ic
}
private void button1_Click(object sender, EventArgs e)
{
Form2 frm= new Form2();
frm.show();
}
}
Form2:
public partial class Form2 : Form
{
private readonly ICategury _ic;
public Form2(ICategury ic)
{
InitializeComponent();
_ic=ic
}
}
Problem?
Definition of dependency injection in Program.cs
Application.Run(new Form1());
Definition of dependency injection at the time of Form 2 call
Form2 frm= new Form2();
frm.show();
How to use Dependency Injection (DI) in Windows Forms (WinForms)
To use DI in a WinForms .NET 5 or 6 you can do the following steps:
Create a WinForms .NET Application
Install Microsoft.Extensions.Hosting package (which gives you a bunch of useful features like DI, Logging, Configurations, and etc.)
Add a new interface, IHelloService.cs:
public interface IHelloService
{
string SayHello();
}
Add a new implementation for your service HelloService.cs:
public class HelloService : IHelloService
{
public string SayHello()
{
return "Hello, world!";
}
}
Modify the Program.cs:
//using Microsoft.Extensions.DependencyInjection;
static class Program
{
[STAThread]
static void Main()
{
Application.SetHighDpiMode(HighDpiMode.SystemAware);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
var host = CreateHostBuilder().Build();
ServiceProvider = host.Services;
Application.Run(ServiceProvider.GetRequiredService<Form1>());
}
public static IServiceProvider ServiceProvider { get; private set; }
static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services)=>{
services.AddTransient<IHelloService, HelloService>();
services.AddTransient<Form1>();
});
}
}
Now you can inject IHelloService in Form1 and use it:
//using Microsoft.Extensions.DependencyInjection;
public partial class Form1 : Form
{
private readonly IHelloService helloService;
public Form1(IHelloService helloService)
{
InitializeComponent();
this.helloService = helloService;
MessageBox.Show(helloService.SayHello());
}
}
If you want to show Form2 using DI, you first need to register it services.AddTransient<Form2>();, then depending to the usage of Form2, you can use either of the following options:
If you only need a single instance of Form2 in the whole life time of Form1, then you can inject it as a dependency to the constructor of Form1 and store the instance and show it whenever you want.
But please pay attention: it will be initialized just once, when you open Form1 and it will not be initialized again. You also should not dispose it, because it's the only instance passed to Form1.
public Form1(IHelloService helloService, Form2 form2)
{
InitializeComponent();
form2.ShowDialog();
}
If you need multiple instances of Form2 or you need to initialize it multiple times, then you may get an instance of it like this:
using (var form2 = Program.ServiceProvider.GetRequiredService<Form2>())
form2.ShowDialog();
There's another approach than the one described by Reza in his answer. This answer of mine was originally published on my blog, however, since Stack Overflow is the primary source of information for most of us, the blog post linked in a comment below Reza's answer could easily be missed.
Here goes then. This solution is based on the Local Factory pattern.
We'll start with a form factory
public interface IFormFactory
{
Form1 CreateForm1();
Form2 CreateForm2();
}
public class FormFactory : IFormFactory
{
static IFormFactory _provider;
public static void SetProvider( IFormFactory provider )
{
_provider = provider;
}
public Form1 CreateForm1()
{
return _provider.CreateForm1();
}
public Form2 CreateForm2()
{
return _provider.CreateForm2();
}
}
From now on, this factory is the primary client's interface to creating forms. The client code is no longer supposed to just call
var form1 = new Form1();
No, it's forbidden. Instead, the client should always call
var form1 = new FormFactory().CreateForm1();
(and similarily for other forms).
Note that while the factory is implemented, it doesn't do anything on its own! Instead it delegates the creation to a somehow mysterious provider which has to be injected into the factory. The idea behind this is that the provider will be injected, once, in the Composition Root which is a place in the code, close to the startup, and very high in the application stack so that all dependencies can be resolved there. So, the form factory doesn't need to know what provider will be ultimately injected into it.
This approach has a significant advantage - depending on actual requirements, different providers can be injected, for example you could have a DI-based provider (we'll write it in a moment) for an actual application and a stub provider for unit tests.
Anyway, let's have a form with a dependency:
public partial class Form1 : Form
{
private IHelloWorldService _service;
public Form1(IHelloWorldService service)
{
InitializeComponent();
this._service = service;
}
}
This form depends on a service and the service will be provided by the constructor. If the Form1 needs to create another form, Form2, it does it it a way we already discussed:
var form2 = new FormFactory().CreateForm2();
Things become more complicated, though, when a form needs not only dependant services but also, just some free parameters (strings, ints etc.). Normally, you'd have a constructor
public Form2( string something, int somethingElse ) ...
but now you need something more like
public Form2( ISomeService service1, IAnotherService service2,
string something, int somethingElse ) ...
This is something we should really take a look into. Look once again, a real-life form possibly needs
some parameters that are resolved by the container
other parameters that should be provided by the form creator (not known by the container!).
How do we handle that?
To have a complete example, let's then modify the form factory
public interface IFormFactory
{
Form1 CreateForm1();
Form2 CreateForm2(string something);
}
public class FormFactory : IFormFactory
{
static IFormFactory _provider;
public static void SetProvider( IFormFactory provider )
{
_provider = provider;
}
public Form1 CreateForm1()
{
return _provider.CreateForm1();
}
public Form2 CreateForm2(string something)
{
return _provider.CreateForm2(something);
}
}
And let's see how forms are defined
public partial class Form1 : Form
{
private IHelloWorldService _service;
public Form1(IHelloWorldService service)
{
InitializeComponent();
this._service = service;
}
private void button1_Click( object sender, EventArgs e )
{
var form2 = new FormFactory().CreateForm2("foo");
form2.Show();
}
}
public partial class Form2 : Form
{
private IHelloWorldService _service;
private string _something;
public Form2(IHelloWorldService service, string something)
{
InitializeComponent();
this._service = service;
this._something = something;
this.Text = something;
}
}
Can you see a pattern here?
whenever a form (e.g. Form1) needs only dependand services, it's creation method in the FormFactory is empty (dependencies will be resolved by the container).
whenever a form (e.g. Form2) needs dependand services and other free parameters, it's creation method in the FormFactory contains a list of arguments corresponding to these free parameters (service dependencies will be resolved by the container)
Now finally to the Composition Root. Let's start with the service
public interface IHelloWorldService
{
string DoWork();
}
public class HelloWorldServiceImpl : IHelloWorldService
{
public string DoWork()
{
return "hello world service::do work";
}
}
Note that while the interface is supposed to be somewhere down in the stack (to be recognized by everyone), the implementation is free to be provided anywhere (forms don't need reference to the implementation!). Then, follows the starting code where the form factory is finally provided and the container is set up
internal static class Program
{
[STAThread]
static void Main()
{
var formFactory = CompositionRoot();
ApplicationConfiguration.Initialize();
Application.Run(formFactory.CreateForm1());
}
static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
services.AddTransient<IHelloWorldService, HelloWorldServiceImpl>();
services.AddTransient<Form1>();
services.AddTransient<Func<string,Form2>>(
container =>
something =>
{
var helloWorldService =
container.GetRequiredService<IHelloWorldService>();
return new Form2(helloWorldService, something);
});
});
}
static IFormFactory CompositionRoot()
{
// host
var hostBuilder = CreateHostBuilder();
var host = hostBuilder.Build();
// container
var serviceProvider = host.Services;
// form factory
var formFactory = new FormFactoryImpl(serviceProvider);
FormFactory.SetProvider(formFactory);
return formFactory;
}
}
public class FormFactoryImpl : IFormFactory
{
private IServiceProvider _serviceProvider;
public FormFactoryImpl(IServiceProvider serviceProvider)
{
this._serviceProvider = serviceProvider;
}
public Form1 CreateForm1()
{
return _serviceProvider.GetRequiredService<Form1>();
}
public Form2 CreateForm2(string something)
{
var _form2Factory = _serviceProvider.GetRequiredService<Func<string, Form2>>();
return _form2Factory( something );
}
}
First note how the container is created with Host.CreateDefaultBuilder, an easy task. Then note how services are registered and how forms are registered among other services.
This is straightforward for forms that don't have any dependencies, it's just
services.AddTransient<Form1>();
However, if a form needs both services and free parameters, it's registered as ... form creation function, a Func of any free parameters that returns actual form. Take a look at this
services.AddTransient<Func<string,Form2>>(
container =>
something =>
{
var helloWorldService = container.GetRequiredService<IHelloWorldService>();
return new Form2(helloWorldService, something);
});
That's clever. We register a form factory function using one of registration mechanisms that itself uses a factory function (yes, a factory that uses another factory, a Factception. Feel free to take a short break if you feel lost here). Our registered function, the Func<string, Form2> has a single parameter, the something (that corresponds to the free parameter of the form constructor) but its other dependencies are resolved ... by the container (which is what we wanted).
This is why the actual form factory needs to pay attention of what it resolves. A simple form is resolved as follows
return _serviceProvider.GetRequiredService<Form1>();
where the other is resolved in two steps. We first resolve the factory function and then use the creation's method parameter to feed it to the function:
var _form2Factory = _serviceProvider.GetRequiredService<Func<string, Form2>>();
return _form2Factory( something );
And, that's it. Whenever a form is created, is either
new FormFactory().CreateForm1();
for "simple" forms (with service dependencies only) or just
new FormFactory().CreateForm2("foo");
for forms that need both service dependncies and other free parameters.
Just wanted to add this here too as an alternative pattern for the IFormFactory. This is how I usually approach it.
The benefit is you don't need to keep changing your IFormFactory interface foreach form that you add and each set of parameters.
Load all forms when application starts and pass arguments to the show method or some other base method you can define on your forms.
internal static class Program
{
public static IServiceProvider ServiceProvider { get; private set; }
[STAThread]
static void Main()
{
ApplicationConfiguration.Initialize();
ServiceProvider = CreateHostBuilder().Build().Services;
Application.Run(ServiceProvider.GetService<Form1>());
}
static IHostBuilder CreateHostBuilder()
{
return Host.CreateDefaultBuilder()
.ConfigureServices((context, services) => {
services.AddSingleton<IFormFactory,FormFactory>();
services.AddSingleton<IProductRepository, ProductRepository>();
//Add all forms
var forms = typeof(Program).Assembly
.GetTypes()
.Where(t => t.BaseType == typeof(Form))
.ToList();
forms.ForEach(form =>
{
services.AddTransient(form);
});
});
}
}
Form Factory
public interface IFormFactory
{
T? Create<T>() where T : Form;
}
public class FormFactory : IFormFactory
{
private readonly IServiceScope _scope;
public FormFactory(IServiceScopeFactory scopeFactory)
{
_scope = scopeFactory.CreateScope();
}
public T? Create<T>() where T : Form
{
return _scope.ServiceProvider.GetService<T>();
}
}
Form 1
public partial class Form1 : Form
{
private readonly IFormFactory _formFactory;
public Form1(IFormFactory formFactory)
{
InitializeComponent();
_formFactory = formFactory;
}
private void button_Click(object sender, EventArgs e)
{
var form2 = _formFactory.Create<Form2>();
form2?.Show(99);
}
}
Form 2
public partial class Form2 : Form
{
private readonly IProductRepository _productRepository;
public Form2(IProductRepository productRepository)
{
InitializeComponent();
_productRepository = productRepository;
}
public void Show(int recordId)
{
var product = _productRepository.GetProduct(recordId);
//Bind your controls etc
this.Show();
}
}

Avoid Dependency cycles in Dependency Injection

C# Windows Form application.
I have an Hub and a class. Both should reference each other.
This is because:
from the hub I need to call the class' methods
from the class I need to retrieve my Hub
Right now I'm able to do the first point using Autofac:
using Autofac;
using Autofac.Integration.SignalR;
using Microsoft.AspNet.SignalR;
using Microsoft.Owin.Cors;
using Microsoft.Owin.Hosting;
using Owin;
using MyProject.Classes;
using System;
using System.Reflection;
using System.Windows.Forms;
namespace MyProject
{
static class Program
{
static IDisposable webApp;
[STAThread]
static void Main()
{
string url = "http://localhost:8080";
webApp = WebApp.Start(url);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Engine());
}
}
class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
var builder = new ContainerBuilder();
var config = new HubConfiguration();
builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();
builder.RegisterType<Erp>().PropertiesAutowired().InstancePerLifetimeScope();
var container = builder.Build();
config.Resolver = new AutofacDependencyResolver(container);
app.UseAutofacMiddleware(container);
app.MapSignalR(config);
}
}
}
here the Hub:
using Microsoft.AspNet.SignalR;
using MyProject.Classes;
using System;
using System.Threading.Tasks;
namespace MyProject.Hubs
{
public class LiveHub : Hub
{
private readonly Erp _erp;
public LiveHub(Erp erp)
{
_erp = erp;
}
public override Task OnConnected()
{
_erp.someMethod();
return base.OnConnected();
}
}
}
and here Erp.cs:
public class Erp
{
public Erp()
{
}
public void SomeMethod()
{
// do something
}
public void SomeOtherMethod()
{
// usually I do:
var hub = GlobalHost.ConnectionManager.GetHubContext<LiveHub>();
hub.Clients.All.foo();
}
}
but here I read:
A common error in OWIN integration is use of the GlobalHost. In OWIN you create the configuration from scratch. You should not reference GlobalHost anywhere when using the OWIN integration. Microsoft has documentation about this and other IoC integration concerns here.
If I cannot use the "old" method, how should I retrieve my Hub?
I tried to add another DI in Erp for LiveHub but it doesn't work. In my form I create an instance of Erp:
public partial class Engine : Form
{
private Erp _erp = new Erp();
public Engine()
{
InitializeComponent();
}
}
if I add that DI the declaration will be impossible because I need to define the LiveHub in constructor, that requires itself the Erp parameter...
What am I not seeing?
You can decouple the Hub from the object (Erp in your case) by emitting events.
namespace MyProject.Hubs
{
public class LiveHub : Hub
{
public event Action SomethingHappened;
public override Task OnConnected()
{
SomethingHappened?.Invoke();
return base.OnConnected();
}
}
}
Now you can connect the Erp without the Hub having to know it. You will have to subscribe to the event somewhere else in your code. But the circular reference is broken.
To decouple Engine from Form you could do something like this:
public partial class EngineForm : Form
{
public EngineForm()
{
InitializeComponent();
}
}
public class Engine
{
public Engine(EngineForm form, Erp erp)
{
this.form = form;
this.erp = erp;
}
// Here is where you'll write some code to coordinate
// communication between the Erp and the EngineForm.
//
// The main advantage is that you can inject the Erp
// and have it preconfigured.
}

Windows Workflow: Getting variable from WorkflowApplication

I'm using the Windows Workflow Foundation (WWF). I made an Activity (XAML) with one Sequence in which I defined a variable.
I run the activity in the console application by creating an instance of WorkflowApplication. How can I get the value of a variable in my console application?
I persist an instance of WorkflowApplication in XML and in it I saw my variable and its value. Is there any correct way to get the value of a variable from XML?
So in your last comment you stated you want to get the state in the console application before the workflow is completed. Unfortunately In/Out and Out arguments are only available upon completion of the workflow. But there are ways to communicate with the host process using other constructs than workflow variables and arguments.
One of the ways to do that is to use a custom extension that can be used to interact with the host process. An extensions can be of any type and is available to the workflow and the host process. A complete example:
using System;
using System.Activities;
namespace WorkflowDemo
{
class Program
{
static void Main(string[] args)
{
var app = new WorkflowApplication(new MyCustomActivity());
var myExtension = new MyCommunicationExtension();
myExtension.MyValueChanged += (s, e) => Console.WriteLine(myExtension.MyValue);
app.Extensions.Add(myExtension);
app.Run();
Console.ReadKey();
}
}
public class MyCommunicationExtension
{
public string MyValue { get; private set; }
public event EventHandler<EventArgs> MyValueChanged;
public void OnMyValueChanged(string value)
{
MyValue = value;
MyValueChanged?.Invoke(this, EventArgs.Empty);
}
}
public class MyCustomActivity : CodeActivity
{
protected override void Execute(CodeActivityContext context)
{
var extensionObj = context.GetExtension<MyCommunicationExtension>();
if (extensionObj != null)
{
extensionObj.OnMyValueChanged("Hello World");
}
}
}
}

Dependency Injection in WindowsForm Application C#

i am currently creating the structure of a windows form application. I encountered the NULL REFERENCE Error when implementing dependency injection. I was using this kind of approach in my MVC applications for easy unit testing but cant figure it out how to implement it here in windows form application.
This is the partial class of the Main form:
public partial class pws : Form
{
private IInterfaceTasks _tasks { get; set; }
public pws(IInterfaceTasks tasks)
{
InitializeComponent();
_tasks = tasks;
}
private void cmdSave_Click(object sender, EventArgs e)
{
IEntities.AssignmentEntityRequest request = new IEntities.AssignmentEntityRequest();
<code mapping here>
_tasks.CreateAssignments(request); --> _tasks here is null
}
}
Here is the class that is inheriting the IServiceTasks interface
public class CreateAssignmentsInterface : IInterfaceTasks
{
private Service.IServiceTasks _task;
public CreateAssignmentsInterface(Service.IServiceTasks task)
{
_task = task;
}
public bool CreateAssignments(IEntities.AssignmentEntityRequest request)
{
Helpers.Helpers mapper = new Helpers.Helpers();
var assignmentRequest = new SEntities.AssignmentEntityRequest();
assignmentRequest = mapper.MapInterfacetoServiceRequest(request);
_task.CreateAssignment(); --> _task here is null
return true;
}
}
Here is my IServiceTasks Interface
public interface IServiceTasks
{
bool CreateAssignment();
}
And for the IInterfaceTasks Interface
public interface IInterfaceTasks
{
bool CreateAssignments(IEntities.AssignmentEntityRequest request);
}
Can somebody help me how can I implement this right?
update:
pws is being called here
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
IInterfaceTasks tasks = new pws();
Application.Run(new pws(tasks));
}
Your issue is that you're creating a windows form and not calling InitializeComponent() in the default constructor.
So your pws class needs a single constructor like this:
public pws(IInterfaceTasks tasks)
{
InitializeComponent();
_tasks = tasks;
}
Or your multiple constructors like this:
public pws()
{
InitializeComponent();
}
public pws(IInterfaceTasks tasks) : this()
{
_tasks = tasks;
}
I highly recommend the first option, since you're not using a service locator pattern (from what I infer/assume). That's a whole different topic that's not worth diving into.
This is a classic example of constructor overloading. In your Main() method, you'll need to get/instanciate an instance of the IInterfaceTasks implementation and pass it into the pws constructor.
So your code will look like this:
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
IInterfaceTasks interfaceTasks = new **SOME CLASS THAT IMPLEMENTS IInterfaceTasks**
Application.Run(new pws(interfaceTasks));
}

c# register commandline argument don't start new instance

Application c:\pinkPanther.exe is running and it is application i wrote in c#.
Some other application starts c:\pinkPanther.exe purpleAligator greenGazelle OrangeOrangutan and i would like not to start new instance of c:\pinkPanther.exe with these arguments, but to currently running c:\pinkPanther.exe register it and react to it somehow.
How to do it?
EDIT!!!: i'm very sorry about pinkPanther.exe and ruzovyJeliman.exe that caused the confusion - i translated question from my native language and missed it :(
This is assuming your application is a WinForms app, as that will make it easier to keep it open. This is a very simple example, but it will show you the basics:
Add a reference to Microsoft.VisualBasic.
Create an Application class inheriting from WindowsFormsApplicationBase. This base class contains built-in mechanisms for creating a single-instance application and responding to repeated calls on the commandline with new arguments:
using Microsoft.VisualBasic.ApplicationServices;
//omitted namespace
public class MyApp : WindowsFormsApplicationBase {
private static MyApp _myapp;
public static void Run( Form startupform ) {
_myapp = new MyApp( startupform );
_myapp.StartupNextInstance += new Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventHandler( _myapp_StartupNextInstance );
_myapp.Run( Environment.GetCommandLineArgs() );
}
static void _myapp_StartupNextInstance( object sender, Microsoft.VisualBasic.ApplicationServices.StartupNextInstanceEventArgs e ) {
//e.CommandLine contains the new commandline arguments
// this is where you do what you want with the new commandline arguments
// if you want it the window to come to the front:
e.BringToForeground = true;
}
private MyApp( Form mainform ) {
this.IsSingleInstance = true;
this.MainForm = mainform;
}
}
All you have to change in Main() is call Run() on your new class rather than Application.Run():
static class Program {
[STAThread]
static void Main() {
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault( false );
MyApp.Run( new MyMainForm() );
}
}
WindowsFormsApplicationBase has some other capabilities you can explore, as well.
To communicate with the other instance of the application, you need some sort of inter-process communication. Apparently, WCF is the recommended form of IPC in .Net. You can do that with code like this (using WPF, but WinForms would be similar):
[ServiceContract]
public interface ISingletonProgram
{
[OperationContract]
void CallWithArguments(string[] args);
}
class SingletonProgram : ISingletonProgram
{
public void CallWithArguments(string[] args)
{
// handle the arguments somehow
}
}
public partial class App : Application
{
private readonly Mutex m_mutex;
private ServiceHost m_serviceHost;
private static string EndpointUri =
"net.pipe://localhost/RuzovyJeliman/singletonProgram";
public App()
{
// find out whether other instance exists
bool createdNew;
m_mutex = new Mutex(true, "RůžovýJeliman", out createdNew);
if (!createdNew)
{
// other instance exists, call it and exit
CallService();
Shutdown();
return;
}
// other instance does not exist
// start the service to accept calls and show UI
StartService();
// show the main window here
// you can also process this instance's command line arguments
}
private static void CallService()
{
var factory = new ChannelFactory<ISingletonProgram>(
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), EndpointUri);
var singletonProgram = factory.CreateChannel();
singletonProgram.CallWithArguments(Environment.GetCommandLineArgs());
}
private void StartService()
{
m_serviceHost = new ServiceHost(typeof(SingletonProgram));
m_serviceHost.AddServiceEndpoint(
typeof(ISingletonProgram),
new NetNamedPipeBinding(NetNamedPipeSecurityMode.None),
EndpointUri);
m_serviceHost.Open();
}
protected override void OnExit(ExitEventArgs e)
{
if (m_serviceHost != null)
m_serviceHost.Close();
m_mutex.Dispose();
base.OnExit(e);
}
}

Categories

Resources