Tag: ASP.NET

Creating Events in ASP.NET

Creating your own events on your own controls is something that is essential if you want you web app to work well and also provide you with reusable controls. It's easy to skip past the problem and find another way to get your code to do what you want it to do and detect the change another way. But you end up with much nicer code if your controls can have proper events for a piece of action, and you web page can have proper event handlers on each. Not only that but the code you need to write in generally a copy and past job and not that hard.

The Code

While it's not that hard, the amount of code that is needed is quite a lot more than you may expect. Fortunately though it's code you going to just re-use again and again changing small bits as needed.

1//1 - Event args (use default, but eventually pass in data through here)
2public class SaveCompleteEventArgs : EventArgs
3{
4 public SaveCompleteEventArgs(int inDataValue)
5 {
6 this.DataValue = inDataValue;
7 } //end of con
8
9 public readonly int DataValue;
10}
11
12//2 - define delegate
13public delegate void SaveCompleteEventHandler(object sender, SaveCompleteEventArgs e);
14
15//3 - define the event itself
16public event SaveCompleteEventHandler SaveComplete;
17
18//4 - the protected virtual method to notify registered objects of the request
19// virtual so that it can be overridden.
20protected virtual void OnSaveComplete(SaveCompleteEventArgs e)
21{
22 //if the UpdateData event is empty, then a delegate has not been added to it yet.
23 if (SaveComplete != null)
24 {
25 //event exists, call it:
26 SaveComplete(this, e);
27 } //end of if
28}
29
30//5 - method that translates the input into the desired event
31public void TriggeringMethod(int strData)
32{
33
34 // get new event args
35 //EventArgs e = new EventArgs();
36 SaveCompleteEventArgs e = new SaveCompleteEventArgs(strData);
37
38 // call the virtual method
39 OnSaveComplete(e);
40}

Custom Validator Error from Server Side

The built in ASP.NET validators are amazing as we all know. You just drag them on the page, tell them what control to validate, give them a summary control to list the errors and they do it. But what if there's something you need to add server side? Such as something that needs to check with the database before saving. You already have your validation summary control, so it would be nice to re-user that and have everything automatically looking the same. But it would appear there's no easy way of doing it built in, so here's an easy way of doing it... 

Creating a Custom Validation Error

