windows application Logging mechanism - c#

I am developing a Windows Application. I am displaying log information in the main form. I want to add logging information from another class. Below is the code on a button click event:
private void button1_Click(object sender, EventArgs e)
{
IDAL dal = new LoadCaseDAL();
Result result = new Result();
dal.Load(result);
AddToLogger("test end");
}
AddtoLogger(){ }
AddtoLogger() and button click event are in main form.
In dal.Load(result) method I am calling this function. I want to add log information in this function to the main form using AddToLogger() method.
protected internal void LoadLCFiles(BoltDataset.LoadCaseDataTable dt)
{
List<string> files = Helper.GetFiles("Text Files|*.txt");
**//AddToLogger("Total files: " + files.Count().ToString());**
Task loadFilesTask = Task.Factory.StartNew(() =>
{
foreach (string filePath in files)
{
LoadLCTextFile(filePath, dt);
}
}).ContinueWith(t =>
{
if (t.IsFaulted)
{
**//AddToLogger("Loading Failed");**
}
else if (t.IsCompleted)
{
**//AddToLogger("Loading Succesfull");**
}
});
}
How can I achieve this ? Kindly suggest.

You can put your logging function in a static class. That way it will be available everywhere in your code and does not need an object in order to execute it.
public static class Tools
{
public static void AddToLogger(string msg) { ... }
}
Now build a delegate that you call inside AddToLogger() everytime you add a message:
// Delegate for new log entries
public delegate void LogEntryAddedDelegate(string message);
public static LogEntryAddedDelegate LogEntryAdded { get; set; }
Then call it in your AddToLogger() function. So your static class should then look something like this:
public static class Tools
{
// Delegate for new log entries
public delegate void LogEntryAddedDelegate(string message);
public static LogEntryAddedDelegate LogEntryAdded { get; set; }
public static void AddToLogger(string msg)
{
// Do some stuff here
// Call the event
LogEntryAdded(msg);
}
}
Then you can hook to your event in your form like this:
// Registers your function to get called when a new log message is added
Tools.LogEntryAdded += new Tools.LogEntryAddedDelegate(NewLogAdded);
protected void NewLogAdded(string msg)
{
// Update your textbox
}
Then you can add new log messages like this:
Tools.AddToLogger("msg");
This way your function NewLogAdded() gets called every time you add a new message to the log.
Also you might want to take a look at logging frameworks. They make logging stuff much easier and you don't have to code it on your own.
A good logging library for .Net is log4net

Related

C# EventHandler : How to handle EventHandler in client application?

I have written a class library(dll) which handle Telephony calls. This class library has delegates that handle phone call events such as OnCallReceived, OnHoldCall etc.
So now i want to add this class library to my Windows Forms App, and be able to handle Phone Call events(OnCall, OnHolde etc) in my Windows Forms application. How can achieve this?
For example
//My Class Library
Class Test
{
ThirdParyLibrary tpl
public Test()
{
tpl= new tpl();
tpl.OnReceiveCall += Handler(OnReceiveCall);
}
public void OnReceiveCall()
{
//i want this event to take place in client app
}
}
//My Windows Forms App
Client App
public main()
{
Test t =new Test()
//i want OnReceiveCall to be processed here
//t.OnReceiveCall
{
Message.Show('You received a call');
}
}
// i want this event to take place in client app
Since you want the Event Handling mechanism to take place in the Client App, which I suppose is another Class containing Main, I have created a small console that replicates the problem scenario
Uploaded to fiddle as well
using System;
namespace Test
{
public class ThirdPartyLibrary
{
public delegate void dEeventRaiser();
public event dEeventRaiser OnReceiveCall;
public string IncomingCall(int x)
{
if (x > 0 && OnReceiveCall != null)
{ OnReceiveCall(); return "Valid "+x.ToString(); }
return "Invalid"+x.ToString();
}
}
public class EventSubscription
{
public EventSubscription()
{
ThirdPartyLibrary a = new ThirdPartyLibrary();
a.OnReceiveCall += HandleTheCall;
var iAnswer = a.IncomingCall(24198724);
Console.WriteLine("Call received from "+iAnswer);
}
public virtual void HandleTheCall()
{
Console.WriteLine("Default way I handle the call");
}
}
public class Program : EventSubscription
{
public override void HandleTheCall()
{
Console.WriteLine("Override sucessful, new way to handle the call ");
}
static void Main(string [] args)
{
Program pb = new Program(); // Control goes EnventSubscription constructor as it is derived
Console.Read();
}
}
}
Output:

Custom event and invocation on main thread

