Ninject web api - System.TypeLoadException - c#

I got this error when using Ninject with Web API.
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
try
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel1);
}
catch (Exception ex)
{
WriteLog(ex.Message +"-------------------------------"+ ex.Source +"---" +ex);
throw;
}
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel1()
{
WriteLog("CreateKernel1 -- 5");
var kernel = new StandardKernel();
try
{
WriteLog("CreateKernel1 -- 6");
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
NinjectServiceRegister ser = new NinjectServiceRegister(kernel);
ser.RegisterServices();
AutoMapperConfig autoMapperConfig = new AutoMapperConfig(kernel);
autoMapperConfig.RegisterServices();
WriteLog("CreateKernel1 -- 7");
kernel.BindHttpFilter<ApiAuthneticatonFilter>(System.Web.Http.Filters.FilterScope.Global).WhenControllerHas<CollectorsAuthenticationAttribute>();
kernel.BindHttpFilter<CollectorsAuthorizationFilter>(System.Web.Http.Filters.FilterScope.Global).WhenControllerHas<CollectorsAuthroizationAttribute>();
WriteLog("CreateKernel1 -- 8");
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
return kernel;
}
catch(Exception ex)
{
WriteLog("Authenticate -- 9" + ex.Message);
kernel.Dispose();
throw;
}
}
error message:
-CollectorsApp.MobileWebAPI---System.TypeLoadException: Method 'ExecuteAuthorizationFilterAsync' in type
'CollectorsApp.MobileWebAPI.InfraStructure.Authorization.CollectorsAuthorizationFilter'
from assembly 'CollectorsApp.MobileWebAPI, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null' does not have an implementation.
at
CollectorsApp.MobileWebAPI.App_Start.NinjectWebCommon.CreateKernel1()
at Ninject.Web.Common.Bootstrapper.Initialize(Func`1
createKernelCallback) at
CollectorsApp.MobileWebAPI.App_Start.NinjectWebCommon.Start() in
D:\IGATE\InvogateWeb-Siva\InvogateWeb\CollectorsApp.MobileWebAPI\App_Start\NinjectWebCommon.cs:line
34

Related

SQLiteOpenHelper - Cannot access disposed object

I have a my SQLiteOpenHelper class, which is written as a singleton. I should note that I am not doing this in Java, I am using Xamarin.Android C# to write this.
Here's a snippet from that class:
public class DatabaseHelper : SQLiteOpenHelper
{
private static readonly string TAG = typeof(DatabaseHelper).FullName;
private static readonly string _databaseName = "istockdb";
private static readonly int _databaseVersion = 32;
private static DatabaseHelper _instance;
private Context _context;
private DatabaseHelper(Context context) : base(context, _databaseName, null, _databaseVersion)
{
_context = context;
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static DatabaseHelper Instance(Context context)
{
// *** Use the application context, which will ensure that ***
// *** the Activity's context is not accidentally leaked ***
return _instance ?? (_instance = new DatabaseHelper(context.ApplicationContext));
}
}
So I have my DatabaseHelper that is a singleton and is used like this within Activities and Services:
Service:
[Service(Name=Text.MobileBackgroundHbService, Enabled = true, Exported = true), IntentFilter(new []{Intents.SyncHeartbeats})]
public class BGHeartbeatService : BaseIntentService
{
public BGHeartbeatService()
{
this._database = DatabaseHelper.Instance(Application.Context);
}
protected override void OnHandleIntent(Intent intent)
{
if (this._database == null)
this._database = DatabaseHelper.Instance(Application.Context);
if (intent.Action.Equals(Intents.SyncHeartbeats)) SyncHeartbeatRecords();
var broadcastIntent = new Intent(Intents.MobileRefresh);
SendBroadcast(broadcastIntent);
}
}
Activity, actually a BaseActivity which all Activities inherit from:
[Activity(Label = "BaseActivity")]
public abstract class BaseActivity : AppCompatActivity
{
/// <summary>
/// Reference to the current context.
/// </summary>
protected Context _context { get; set; }
/// <summary>
/// "Tag" used for Log functionallity.
/// </summary>
protected string _tag { get; set; }
/// <summary>
/// Reference To <see cref="RemoteSyncServiceConnection"/>
/// </summary>
protected RemoteSyncServiceConnection _service_connection;
/// <summary>
/// Reference To The Current SessionState.
/// </summary>
protected SessionState _session_state;
/// <summary>
/// Reference To <see cref="SyncReceiver"/>
/// </summary>
protected SyncReceiver _sync_receiver;
/// <summary>
/// Base FloatingActionButton.
/// </summary>
protected FloatingActionButton _base_fab;
/// <summary>
/// Is the Fab Menu Shown / Hid.
/// </summary>
protected static bool _is_fab_open;
protected IConnection _printer_connection;
protected string _printer_address;
protected bool _service_required;
protected bool _receiver_required;
protected MediaPlayer _media_player;
protected DatabaseHelper _database;
/// <summary>
/// <see cref="IntentFilter"/> for the <see cref="SyncReceiver"/>
/// </summary>
protected readonly string[] _intent_filters =
{
Intents.AlarmCompleteOrders,
Intents.AlarmHeartbeats,
Intents.AlarmPkas,
Intents.AlarmTrackingScans,
Intents.MobileRefresh
};
#region Lifecycle Methods
/// <summary>
/// Application Lifecycle Method.
/// </summary>
/// <param name="savedInstanceState"></param>
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// *** Initialize Xamarin.Essentials ***
Xamarin.Essentials.Platform.Init(this, savedInstanceState);
// *** Initialize the DatabaseHelper ***
if(this._database == null)
this._database = DatabaseHelper.Instance(this.ApplicationContext);
}
}
The DatabaseHelper instance is being disposed of frequently causing either services, or activities to try and access the disposed _database object.
How is this being disposed of and why?
I thought making the _instance static within the DatabaseHelper as well as making the constructor private and forcing the use of the DatabaseHelper.Instance method would keep a single instance of the DatabaseHelper that wouldn't be disposed of between activities and services?
Am I misunderstanding this?
EDIT logcat output from try/catch blocks showing the exception being thrown. The SaveHeartbeat method exists in the base activity.:
protected void SaveHeartbeat(DateTime time, string sourceActivity, [CallerMemberName] string sourceEvent = "")
{
try
{
var heartbeat = new SmartWarehouse.Shared.Models.Heartbeat(sourceActivity,
sourceEvent,
this._session_state.CurrentSession.ROWID.ToString());
this._database.InsertHeartbeat(heartbeat);
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
}
EDIT 2 DatabaseHelper.InsertHeartbeat():
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
Alright so my theory is that when I access the db object in the using() statement it is disposing of the database that the DatabaseHelper object uses. Also noticed that I'm not using db.InsertOrThrow() method which I should be.. Gonna do some re-working on my DatabaseHelper class to see if that resolves the issue.
It turns out that my singleton instance of the DatbaseHelper was not being disposed of.
Actually what was happening is I was disposing of the SQLiteDatabase object that was being used by the DatbaseHelper from within the helper methods.
All I had to do to actually resolve the issue was change:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This using() statement is causing the disposal
using (var db = this.WritableDatabase)
{
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
}
TO:
/// <summary>
/// Inserts a Heartbeat record into local DB.
/// </summary>
/// <param name="heartbeat"></param>
/// <returns></returns>
public long InsertHeartbeat(Heartbeat heartbeat)
{
if (heartbeat == null) return -2L;
// This is no longer initialized in a using() statement
var db = this.WritableDatabase;
var id = -3L;
db.BeginTransactionNonExclusive();
try
{
var cv = GetContentValues(heartbeat);
id = db.Insert(DatabaseSchema.Heartbeat.TableName, null, cv);
db.SetTransactionSuccessful();
}
catch (Exception e)
{
// TODO: Document Exception
Util.Tools.Bark(e);
}
finally
{
db.EndTransaction();
}
return id;
}
SUMMARY:
By initializing my SQLiteDatabase db object inside of using() statements inside of my helper methods I was disposing of the SQLiteDatabase that my DatabaseHelper needed.

Error loading Ninject component ICache using Web API 2

I'm receiving the following error when executing the web api controller.
I receive this error:
Error loading Ninject component ICache\r\nNo such component has been
registered in the kernel's component container.
The controller I am calling has several Interfaces which are used by the controller.
My controller constructor:
private ISDKConfiguration iSDKConfiguration;
private ISDKLogin iSDKLogin;
private ISDKLogout iSDKLogout;
private ISDKRetrieveUserSession iSDKRetrieveUserSession;
public SDKAccountController(ISDKConfiguration sdkConfiguration, ISDKLogin sdkLogin, ISDKLogout sdkLogout, ISDKRetrieveUserSession sdkRetrieveUserSession)
{
iSDKConfiguration = sdkConfiguration;
iSDKLogin = sdkLogin;
iSDKLogout = sdkLogout;
iSDKRetrieveUserSession = sdkRetrieveUserSession;
}
My HTTP Post Method
[HttpPost]
[Route("Login")]
public SDKUserDTO Login([FromBody]SDKUserDTO sdkUserDTO)
{
iSDKConfiguration.Load();
iSDKLogin.SDKUserDTO = sdkUserDTO;
iSDKLogin.Process();
iSDKRetrieveUserSession.SDKUserDTO = sdkUserDTO;
sdkUserDTO = iSDKRetrieveUserSession.Process();
return sdkUserDTO;
}
The NinjectWebCommon.cs which was included when I downloaded the Ninject.Web.Common.WebHost nuget package.
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>
/// The created kernel.
/// </returns>
private static IKernel CreateKernel()
{
var kernel = new StandardKernel();
try
{
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
RegisterServices(kernel);
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
return kernel;
}
catch
{
kernel.Dispose();
throw;
}
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">
/// The kernel.
/// </param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ISDKConfiguration>().To<SDKConfiguration>();
kernel.Bind<ISDKLogin>().To<SDKLogin>();
kernel.Bind<ISDKLogout>().To<SDKLogout>();
kernel.Bind<ISDKRetrieveUserSession>().To<SDKRetrieveUserSession>();
}
}
I've edited as per several articles online to include this line of code
System.Web.Http.GlobalConfiguration.Configuration.DependencyResolver = new Ninject.Web.WebApi.NinjectDependencyResolver(kernel);
I'm expecting to return the following json.
{
"UserID": "dhu",
"Password": "password",
"Identifier": "LoginTestUsingPostman"
}
But it's throwing the above exception.

I can't deal with the fileSystemWatcher

Today my problem is in that i can't deal with the fileSystemWatcher (even with debug).
So... i want to use the function GetHashFromFile(string path, HashAlgorithm algorithm ) while the fileSystemWatcher is watching the choosen directory. Once it gets an change in this directory (File has been created, re-named, change..) i want to use the e.fullPath as 1st argument in GetHashFromFile, but it throws me an exception about that this file can't be found. Could someone tell me on wich place in the code should i use the GetHashFromFile() ?
Thanks !
Here is some sample code which I created for a different SO question which correctly uses FileSystemWatcher to process files which should meet your needs
using System;
using System.Collections.Concurrent;
using System.Globalization;
using System.Reactive.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using System.Security.Permissions;
namespace ConsoleApplication9
{
internal class Program
{
private static void Main(string[] args)
{
const string directorytowatch = #"d:\junk\watch\"; // the directory to watch for new files
// this initiates a filesystemmonitor to watch for new files being created
Task.Factory.StartNew(() => FileSystemMonitor.Instance.WatchDirectory(directorytowatch));
// initiate the processing of any new files
FilesWorker.Instance.ReadQueue();
Console.ReadLine();
}
}
/// <summary>
/// Monitors the filesystem in "real-time" to check for new files
/// </summary>
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
internal class FileSystemMonitor : SingletonBase<FileSystemMonitor>
{
private FileSystemMonitor()
{
}
internal void WatchDirectory(string dir)
{
var watcher = new FileSystemWatcher(dir)
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.LastAccess,
Filter = "*.*"
};
// watch all files
watcher.Created += WatcherOnCreated;
watcher.EnableRaisingEvents = true;
}
private static void WatcherOnCreated(object sender, FileSystemEventArgs fileSystemEventArgs)
{
Console.WriteLine(fileSystemEventArgs.FullPath + "" + fileSystemEventArgs.ChangeType); // for test purposes
var fileInfo = new FileInfo(fileSystemEventArgs.FullPath);
FilesWorker.Instance.AddToQueue(fileInfo);
}
}
/// <summary>
/// handles the queue of files to be processed and the syncronisation of tasks related to the queue
/// </summary>
internal class FilesWorker : SingletonBase<FilesWorker>
{
private FilesWorker()
{
}
/// <summary>
/// The queue of files which still need to be processed
/// </summary>
private readonly ConcurrentQueue<FileInfo> _filesQueue = new ConcurrentQueue<FileInfo>();
/// <summary>
/// create a semaphore to limit the number of threads which can process a file at any given time
// In this case only allow 2 to be processed at any given time
/// </summary>
private static readonly SemaphoreSlim Semaphore = new SemaphoreSlim(2, 2);
/// <summary>
/// add new file to the queue
/// </summary>
/// <param name="fileInfo"></param>
internal void AddToQueue(FileInfo fileInfo)
{
_filesQueue.Enqueue(fileInfo);
}
/// <summary>
/// executes a method on a given timeframe
/// </summary>
/// <param name="method">method to execute</param>
/// <param name="timer">time between execution runs (seconds)</param>
internal void ExecuteMethod(Action method, double timer)
{
IObservable<long> observable = Observable.Interval(TimeSpan.FromSeconds(timer));
// Token for cancelation
var source = new CancellationTokenSource();
observable.Subscribe(x =>
{
var task = new Task(method);
task.Start();
}, source.Token);
}
/// <summary>
/// Get any new files and send for processing
/// </summary>
internal void ReadQueue()
{
// check the queue every two seconds
ExecuteMethod(ProcessQueue, 2d);
}
/// <summary>
/// takes files from the queue and starts processing
/// </summary>
internal void ProcessQueue()
{
try
{
Semaphore.Wait();
FileInfo fileInfo;
while (_filesQueue.TryDequeue(out fileInfo))
{
var fileProcessor = new FileProcessor();
fileProcessor.ProcessFile(fileInfo);
}
}
finally
{
Semaphore.Release();
}
}
}
internal class FileProcessor
{
internal void ProcessFile(FileInfo fileInfo)
{
// do some long running tasks with the file
}
}
/// <summary>
/// Implements singleton pattern on all classes which derive from it
/// </summary>
/// <typeparam name="T">Derived class</typeparam>
public abstract class SingletonBase<T> where T : class
{
public static T Instance
{
get { return SingletonFactory.Instance; }
}
/// <summary>
/// The singleton class factory to create the singleton instance.
/// </summary>
private class SingletonFactory
{
static SingletonFactory()
{
}
private SingletonFactory()
{
}
internal static readonly T Instance = GetInstance();
private static T GetInstance()
{
var theType = typeof(T);
T inst;
try
{
inst = (T)theType
.InvokeMember(theType.Name,
BindingFlags.CreateInstance | BindingFlags.Instance
| BindingFlags.NonPublic,
null, null, null,
CultureInfo.InvariantCulture);
}
catch (MissingMethodException ex)
{
var exception = new TypeLoadException(string.Format(
CultureInfo.CurrentCulture,
"The type '{0}' must have a private constructor to " +
"be used in the Singleton pattern.", theType.FullName)
, ex);
//LogManager.LogException(LogManager.EventIdInternal, exception, "error in instantiating the singleton");
throw exception;
}
return inst;
}
}
}
}

how to use Ninject intercept using InterceptAttribute

I have a NinjectWebCommon as follow. I am unable to get the TimingInterceptor to trigger on the method that has "Timing" attribute set. It works fine if the intercetor is defined at the class level where all method call is going to be intercepted, but I would like to have the ability to specify the method I want to intercept (opt in).
I do have the Ninject.Extensions.Interception.DynamicProxy added.
public static class NinjectWebCommon
{
private static readonly Bootstrapper bootstrapper = new Bootstrapper();
/// <summary>
/// Starts the application
/// </summary>
public static void Start()
{
DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
bootstrapper.Initialize(CreateKernel);
}
/// <summary>
/// Stops the application.
/// </summary>
public static void Stop()
{
bootstrapper.ShutDown();
}
/// <summary>
/// Creates the kernel that will manage your application.
/// </summary>
/// <returns>The created kernel.</returns>
private static IKernel CreateKernel()
{
var NinjectSettings = new NinjectSettings();
var kernel = new StandardKernel(NinjectSettings);
kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
GlobalConfiguration.Configuration.DependencyResolver = new BazingaNinjectResolver(kernel);
RegisterServices(kernel);
return kernel;
}
/// <summary>
/// Load your modules or register your services here!
/// </summary>
/// <param name="kernel">The kernel.</param>
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IMyService>().To<MyService>().InRequestScope();
}
}
my Service class define as follow
public class MyService : IMyService
{
Logger log;
public MyService()
{
log = LogManager.GetLogger(this.GetType().FullName);
}
[Timing]
public string GetString()
{
log.Info("log me!!");
return "Cool string !!!!";
}
public string GetUnInterceptString()
{
return "Not intercepted";
}
}
Interceptor and attribute define as follows
public class TimingAttribute : InterceptAttribute
{
public override IInterceptor CreateInterceptor(IProxyRequest request)
{
return request.Context.Kernel.Get<TimingInterceptor>();
}
}
public class TimingInterceptor : SimpleInterceptor
{
readonly Stopwatch _stopwatch = new Stopwatch();
protected override void BeforeInvoke(IInvocation invocation)
{
_stopwatch.Start();
}
protected override void AfterInvoke(IInvocation invocation)
{
_stopwatch.Stop();
string message = string.Format("Execution of {0} took {1}.",
invocation.Request.Method,
_stopwatch.Elapsed);
_stopwatch.Reset();
}
}
You need it to be virtual, for ninject to intercept it:
public class MyService : IMyService
{
Logger log;
public MyService()
{
log = LogManager.GetLogger(this.GetType().FullName);
}
[Timing]
public virtual string GetString()
{
log.Info("log me!!");
return "Cool string !!!!";
}
public string GetUnInterceptString()
{
return "Not intercepted";
}
}

How can I invoke a method within another process instance of my WinForms app?

I am working on an application that uses a Mutex to ensure that it is the only instance of the application running on the system.
When another instance of the application attempts to start, I want a method to run in the original instance.
Can I invoke a specific method in my application from another instance of the application?
I've found some examples using RegisterWindowMessage/PostMessage Win32 APIs by sending the message to HWND_BROADCAST, but I couldn't get them to work, and I've read elsewhere that using HWND_BROADCAST can be dangerous.
Is there a better way to do this that doesn't involve the app needing to be run in privileged mode?
Here's a little helper I wrote.
To use it:
var pipeListener = new NamedPipeListener<String>(); // instantiate an instance
pipeListener.MessageReceived += (sender, e) => MessageBox.Show(e.Message); // when a message is received, show a messagebox with the message
pipeListener.Error += (sender, e) => MessageBox.Show("Error ({0}): {1}", e.ErrorType, e.Exception.Message); // oh noes!
pipeListener.Start(); // when you're ready, start listening
From another process:
NamedPipeListener<String>.SendMessage("Howdy howdy howdy");
Note that it uses the full name of the PipeListener as the default name of the pipe. If you need to get more discrete than that, use the constructor overload that takes a pipe name.
Here's the class:
using System;
using System.IO.Pipes;
using System.Runtime.Serialization.Formatters.Binary;
namespace FunWithNamedPipes
{
/// <summary>Contains event data for <see cref="NamedPipeMessageReceiveHandler{TMessage}" /> events.</summary>
/// <typeparam name="TMessage"></typeparam>
public class NamedPipeListenerMessageReceivedEventArgs<TMessage> : EventArgs
{
/// <summary>Initializes an instance of <see cref="NamedPipeListenerMessageReceivedEventArgs{TMessage}" /> with the specified <paramref name="message" />.</summary>
/// <param name="message">The message passed by the event.</param>
public NamedPipeListenerMessageReceivedEventArgs(TMessage message)
{
this.Message = message;
}
/// <summary>Gets the message passed by the event.</summary>
public TMessage Message { get; private set; }
}
/// <summary>Contains event data for <see cref="NamedPipeListenerErrorEventHandler" /> events.</summary>
public class NamedPipeListenerErrorEventArgs : EventArgs
{
/// <summary>Initializes an instance of <see cref="NamedPipeListenerErrorEventArgs" /> with the specified <paramref name="errorType" /> and <paramref name="exception" />.</summary>
/// <param name="errorType">A <see cref="NamedPipeListenerErrorType" /> describing the part of the listener process where the error was caught.</param>
/// <param name="ex">The <see cref="Exception" /> that was thrown.</param>
public NamedPipeListenerErrorEventArgs(NamedPipeListenerErrorType errorType, Exception ex)
{
this.ErrorType = errorType;
this.Exception = ex;
}
/// <summary>Gets a <see cref="NamedPipeListenerErrorType" /> describing the part of the listener process where the error was caught.</summary>
public NamedPipeListenerErrorType ErrorType { get; private set; }
/// <summary>Gets the <see cref="Exception" /> that was caught.</summary>
public Exception Exception { get; private set; }
}
/// <summary>Represents a method that will handle an event where a message is received via named pipes.</summary>
/// <typeparam name="TMessage">The type of message that will be received.</typeparam>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The event data passed by the event, which includes the message that was received.</param>
public delegate void NamedPipeMessageReceivedHandler<TMessage>(Object sender, NamedPipeListenerMessageReceivedEventArgs<TMessage> e);
/// <summary>Represents a method that will handle an event that is fired when an exception is caught.</summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">The event data passed by the event, included the error type and exception that was caught.</param>
public delegate void NamedPipeMessageErrorHandler(Object sender, NamedPipeListenerErrorEventArgs e);
/// <summary>Includes different types of errors that describe where in the listening process an exception was caught.</summary>
public enum NamedPipeListenerErrorType : byte
{
/// <summary>Indicates that an exception was caught while calling <see cref="NamedPipeServerStream.BeginWaitForConnection" />.</summary>
BeginWaitForConnection = 1,
/// <summary>Indicates that an exception was caught while calling <see cref="NamedPipeServerStream.EndWaitForConnection" />.</summary>
EndWaitForConnection = 2,
/// <summary>Indicates that an exception was caught while deserializing a message received from the named pipe.</summary>
DeserializeMessage = 3,
/// <summary>Indicates that an exception was caught while closing or disposing a used named pipe.</summary>
CloseAndDisposePipe = 4,
/// <summary>Indicates that an exception was caught while invoking the <see cref="NamedPipeListener{TMessage}.MessageReceived"/> event.</summary>
NotifyMessageReceived = 5
}
/// <summary>A helper class for sending and receiving messages using named pipes.</summary>
/// <typeparam name="TMessage">The type of message that will be sent or received.</typeparam>
public class NamedPipeListener<TMessage> : IDisposable
{
/// <summary>Occurs when a message is received.</summary>
public event NamedPipeMessageReceivedHandler<TMessage> MessageReceived;
/// <summary>Occurs when an exception is caught.</summary>
public event NamedPipeMessageErrorHandler Error;
static readonly String DEFAULT_PIPENAME = typeof(NamedPipeListener<TMessage>).FullName;
static readonly BinaryFormatter formatter = new BinaryFormatter();
NamedPipeServerStream pipeServer;
/// <summary>Initializes a new instance of <see cref="NamedPipeListener{TMessage}" /> using the specified <paramref name="pipeName" />.</summary>
/// <param name="pipeName">The name of the named pipe that will be used to listen on.</param>
public NamedPipeListener(String pipeName)
{
this.PipeName = pipeName;
}
/// <summary>Initializes a new instance of <see cref="NamedPipeListener{TMessage}" /> using the default pipe name.</summary>
/// <remarks>The default pipe name is the full name of the type of the instance.</remarks>
public NamedPipeListener()
: this(DEFAULT_PIPENAME) { }
/// <summary>The name of the named pipe that will be used to listen on.</summary>
public String PipeName { get; private set; }
/// <summary>Starts listening on the named pipe specified for the instance.</summary>
internal void Start()
{
if (pipeServer == null) pipeServer = new NamedPipeServerStream(DEFAULT_PIPENAME, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
try { pipeServer.BeginWaitForConnection(new AsyncCallback(PipeConnectionCallback), null); }
catch (Exception ex) { this.OnError(NamedPipeListenerErrorType.BeginWaitForConnection, ex); }
}
private void PipeConnectionCallback(IAsyncResult result)
{
try
{
pipeServer.EndWaitForConnection(result);
}
catch (Exception ex)
{
this.OnError(NamedPipeListenerErrorType.EndWaitForConnection, ex);
return;
}
TMessage message;
try
{
message = (TMessage)formatter.Deserialize(pipeServer);
}
catch (Exception ex)
{
this.OnError(NamedPipeListenerErrorType.DeserializeMessage, ex);
return;
}
try
{
this.OnMessageReceived(new NamedPipeListenerMessageReceivedEventArgs<TMessage>(message));
}
catch (Exception ex)
{
this.OnError(NamedPipeListenerErrorType.NotifyMessageReceived, ex);
return;
}
if (this.End())
{
this.Start();
}
}
internal Boolean End()
{
try
{
pipeServer.Close();
pipeServer.Dispose();
pipeServer = null;
return true;
}
catch (Exception ex)
{
this.OnError(NamedPipeListenerErrorType.CloseAndDisposePipe, ex);
return false;
}
}
private void OnMessageReceived(TMessage message)
{
this.OnMessageReceived(new NamedPipeListenerMessageReceivedEventArgs<TMessage>(message));
}
protected virtual void OnMessageReceived(NamedPipeListenerMessageReceivedEventArgs<TMessage> e)
{
if (this.MessageReceived != null)
{
this.MessageReceived(this, e);
}
}
private void OnError(NamedPipeListenerErrorType errorType, Exception ex)
{
this.OnError(new NamedPipeListenerErrorEventArgs(errorType, ex));
}
protected virtual void OnError(NamedPipeListenerErrorEventArgs e)
{
if (this.Error != null)
{
this.Error(this, e);
}
}
void IDisposable.Dispose()
{
if(pipeServer != null)
{
try { pipeServer.Disconnect(); }
catch { }
try { pipeServer.Close(); }
catch { }
try { pipeServer.Dispose(); }
catch { }
}
}
/// <summary>Sends the specified <paramref name="message" /> to the default named pipe for the message.</summary>
/// <param name="message">The message to send.</param>
public static void SendMessage(TMessage message)
{
NamedPipeListener<TMessage>.SendMessage(DEFAULT_PIPENAME, message);
}
/// <summary>Sends the specified <paramref name="message" /> to the specified named pipe.</summary>
/// <param name="pipeName">The name of the named pipe the message will be sent to.</param>
/// <param name="message">The message to send.</param>
public static void SendMessage(String pipeName, TMessage message)
{
using (var pipeClient = new NamedPipeClientStream(".", DEFAULT_PIPENAME, PipeDirection.Out, PipeOptions.None))
{
pipeClient.Connect();
formatter.Serialize(pipeClient, message);
pipeClient.Flush();
pipeClient.WaitForPipeDrain();
pipeClient.Close();
}
}
}
}
I've done research on this before - you can use a memory mapped file, demonstrated in this article http://www.codeproject.com/KB/cs/singleinstanceapplication.aspx, or you can do what I did (the easy way) and take advantage of vb.net features (specifically, one that lets you make single instance apps and calls a method in the currently running instance that passes on command line args [so you could use it to invoke the method in your application]). I know using VB classes in C# sounds a bit poor but it's the most abstract and easy way. Link to the relevant articles - http://www.codeproject.com/KB/cs/CSSIApp.aspx, last part of http://msdn.microsoft.com/en-us/magazine/cc163741.aspx

Categories

Resources