If you haven’t tried using the event model in .NET you don’t know what you’re missing. If this is the case, then I’m glad you’re here. Events are a very nice way to add flexibility to your projects and eliminate cross cutting concerns. You can use them for a variety of things including validation and logging. You can think of an event as sort of an All Points Bulletin (APB) throughout your application. Once you declare and throw an event, every place in your code that has an event handler for that event will be executed. Events can be both static or per instance. You use events every time you build an ASP.NET website. The Page_Load event, Button_Click event, etc… It is like an application wide notification that something is happening.
An important note is that all event handlers that have been moved to the call stack will be fired. So when you call out to your custom event, all objects that are in the call stack with an event handler for that event will be fired. Another thing to keep in mind is that there is no guaranteed order in which the events will be fired. If you are in need of doing something that requires a specific order, you should use more events or take another approach entirely.
In this project, we will create some events and handle them in a logging system. The first thing we will need to do is set up an event delegate to strongly type our event. Along with doing that, I like to setup some custom event arguments that will take in the object(s) that I will be dealing with during the event.
using System; using System.Collections.Generic; //Delegate for a PersonEvent publicdelegatevoidPersonEvent(PersonEventArgs e); publicclassPersonEventArgs : EventArgs { publicPersonEventArgs() { } publicPersonEventArgs(Person person) { this.Person = person; } publicPersonEventArgs(List<Person> personList) { this.PersonList = personList; } //Person the action will be on public Person Person { get; privateset; } //List of person the action will be on public List<Person> PersonList { get; privateset; } //For canceling action publicbool Cancel { get; set; } }
Ok, Now all we have to do is declare and throw our events. When declaring our events, they will be of the type PersonEvent.
using System.Collections.Generic; using System.ComponentModel; [DataObject(true)] publicclassPersonBLL { //Declare events publicstaticevent PersonEvent Pre_Get; publicstaticevent PersonEvent Post_Get; publicstaticevent PersonEvent Pre_Insert; publicstaticevent PersonEvent Post_Insert; publicstaticevent PersonEvent Pre_Update; publicstaticevent PersonEvent Post_Update; publicstaticevent PersonEvent Pre_Delete; publicstaticevent PersonEvent Post_Delete; [DataObjectMethod(DataObjectMethodType.Select)] public List<PersonPresentationShell> GetPeople() { //Call out to event handler if (Pre_Get != null) { PersonEventArgs args = new PersonEventArgs(); Pre_Get(args); if (args.Cancel) returnnull; } List<PersonPresentationShell> result = new List<PersonPresentationShell>(); List<Person> personList = DataAccessFactory.GetPeople(); foreach (Person item in personList) { result.Add(new PersonPresentationShell(item)); } //Call out to event handler if (Post_Get != null) { PersonEventArgs args = new PersonEventArgs(personList); Post_Get(args); if (args.Cancel) returnnull; } return result; } [DataObjectMethod(DataObjectMethodType.Update)] publicvoidUpdatePerson(PersonPresentationShell p) { //Call out to event handler if (Pre_Update != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Pre_Update(args); if (args.Cancel) return; } DataAccessFactory.UpdatePerson(p.Person); //Call out to event handler if (Post_Update != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Post_Update(args); } } [DataObjectMethod(DataObjectMethodType.Delete)] publicvoidDeletePerson(PersonPresentationShell p) { //Call out to event handler if (Pre_Delete != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Pre_Delete(args); if (args.Cancel) return; } DataAccessFactory.DeletePerson(p.Person); //Call out to event handler if (Post_Delete != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Post_Delete(args); } } [DataObjectMethod(DataObjectMethodType.Insert)] publicvoidInsertPerson(PersonPresentationShell p) { //Call out to event handler if (Pre_Insert != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Pre_Insert(args); if (args.Cancel) return; } DataAccessFactory.InsertPerson(p.Person); //Call out to event handler if (Post_Insert != null) { PersonEventArgs args = new PersonEventArgs(p.Person); Post_Insert(args); } } }
There we have it! An event will now be thrown before and after every get, insert, update and delete. Now we have to set up some event handlers in our logging object.
using System; using System.IO; using System.Web; publicclassLogger { //Set the log file location privatestaticstring _logFileLocation = HttpContext.Current.Server.MapPath("~/App_Data/logfile.log"); staticLogger() { //Attach event handlers PersonBLL.Pre_Delete += new PersonEvent(PersonBLL_Pre_Delete); PersonBLL.Post_Delete += new PersonEvent(PersonBLL_Post_Delete); PersonBLL.Pre_Get += new PersonEvent(PersonBLL_Pre_Get); PersonBLL.Post_Get += new PersonEvent(PersonBLL_Post_Get); PersonBLL.Pre_Insert += new PersonEvent(PersonBLL_Pre_Insert); PersonBLL.Post_Insert += new PersonEvent(PersonBLL_Post_Insert); PersonBLL.Pre_Update += new PersonEvent(PersonBLL_Pre_Update); PersonBLL.Post_Update += new PersonEvent(PersonBLL_Post_Update); } staticvoidPersonBLL_Post_Update(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + " " + e.Person.LastName + " was updated”); } static void PersonBLL_Pre_Update(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + "" + e.Person.LastName + "is about to be updated”); } staticvoidPersonBLL_Post_Insert(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + " " + e.Person.LastName + " was inserted”); } static void PersonBLL_Pre_Insert(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + "" + e.Person.LastName + "is about to be inserted”); } staticvoidPersonBLL_Post_Get(PersonEventArgs e) { WriteToLogFile("The people were gotten”); } static void PersonBLL_Pre_Get(PersonEventArgs e) { WriteToLogFile("The people are about to be gotten”); } staticvoidPersonBLL_Post_Delete(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + " " + e.Person.LastName + " was deleted”); } static void PersonBLL_Pre_Delete(PersonEventArgs e) { WriteToLogFile("PersonId: " + e.Person.PersonId.ToString() + " - " + e.Person.FirstName + "" + e.Person.LastName + "is about to be deleted”); } publicstaticvoidWriteToLogFile(string message) { DateTime now = DateTime.Now; using(StreamWriter sw = File.AppendText(_logFileLocation)) { sw.WriteLine(now.ToString() + " - " + message); } } }
Finally, we have to create an instance of our logger class in the Global.asax file to attach our event handlers to our events when the application starts.
1 2 3 4 5 6
voidApplication_Start(object sender, EventArgs e) { //Create an instance of the logger //To attach event handlers Logger logger = new Logger(); }
There we have it. Now on every CRUD operation in our application, a log entry will be written with some data about that action. Once you get the hang of it events become extremely useful. One big instance I like to use it for is authorization of performing an action in a membership and roles scenario.