I was given a generic API class, that contains a custom event which always needs to be invoked by the main UI thread.
My job is to banish these invocation call from the custom class, to make it "painless".
It should be synchronized like the default events in WinForms (eg the Timer "Elapsed" event, which also needs no invocation when it published values to a text box)
Is it possible to solve this, since the custom class needs to know where to invoke?
Here's the (important part of the) code:
public class ContactSensorHelper
{
public event OnReleaseStateChanged ReleaseStateChanged;
public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
private ContactSensorEventArgs.ReleaseState recentReleaseState;
public void ReportStateChanged()
{
if (ReleaseStateChanged != null)
ReleaseStateChanged(new ContactSensorEventArgs()
{
State = recentReleaseState
});
}
public class ContactSensorEventArgs : EventArgs
{
//......
public ReleaseState State { get; set; }
//......
public enum ReleaseState
{
FullReleased,
PartlyReleased,
NotReleased
}
}
}
The call from main UI:
public void SensorInit()
{
//....
sensorHelper.ReleaseStateChanged += releaseStateChanged;
//....
}
private void releaseStateChanged(ContactSensorEventArgs e)
{
//example
textBox1.Text = e.State.ToString(); // Thread exception (obviously)
}
Does anybody have me a hint to start?
You could do this by using your own event calling, and storing a reference to the thread, when the event is attached.
With the event add/remove syntax, you can have the caller attach to the event like before, but internally you store a list, with a reference to the thread (using an AsyncOperation) and the delegate to be called (used a Tuple containing both in the example)
Below is an example. I tested it, and it worked as expected when testing, but you might have to add some locking of the list to make it thread safe in case events are added/removed simultaneously.
public class ContactSensorHelper:IDisposable
{
public delegate void OnReleaseStateChanged(ContactSensorEventArgs e);
private ContactSensorEventArgs.ReleaseState recentReleaseState;
public void ReportStateChanged()
{
if (statechangedList.Count > 0)
{
var e = new ContactSensorEventArgs()
{
State = recentReleaseState
};
statechangedList.ForEach(t =>
t.Item1.Post(o => t.Item2((ContactSensorEventArgs)o), e));
}
}
List<Tuple<AsyncOperation, OnReleaseStateChanged>> statechangedList = new List<Tuple<AsyncOperation,OnReleaseStateChanged>>();
public event OnReleaseStateChanged ReleaseStateChanged
{
add
{
var op = AsyncOperationManager.CreateOperation(null);
statechangedList.Add(Tuple.Create(op, value));
}
remove
{
var toremove = statechangedList.Where(t => t.Item2 == value).ToArray();
foreach (var t in toremove)
{
t.Item1.OperationCompleted();
statechangedList.Remove(t);
}
}
}
public void Dispose()
{
statechangedList.ForEach(t => t.Item1.OperationCompleted());
statechangedList.Clear();
}
public class ContactSensorEventArgs : EventArgs
{
//......
public ReleaseState State { get; set; }
//......
public enum ReleaseState
{
FullReleased,
PartlyReleased,
NotReleased
}
}
}

Instantiating a delegate method to be used in a class library

I'm building an email-monitoring framework that I'll be using for a handful of users, so I'm building a class library to wrap everything in. I'm instantiating the configuration (sender, subject, last-received, ...) in a static class. Therefore, I have something like this.
public static class MyConfig
{
public static int Sender { get; set; }
// and so on and so forth
public static void BuildMyConfig(string theSender, string theRecipient, ...)
{
Sender = theSender;
// yada yada yada...
}
}
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Obviously, what we do with the email will be something completely different in each case. What I'm trying to is instantiate that delegate. Where would I do that? The MyConfig class and then invoke it from there as a static method? The instance of the Monitoring class?
An application would look like...
public class SpecificMonitor
{
Monitoring.BuildMyConfig("foo#bar.com", "bar#foo.com", ...);
Monitoring m = new Monitoring();
m.StartMonitoring();
//But where do I build the delegate method???
}
I've gotten compiling errors with every option I've tried so far. I've also tried overriding a method instead of using a delegate, using interfaces... but I think delegation is where it's at.
Thanks in advance!
Consistent with the rest of your design (although I do not necessarily agree that the design is great) you could allow for the callback to be set in the configuration class
public static class MyConfig
{
public static string Sender { get; set; }
public static DoSomethingWithEmail EmailReceivedCallback { get; set; }
public static void BuildMyConfig(string theSender, string theRecipient,
DoSomethingWithEmail callback)
{
Sender = theSender;
EmailReceivedCallback = callback;
}
}
// Make sure you bring the delegate outside of the Monitoring class!
public delegate void DoSomethingWithEmail(string theContents);
When an incoming email is acknowledged by your application you can now pass the email to the callback assigned to the configuration class
public class Monitoring
{
public void StartMonitoring()
{
const string receivedEmail = "New Answer on your SO Question!";
//Invoke the callback assigned to the config class
MyConfig.EmailReceivedCallback(receivedEmail);
}
}
Here is an example of usage
static void Main()
{
MyConfig.BuildMyConfig("...", "...", HandleEmail);
var monitoring = new Monitoring();
monitoring.StartMonitoring();
}
static void HandleEmail(string thecontents)
{
// Sample implementation
Console.WriteLine("Received Email: {0}",thecontents);
}
Define the constructor so that when people instantiate a Monitoring object, they must define the delegate:
public class Monitoring
{
public delegate void DoSomethingWithEmail(EmailContents theContents);
public Monitoring(Delegate DoSomethingWithEmail)
{
this.DoSomethingWithEmail = DoSomethingWithEmail;
}
public void StartMonitoring() {
//When I get an email, I call the method
DoSomethingWithEmail(theEmailWeJustGot);
}
}
Then pass in the delegate you want when you instantiate each Monitoring:
Monitoring m = new Monitoring(delegate(EmailContents theContents)
{
/* Do stuff with theContents here */
});
m.StartMonitoring();