First your going to need a class with some static class's that you can pass your error message to. Here I have two functions one for simply adding the error to the page and the other for adding the error to the page with a specific validation group. I am using a CustomValidator object to make this all work, another option is to implement IValidator but it's actually more effort than's needed. The other section to note is that I'm setting the Error.Text to a non breaking space (this is what would normally go next to the form field you're validating). This is because if you don't then it will default to the ErrorMessage which we only want to go into the summary. If you try setting it to a normal space it will still also default to the summary text.

1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Web;
5using System.Web.UI;
6using System.Web.UI.WebControls;
7
8/// <summary>
9/// Summary description for Validator
10/// </summary>
11public class ValidationError
12{
13
14 public static void Display(string Message)
15 {
16 Display(Message, "");
17 }
18
19public static void Display(string Message, string ValidationGroup)
20 {
21CustomValidator Error = new CustomValidator();
22 Error.IsValid = false;
23 Error.ErrorMessage = Message;
24 Error.ValidationGroup = ValidationGroup;
25 Error.Text = " ";
26
27Page currentPage = HttpContext.Current.Handler as Page;
28 currentPage.Validators.Add(Error);
29 }
30}

Now to trigger the error you just need to called the function as below:

1ValidationError.Display("Useful error message", "ValidationGroupName");

LINQ to SQL Inserts and Deletes

Inserting and Deleting records in a database using LINQ to SQL is just as easy as selecting information. What's not so easy is actually finding out how to do it. There are lots of excellent blog posts around such as this one by Scott Guthrie http://weblogs.asp.net/scottgu/archive/2007/07/11/linq-to-sql-part-4-updating-our-database.aspx, however most of them we're all written for the Beta version of LINQ to SQL which let you do a .Add() or .Remove() on your table, which was  changed on the final release. 

So to insert do something like this: 

1DataClassesDataContext dataContext = new DataClassesDataContext(); 
2
3//Create my new Movie record
4Movie movie = new Movie();
5movie.Name = "Tim's movie"; 
6
7//Insert the movie into the data context
8dataContext.Movies.InsertOnSubmit(movie); 
9
10//Submit the change to the database
11dataContext.SubmitChanges();

And to delete do something like this:

1DataClassesDataContext dataContext = new DataClassesDataContext();
2
3var movies = from m in dataContext.Movies
4 where m.Name == "Tim's movie"
5 select m;
6
7dataContext.Movies.DeleteAllOnSubmit(movies);
8
9dataContext.SubmitChanges();

LINQ to SQL Connection Strings

LINQ to SQL is great but like all great things at some point it does something that you don't expect and gives you a headache. An example of this happened to me this week with the differences between how connection strings are handled when you LINQ to SQL model is in a class library rather than a Website or Web Application.

What makes this issue particularly annoying is that it only appears when you try and change the database server that your code is looking at which could end up being when it's going live or moving to a staging server.

So we all know about connection strings, their quite simple and you just store them in your web.config file, which is how LINQ to SQL works when your using them in a Website. But as soon as you move them to a class library things change. First your connection string name is no longer that simple name you gave it e.g. ConnectionString, now it is prefixed with the namespace which is annoying but not the end of the world. Second discovery though is no matter what you do, it just doesn't seem to pick up the connection string from the web.config file. Reason being your original connection string has now compiled itself in the class library's dll and that is what it is using.

The Solution

Depending when you discovered this the solution is not to bad as you either have a lot of code to change or only a small amount. You can always pass a connection string to the constructor when you are creating an instance of the data context e.g.

1DataClasses1DataContext da = new DataClasses1DataContext(connectionstring);

You can also set the connection string on your LINQ to SQL model to be blank, this will remove the default constructor and force you to pass a connection string. This way you web application has the choice of what connection string to use and you can keep re-using your class library in different projects.

.NET Charts (Pleasing clients by giving them a graph to look at)

Irrespective of if your working on some kind of company extranet or the admin side of a public facing site, one thing that will make you're clients go ooooooo and love your work is the inclusion of a funky looking chart. It may not serve any amazing purpose, but as there looking through all the boring text area's and buttons that actually make up the functionality of the site, the inclusion of nice looking chart is going to make them go "oooo that's nice" and like you even more. For those of us working in .NET, thanks' to an update from Microsoft at the end of 2008 it's also something that've very quick an easy to do. Better yet the update was free so the only cost is the time you take to implement it. 

First off if you want to use the chart's and you haven't downloaded them then that's what you need to do. The chart's shipped after .NET 3.5 so there a separate install, .NET 4 however has them included by default. 

Using the Chart Control

Like I said adding a chart to a page is a quick and easy thing to do. Once you have the Visual Studio add on installed you can also drag and drop everything into place. However I'm going to go into a bit more detail. 

To start your going to need a data source. In this example I'm using a SQL Data Source object for ease of use, in a production environment I heavily recommend against using them as there going to make your code a completely unmanageable mess, instead I would use something like a Entity Data Source. My chart is going to be showing a graph of mobile phone handset popularity so my SQL is simply just returning a table of phone names and how many people use them. 

Code so far: 

1<asp:SqlDataSource ID="ChartDB" runat="server" ConnectionString="<%$ ConnectionStrings:ConnectionString %>" SelectCommand="SELECT [Name], [People] FROM [PhonePopularity]">
2</asp:SqlDataSource> 

Next we need to add a chart, the easiest way to do this is to just drag a chart object onto the page from the toolbox, however if you do want to type it yourself it's not particularly complex. 

First you will need to register the assembly on the page.. 

1 <%@ Register assembly="System.Web.DataVisualization, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" namespace="System.Web.UI.DataVisualization.Charting" tagprefix="asp" %> 

And then add the chart like so...

1<asp:Chart ID="Chart1" runat="server" DataSourceID="ChartDB" Height="400px" Width="400px">
2 </asp:Chart>

Now we're ready to start customizing what type of chart we're going to have and what data it should show from our data source.

To actually show a chart there's two bits of information you have to describe, area's and series'. The first area's is used to define an area for a chart to appear, one interesting thing about the chart control is you aren't limited to just one area. In fact in this example I'm going to have to chart's one showing a pie chart of phone popularity that will quickly show what kind of share each phone has, and then a second bar chart making it more clear the actual numbers people have of each phone. Area's also let you set properties on what the chart is actually going to look like as well. In this instance I'm going to set for both charts to be 3D.

The second bit of information is the Series. This is where you're actually specifying what data is going to be shown in which area and what kind of chart it is (e.g. Pie, Column, Donut etc). My completed code then looks like this...

1<asp:Chart ID="Chart1" runat="server" DataSourceID="ChartDB" Height="400px" Width="400px">
2
3<series>
4
5<asp:Series ChartArea="ChartArea1" ChartType="Pie" Name="Series1" XValueMember="Name" YValueMembers="People">
6</asp:Series>
7<asp:Series ChartArea="ChartArea2" Name="Series2" XValueMember="Name" YValueMembers="People">
8</asp:Series>
9
10</series>
11<chartareas>
12
13<asp:ChartArea AlignmentOrientation="Horizontal" Name="ChartArea1">
14
15<Area3DStyle Enable3D="True" />
16
17</asp:ChartArea>
18<asp:ChartArea Name="ChartArea2">
19
20<area3dstyle enable3d="True" />
21
22</asp:ChartArea>
23
24</chartareas>
25
26</asp:Chart>

Depending on your data this should give you something like this...

This is just a simple example of what you can do, but if you download the Chart Samples Project and have a look through there is no end to the possibilities with everything from different styles of charts to adding ajax functionality even with the ability to click of different parts of the carts to trigger events.

System.Lazy

Lazy loading isn't a new concept, it's a pattern that been around for a while to improve the performance of your apps by only loading objects when they are going to be used. For example if you have an object that contains a property of a list of customers then you only really need to populate it when you access the property not when the object was initially created, as it may never be used. At the same time though you don't want to be going off to the database every time access the property. So the simple solution is to have another private variable that stores if the customers property is populated or not and then check that in the property's get to determine if the data needs to be loaded or not.

Well now in .NET 4, lazy loading has been built into the framework with System.Lazy. Instead of the above all you need to do now is write something like this...

Lazy<Customers> _customers = new Lazy<Customers>();

What this will do is create you a customers object but only run the constructor when you actually access the objects Value property which will be of type Customers. e.g.

_customers.Value.CustomerData 

It's that simple, but can get even better. The constructor may not be the only thing you want to run when you access the property the first time. In this case you would write something like...

_customers = new Lazy<Customers>(() =>
        {
            // Write any other initialization stuff in here
            return new Customers();
        });

I must point out though while as great as this is, it does have some limitations so you probably won't want to use it in all scenarios.

For more information check out the Lazy initialization page on MSDN

Doloto

Doloto

Meant for Web 2.0 Apps that use a lot of JavaScript, Doloto will speed up the download time of all the JavaScript by basically removing anything that isn't initially needed and replacing it with stubs. It will then download in the background or wait until it is first called. The result, a seemingly much faster Web App for the user.

For more info have a look at the Doloto page on Microsoft's Research site or head over to the download page on MSDN.

Refreshing an UpdatePanel using JavaScript

Update panels provide a really easy way to add partial page refresh's to a web page in order to give a more user friendly experience that's more like a common desktop App. By default a button within that update panel will cause a post back and so long as no elements outside of the update panel are affected in the post back only it will refresh. However what do you do if you need to refresh a panel based on something outside of the update panel. One option is just to place a hidden button within the Update Panel and trigger that to post back, however this appears a little hacky. The solution is to use JavaScript and the _doPostBack method.

The following bit of code is all you really need:

1<script type="text/javascript">
2function refreshUpdatePannel(param) {
3var prm = Sys.WebForms.PageRequestManager.getInstance();
4prm._doPostBack('<%=UpdatePanel1.ClientID %>', param);
5prm.add_endRequest(refreshUpdatePanelComplete);
6}
7
8
9function refreshUpdatePanelComplete() {
10//add code here for when the update pannel is refreshed
11}
12</script>

All you need to add is something to call the function.

The second parameter is optional and provides a way of passing some information back to the server to let it know what has just happened on the page.

When the update panel has finished refreshing the refreshUpdatePanelComplete function will fire so more JavaScript can be added if needed e.g. To reset whatever just happened on the page that caused the initial postback.