A little while back I came across a great post on how to use JQuery to do more efficient client side paging by Dave Ward. The sample shows you how to use JQuery to do Ajax callbacks for client side paging using a grid template. After downloading the demo and parsing through it all, I found a lot of things I really liked and even came across a little gotchya with the way ASP.NET serializes dates in JSON.
One part I really enjoyed about this sample is that your objects on the server are translated into client side objects. So Order.OrderID or Order.ShippingAddress.ShipName would work the same on the client and server side of the programming. The jtemplates add-in allows you to name your active object of the collection you are looping through a lot like .NET like so:
As you can see the order object is used in the jtemplates code just like in .NET code.
You may have noticed the DateDeserialize() function followed by the extension method .format() in the snipped above. This is due to some date deserialization issues I ran into. The signature for the DateDeserialize method is as so:
This method is basically returning the evaluation of the date returned by the .NET framework (ex: /Date(894427200000)/), replacing the / with a space with the keyword "new" in front of it. This will return us a JavaScript Date object. Then I'm using the .format() extension method from the included MSAjax framework. It took me a little while to figure out, but once I did I fell in love. You can't put a price on full on object-oriented programming!
Special thanks to Dave Ward for opening my eyes to the power of JQuery!
In a recent situation I was trying to pull some aggregates out of a DataTable using LINQ. I needed to get the rows of the DataTable with a Distinct clause, but my aggregates would be on other columns of the row. The problem is that when you call LINQ’s Distinct() extension method with no arguments, it uses the "default IEqualityComparer". This means that it will work if you use the Select() extension method, only returning the column you want the distinct on. Well that works great, unless you need more columns from the DataTable.
The solution here is simple. Write a custom DataRow comparer that compares the DataRow against the column you are trying to put the distinct on. Here is an example:
Once we inherit IEqualityComparer<T> (T being the type we want to do the comparison on) all we do is fill in the Equals() and the GetHashCode() methods. In the Equals() method, we just tell the DataRows to compare the fields "PersonID" and return if they are equal. This will tell LINQ if the DataRow is distinct or not.
A short time ago I was confronted with a serious problem. What I needed to do was dynamically choose a UserControl as well as fire methods from that UserControl. The problem lies in the fact that a UserControl does not implement my custom methods that I needed for my controls. Each control was similar and would have the same methods but it would have different display characteristics.
That was when I had a small epiphany. Why can’t I just make an abstract base class? Well the answer is you can! Sometimes I am prone to forget how .NET allows me to customize pre-defined classes. What we can do is create an abstract base class that inherits the UserControl class, then have our UserControls inherit from our base class.
using System; using System.Data; using System.Configuration; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq;
///<summary> /// Base class to be inherited by a UserControl that displays the date ///</summary> publicabstractclassDateTimeDisplayControl : UserControl { ///<summary> /// Updates the date time inside the user control. ///</summary> publicabstractvoidUpdateDateTime(); }
So in the snippet above, we have created a class called DateTimeDisplayControl. This inherits from UserControl and will have to override the abstract method UpdateDateTime().
Now we can create a couple of UserControls that inherit from our DisplayDateTimeControl class. The first control will be called "ControlOne".
Here is the *.ascx code:
1 2 3 4 5 6 7
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="ControlOne.ascx.cs" Inherits="UserControls_ControlOne" %> <p>User control one</p> <asp:UpdatePanelID="udp1"runat="server"UpdateMode="Conditional"> <ContentTemplate> <asp:LabelID="lblDateTime"runat="server" /> </ContentTemplate> </asp:UpdatePanel>
using System; using System.Collections; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq;
As you can see, ControlOne contains an UpdatePanel with a Label inside of it. The Label will display the date and time. We will call our second control "ControlTwo" and it will look exactly like ControlOne, only it will say "User control two" inside of it.
Now we will create the actual *.aspx page to display the controls.
using System; using System.Configuration; using System.Data; using System.Linq; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.HtmlControls; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Xml.Linq;
privatestring ControlVirtualPath { get { if (string.IsNullOrEmpty(_controlVirtualPath)) _controlVirtualPath = ViewState["ControlVirtualPath"].ToString(); ViewState["ControlVirtualPath"] = _controlVirtualPath; if (string.IsNullOrEmpty(_controlVirtualPath)) thrownew ApplicationException("The control virtual path was not found"); return _controlVirtualPath; } }
private DateTimeDisplayControl LoadedAjaxControl { get { if (_DateTimeDisplayControl == null) { _DateTimeDisplayControl = (DateTimeDisplayControl)Page.LoadControl(ControlVirtualPath); } return _DateTimeDisplayControl; } }
As you may see, the *.aspx page will load up ControlOne by default. There are 3 buttons on the page that will allow you to swap out ControlOne and ControlTwo as well as call the UpdateDateTime() method of the controls.
That is all there is to it! One important note is that I am using a private property to get the loaded control, this is important to note because you will need to call that UpdateDateTime() method on the instance of the control that you rendered to the page. I don’t know why I didn’t think of this long ago, but I hope you will find it as useful as I did!
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.
Ok, if you’re anything like me you absolutely gag when you see the rendered content of the ASP.NET head tag. It is all rendered out inline for some reason. I’m not 100% sure about the affects of it on web marketing, but I know one thing is for sure… It certainly doesn’t help your rankings any. At the very least it looks gross and it can be easily fixed with some portable c# files that you can include in any project. I found a reference here about it, so I picked it up and ran with it.
A couple of good things to note is the placement of some key pieces for control adapters in the .NET framework. The ControlAdapter class should be inherited for every control adapter you create, it can be found in the System.Web.UI.Adapters namespace. All of the tags we will be overriding belong to the System.Web.UI.HtmlControls namespace.
The first tag we will override is the head tag itself.