C# Multiple class events

Im making a program what connects to multiple 3th party systems. The connect with different formats so i created multiple classes to deal with them. I have now three 4 classes.
The MainForm is the first class. This is the basic windows form class with the user interface.
SDKCommunication is the second class.
VMS (this class handles the events given of by the 2th party system and activates methods on SDK COmmunication)
Events
Events Class
public class Events
{
public event EventHandler LoginStateChanged;
private bool loginstate;
public bool LogInState
{
get { return this.loginstate; }
set
{
this.loginstate = value;
if (this.LoginStateChanged != null)
this.LoginStateChanged(this, new EventArgs());
}
}
}
part of SDKCommunicatie class
Events events = new Events();
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
MainForm Class
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
When the LogInState Changes in the SDKCommunicatie class. There needs to be an event fired in the MainForm class. But sadly that doesn't work.
But when I change the loginstate in the mainform(with a buttonclick)(see code below) the event is fired. But that is not the intention i would like to have.
private void button1_Click(object sender, EventArgs e)
{
events.LogInState = true;
}
If my question isn't clear enough, please let me know.
VMS class Added as reply to #Astef
class VMS {
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(typeof(MainForm));
GxUIProxyVB m_UIProxy = new GxUIProxyVB();
public string username2;
public string directory2;
public string Status;
public void initOmni()
{
m_UIProxy.CreateInstance();
m_UIProxy.OnLogon += new _IGxUIProxyVBEvents_OnLogonEventHandler(m_UIProxy_OnLogon);
m_UIProxy.OnLogoff += new _IGxUIProxyVBEvents_OnLogoffEventHandler(m_UIProxy_OnLogoff);
m_UIProxy.OnError += new _IGxUIProxyVBEvents_OnErrorEventHandler(m_UIProxy_OnError);
m_UIProxy.OnAlarmStatusEx2 += new _IGxUIProxyVBEvents_OnAlarmStatusEx2EventHandler(m_UIProxy_OnAlarmStatusEx2);
}
public void login(string username, string password, string directory)
{
username2 = username;
directory2 = directory;
initOmni();
m_UIProxy.LogOn(directory, username, password,false);
}
public void logOff()
{
m_UIProxy.LogOff();
}
void m_UIProxy_OnLogon()
{
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
sdkcommunicatie.onLogon(username2, directory2, "Genetec Omnicast");
}
I have fixed this with deleting the following:
SDKCommunicatie sdkcommunicatie = new SDKCommunicatie();
And adding the following in the base of VMS:
SDKCommunicatie sdkcommunicatie;
But now i got a new error in the mainform when i tried to call a class in SDKCommunicatie
connectedStatus = sdkcommunicatie.connectedStatus();
I got the following error:
NullReferenceException was unhandled
You are not using the same instance of the Events class, and that's why on button click you catch LoginStateChanged. You should inject the same instance of Events class to SDKCommunicatie class, then you'll be able to listen to event changes.
Edit:
Jeremy Todd and I were both writing at the same time.
Events in your SDKCommunicatie are not fired because you've created an individual instance of class Events for it. That is not the instance you have placed on the MainForm.
Inject the right instance (pass a reference) to SDKCommunicatie from MainForm through constructor, property or somehow else. For example:
MainForm:
SDKCommunicatie sdkcommunicatie;
Events events = new Events();
public MainForm()
{
InitializeComponent();
events.LoginStateChanged += new EventHandler(events_LoginStateChanged);
sdkcommunicatie = new SDKCommunicatie(events);
}
void events_LoginStateChanged(object sender, EventArgs e)
{
log.Info("EventFired loginstateChanged");
}
SDKCommunicatie:
Events events;
public SDKCommunicatie(Envents eventsInstance)
{
events = eventsInstance;
}
public void onLogon(string username, string directory, string system)
{
events.LogInState = false;
}
Your SDKCommunication class and your MainForm class each have their own separate instance of Events, so any events you trigger from one won't be visible from the other -- they're being raised on an entirely different object.
What you need is a single instance of the Events class that both SDKCommunication and MainForm can share -- that way they'll both be seeing the same thing. There are several different approaches you could take for this. Depending on what it needs to do, one very simple possibility might be to make Events a static class, and then the events would be visible everywhere without needing to create any instances.
I have solved the riddle.
When i need a method is a class i can call the method directly like this:
public class MainForm : Form
{
SDKCommunication sdkcommunication = new SDKCommunication();
public MainForm()
{
}
private void Button1_Click(oject sender, EventArgs e)
{
sdkcommunication.method("Test")
}
}
This is pretty straightforward. Look here the receiverclass:
public class SDKCommunication
{
method(string word)
{
//do something with word
}
}
The biggest problem is calling the class with the form(the original class). I have solved this with a eventhandler.
class CustomEventHandler1 : EventArgs
{
public CustomEventHandler1(string u, string d)
{
msgu = u;
msgd = d;
}
private string msgu;
private string msgd;
public string Username
{
get { return msgu; }
}
public string Directory
{
get { return msgd; }
}
}
Then the SDKCOmmunication class should look like this:
class SDKCommunication
{
public event EventHandler<CustomEventHandler1> RaiseCustomEventHandler1;
protected virtual void OnRaiseCustomEventHandler1(CustomEventHandler1 e)
{
EventHandler<CustomEventHandler1> handler = RaiseCustomEventHandler1;
if (handler != null)
{
handler(this,e);
}
}
//Custom Method that is called somewhere
internal void custommethod()
{
OnRaiseCustomEventHandler1(new CustomEventHandler1("johnsmith", "localhost");
}
}
Then in the mainform class:
public class MainForm : Form
{
public MainForm()
{
sdkcommunication.RaiseCustomEventHandler1 += new EventHandler<CustomEventHandler1>(sdkcommunication_RaiseCustomEventHandler1);
}
void sdkcommunication_RaiseCustomEventHandler1(object sender, CustomEventHandler1 e)
{
//Do something.
}
}
The information sended with the event you can get with e.Username and e.Directory. In this example they are strings where e.Username = johnsmith and e.Directory = localhost.
I hope somebody can use this information for their own code.

using events to centralize information

Here's an explanation of what I'm trying to achieve:
I have a textbox that I'm using as a 'debug', or 'information' window on my form. What I would like to do is have any classes that I create throw an event when it has information to post to the debug window, and then have the text window subscribe to said event, and post each time something new comes in. I'm trying to make it so that my classes don't need knowledge of the textbox but still have the capability to pass all of the information to the text box.
Is it possible to have a 'shared' event among classes (perhaps using an interface) so that I only need to subscribe to that one event and it will pull from all classes that throw the event?
For a visual, it would basically look like this:
Public delegate void DebugInfo(string content)
Class foo1
{
event DebugInfo DebugContentPending
public void bar()
{
DebugContentPending("send this info to the debug window")
}
}
Class foo2
{
event DebugInfo DebugContentPending
public void bar()
{
DebugContentPending("send this info to the debug window")
}
}
Class SomeClass
{
public void SomeMethod()
{
DebugContentPending += new DebugInfo(HandleContent); //gets events from foo1 and foo2
}
public void HandleContent(string content)
{
//handle messages
}
}
is this possible or am I off my rocker?
Most likely you don't need events.
class DebugLogger
{
public DebugLogger(TextBox textBox)
{
this.TextBox = textBox;
}
public TextBox TextBox { get; private set; }
public static DebugLogger Instance { get; set; }
public void Write(string text)
{
this.TextBox.Text += text;
}
}
Initialization:
DebugLogger.Instance = new DebugLogger(textBox1);
Usage:
DebugLogger.Instance.Write("foo");
Notice that code is not thread safe. See Automating the InvokeRequired code pattern and related for more information.

Categories

Resources