Sunday, November 22, 2009
Back to Basics: Looping
Pretty soon after learning conditional statements comes looping. Looping can be used to scan through a recordset, or to add items to a drop down or any number of things really. Looping is vital to almost any program. Today we will learn how to use for loops and while loops in both C# and VB.
For-Loop
In both C# and VB the for loop can come in two flavors. The more traditional what I will call the counting for loop, and a for each loop which will allow you to loop through a collection or enumeration of things.
First we will start off with the counting for loop. There are three main parts to this for loop. First is the counter and it's initialization. You can either define this outside of the loop and just reference it in the loop, or you can define it inline with the loop. This is the the method I prefer since the scope of the variable is localized to the for loop. Traditionally the counter variables are 'i', 'j', or 'k'. There is nothing wrong with using other variable names, but you will see these 3 used all the time. More often than not you will see 'i' being the most prevalent.
The second part is the ending criteria such as an upper or lower bound, it is essentially how many times the loop will execute. This is a very important piece because if you don't have it then you will enter into an infinite loop in which there is no way your program will exit until you run out of memory or hit the upper bound of the data type you are using (both are bad things). Since this is tested at the beginning of each iteration this is called a pre-test loop.
Lastly we define how are are going to increment our counter. Many times this is just up by one each time or down by one. But you can use any increment you wish. The increment happens after the end of the loop.followed by the check of the counter. If the ending criteria is not met the loop will execute again.
In this example we are just going to loop 10 times writing out to the screen the value of i each time
C#
//Example 1
for (int i = 0; i < 10; i++) {
Response.Write("i=" + i.ToString() + "<br/>");
}
//Example 2
int i;
for (i = 0; i < 10; i+=2) {
Response.Write("i=" + i.ToString() + "<br/>");
}
You can see how I defined the variable 'i' inside the for loop in the first example. In the second I declared the variable outside of the loop. Both are valid, and it is just personal preference. Just remember that the scope on each variable is different.
In the second example above we are incrementing by 2 each time through the loop. The += notation is the same thing as writing out the full expressoin i = i+2. It just makes the whole thing easier to read.
In VB.Net if you are going to increment by 1 each time around you do not need to define the last piece of the loop, it is built in. So in example 1 below we are just going to count up by one. In example 2 we will increment by 2 as before.
VB
//Example
For i As Integer = 0 To 10
Response.Write("i=" & i & "<br/>")
Next
//Example 2
For i As Integer = 0 To 10 Step 2
Response.Write("i=" & i & "<br/>")
Next
So as you can see in Example 2 using the step clause in VB will allow you to change what you increment (or step) by.
The next type of For loop is the for each, which is very useful in stepping though a collection of objects. For example, lets assume we have a collection, addressBook, of people using the class (person) we have been using in the past 2 posts. The examples are just going to loop through all of the items in the collection. Note how we do not have to declare a counter. .Net will handle fetching each item and knowing when to stop. This loop can be re-written into a counting for loop very easily. I would be willing to say that each foreach loop could be re-written as a counting for loop, but the reverse isn't true. I'm not positive on that, but I can't think of any examples to prove me wrong, if you can think of one put it in the comments below.
C#
foreach (person peep in addressBook) {
Response.Write(peep.LastName);
}VB
For Each peep As person In addressBook
Response.Write(peep.LastName)
Next
As you can see the syntax is almost identical between the two languages.
While Loops
While have the same purpose as a for loop, and they can be swapped in almost any case, but sometimes it just makes more sense to use a while loop instead of a for loop.
For example, lets say we have a loop that we really have no way of knowing how many times the loop would need to run. A great example of this is while reading a file from disk. We want to keep looping until we hit the end of file (EOF) character. I am sure you could probably find out the length of the file, divide the bytes and use a for loop, but it just feels better to use a while loop. After programming for a while you will get a good feel of when to use a while loop and when to use a for.
The first example, is just re-writing the counting loop from above just to show you how it is done. The second example is reading from an OracleDataReader. I am not going to show the opening of the data reader and all that, but I am just going to loop through it for you and am going to fill our addressBook from before. I am going to use some newer notation (.Net 3.5) to make the code a bit shorter for the initialization of the person object.
C#
//Example 1
int i;
while (i < 10) {
Response.Write("i=" + i.ToString());
i++;
}
//Example 2
while (reader.HasRows) {
person peep = new person { FirstName = reader["FirstName"], LastName = reader["LastName"], Age = reader["Age"] };
addressBook.Add(peep);
}
So those are your basic loops. There is one more type of loop that can be used the do-while. But haven't used that in many years and is only used in a few cases. The difference being the compiler will check the condition at the end of the loop instead of at the beginning, so your loop will always execute at least once, this is called a post test loop.
And a special thanks to
Brent for guest editing this post
Labels: .NET, Back to Basics
posted by Tom Becker at
|

Monday, November 9, 2009
Back to Basics: Conditional Statements
This is the second in my Back to Basics series, and this time we are going way back. Conditional statements are some of the very first things you learn in any introductory programing class. In this post I will show you the C# and VB syntax for if, if/else, and switch statements.
If-statement
We will start off with the simplest of conditional statements, the if-statement. This is just simple boolean logic that will evaluate true or false. If the result is true, it will execute the block, if false it will skip it. In this example we will check to see if a person is over the age of 21. We will be using the same person class as in my last
postC#
if (myPerson.Age >= 21)
canDrink = true; //Whatever logic you want
Notice that in C# you can omit the curly braces ({}) if the logic under the if statement is one line long. If it is longer than one line you must use the braces. If you omit those, then the line directly beneath the if statement will be the only one evaluated on a conditional basis the rest of the statements will always be executed.
However in the VB.Net syntax you must have a closing End If, even if the statement is a single line.
VB
If myPerson.Age >= 21 Then
canDrink = true
End If
If/Else
The next example is of an if/else statement. The same rules apply as before, we are just extending it a bit. You can chain together as many if/else statements as you wish, just by adding more conditions. However all of the conditions must before the else, with the else being the final statement (if needed, don't have to have an else).
Once the compiler finds a match for your statement it will not execute any more of the statements in your if/else block. This lets the compiler be more efficient.
C#
if (myPerson.Age < 18)
canDrink = canVote = false;
else if (18 <= myPerson.Age < 21) {
canVote = true;
canDrink = false;
}
else {
canDrink = canVote = true;
}
Note in this example that I mixed my curly braces. First condition I didn't need them since I had one line. Second one I did since I have more than one line. And the third I didn't need them but put them anyway.
VB
If myPerson.Age < 18 Then
canVote = canDrink = False
ElseIf 18 <= myPerson.Age < 21 Then
canVote = True
canDrink = False
Else
canVote = canDrink = True
End If
Switch Statement
The switch statement is a little more complicated than the if and if/else statements but it can be very useful and make your code look cleaner in a lot of places. They can be very useful when evaluating enumerations. In the example below lets assume that our person class has an enumeration of hair colors called (strangely) HairColors. So lets use an switch statement to evaluate our public property hair, and do some logic based on hair color. If the hair color is not in our list the default case will be evaluated. I realize that since we are using an enum we would never evaluate the default case, but just bear with me.
C#
switch (myPerson.hair) {
case HairColors.brown:
//You are a brunette
break;
case HairColors.blonde:
// you are blonde, duh
break;
case HairColors.red:
//You are a redhead
break;
case HairColors.black:
//You have black hair
break;
default:
//You have colorful hair
break;
}You must use the break statement to end each specific case. This will exit you out of the enclosing block, in this case the switch. The break statement can be used in any control flow statement, and it will have the same effect. In the switch statement though it is required, and the compiler will throw an error if you omit this step.
VB
Select Case myPerson.hair
Case HairColors.brown
'You are a brunette
Case HairColors.blonde
' you are blonde, duh
Case HairColors.red
'You are a redhead
Case HairColors.black
'You have black hair
Case Else
'You have colorful hair
End Select
In VB, the switch statement is known as a Select Case, and as you can see by the syntax it is very similar to C# other than the naming. In this case however, you do not need to include the break statement, the flow will stop when it hits the next case keyword.
As a bonus I will give you one more statement called the ternary operator. This works very well in C# because of
short-circuiting, but in VB you have to be careful because VB won't short circuit.
You can use the ternary operator to evaluate something and assign a value on one line. You can easily re-write it to be an if/else statement. Lets re-write our first statement using a ternary operator. The first part is your condition. So in this case we are checking to make sure person is over 21. After the question mark is the true part of the statement and the last is the false.
C#
canDrink = myPerson.Age >= 21 ? true : false;
VB
canDrink = IIf(myPerson.Age >= 21, True, False)
The syntax is very similar, however this isn't a true ternary operator since we are calling a function (iif), but it functions almost exactly the same. The difference being that in VB the second part of the statement (the false section) will still be evaluated. In this case it wouldn't matter if it is evaluated since nothing can go wrong.
Check here for some other reading on the subject of VB and iif.
Conclusion
So there are your basic control flow and conditional statements. I hope this was useful, and good luck.
Labels: .NET, Back to Basics
posted by Tom Becker at
|

Thursday, November 5, 2009
Back to Basics: Parameterizing Inline SQL
Things have been a bit slow with any interesting project work and I don't want this blog to fall
even more stagnant . So I am going to be writing a new series called "Back to Basics" containing best practices and some basic code references aimed at newer coders.
There are some situations in which you cannot use stored procedures in order to handle all of your data access. Some cases it is just because of the architecture where you are at, other times it is because you are building the SQL at run time (this still can be done in both P/L or T-SQL but in this case we are going to write it inline).
But no matter what the circumstance, it is still good practice to parameterize your statements. This can help with style as well as helping to protect against
SQL Injection (Wikipedia).
We will take a normal inline SQL statement and convert it to a parameterized statement. We will start with this.
public void Save() {
string sql = "INSERT INTO People (First_Name, Last_Name, Age) VALUES (\"" + this.FirstName + "\", \"" + this.LastName +
"\", \"" + this.Age + "\");";
using (OracleConnection conn = new OracleConnection("connstring"))
using (OracleCommand comm = new OracleCommand(conn, sql)) {
comm.CommandType = CommandType.Text;
comm.ExecuteNonQuery();
}
}This will work as is, and technically is correct. However, the readability goes out the window. With all the escape characters and everything in that statement it becomes hard to read very quickly. This is also a very small insert statement. Imagine a larger table with 15-20 rows. The statment would become huge and debugging would become hard if you mistyped something, so along with the readability, scaleability is bad as well.
So lets take that statement and parameterize it. This adds to the number of lines of code, but in this case it is well worth it. We take out all of the items in the VALUES clause and replace them with identifiers, much like you would if you were writing a full stored procedure. Then you can add the parameters to the command object. With this you can specify data types and sizes to even further restrict the data entered to help make sure no bad data gets through. This also allows you to significantly shorten your SQL statement, and allows you to add another value much easier than in the previous example.
public void Save() {
string sql = "INSERT INTO People (First_Name, Last_Name, Age) VALUES (:FirstName, :LastName, :Age);";
using (OracleConnection conn = new OracleConnection("connstring"))
using (OracleCommand comm = new OracleCommand(conn, sql)) {
comm.CommandType = CommandType.Text;
comm.Parameters.Add(":FirstName", OracleType.VarChar, 50).Value = this.FirstName;
comm.Parameters.Add(":LastName", OracleType.VarChar, 50).Value = this.LastName;
comm.Parameters.Add(":Age", OracleType.Int32).Value = this.Age;
comm.ExecuteNonQuery();
}
}This will work for both Oracle and MS SQL, you would just have to change from and Oracle connection and command to a SQL one. Also I think the preferred syntax when using MS SQL would be to use the @ symbol rather than the colon.
Labels: .NET, Back to Basics, SQL
posted by Tom Becker at
|

Monday, September 21, 2009
Custom Attributes in C#
An attribute in C# is a way for you to add meta-data around an element in your code. You can attach an attribute to many different targets, see
here for full list.
Attributes are useful in supplying extra information about the target at all stages of developement, from design to run time. They help you specify specific information about the target, such as the method type, such as designating a
WebMethod. Or to inform the compiler that a method is now obsolete, so that the compiler can warn you that you are using an outdated method. I think the most recognizable one that I think most people would have used an not even thought about it as an attribute is the
Serializable.You can also create your own custom attributes in C#, and basically all it takes is a small lightweight class that inherits from System.Attribute and has a constructor and some public properties. These properties can be then read at runtime through reflection.
In this example, we are going to create an attribute to denote a field that we can expect in an import from a user. So first we create the attribute. We are going to require that we have 3 pieces of meta-data in our attribute, a display name, whether or not the field is required in the upload, and a description of the field (used for display purposes). So let's create the class
using System;
using System.Collections.Generic;
using System.Text;
[System.AttributeUsage(System.AttributeTargets.Property, AllowMultiple=false)]
public class ImportDescriptor : System.Attribute{
/// <summary>
/// Custom Property Attribute
/// </summary>
/// <param name="displayName">The string to be displayed in the Import UI (e.g. grid column) for this property.
/// <param name="required">If true, a value for this property is required for import. If false, the property value is optional.
public ImportDescriptor(string displayName, string description, bool required) {
DisplayName = displayName;
Required = required;
Desc = description;
}
public string DisplayName{
get { return (_displayName); }
set { _displayName = value; }
} private string _displayName = null;
public bool Required{
get { return (_required); }
set { _required = value; }
} private bool _required = false;
public string Desc{
get { return (_desc); }
set { _desc = value; }
} private string _desc = null;
}
As you can see we inherited from System.Attribute, and we are using an attribute called
System.AttributeUsage (msdn), that tells us how this attribute is going to be used.
Now we need to add that attribute to the properties on our class that we expect to see in an import. Assume we have a class Person that has properties of PersonID, FirstName, LastName, and Title. And lets assume that everything except title is required. So lets add the attributes to the Person class.
public class Person {
private int _personID;
private string _first_name;
private string _last_name;
private string _title;
public Person() {
//empty constructor
}
[ImportDescriptor("Person ID", "ID of the person", true)]
public int PersonID {
get { return _personID; }
set { _personID = value; }
}
[ImportDescriptor("First Name", "First Name of the pesron.", true)]
public string FirstName {
get { return _first_name; }
set { _first_name = value; }
}
[ImportDescriptor("Last Name", "Last Name of the person", true)]
public string LastName {
get { return _last_name; }
set { _last_name = value; }
}
[ImportDescriptor("Title", "The persons title in the company (CEO, Developer, etc.)", false)]
public string Title {
get { return _title; }
set { _title = value; }
}
}
We now have our class set up to use our attribute. We can add more fields to our Person class and add the ImportDescriptor attribute and our code will automatically expect to see the field in the import. So our framework is set up. We now just need to consume this. Below is an example of how to use reflection to read the attribute, and handle the line in the import accordingly. It is a brief example and will leave the rest of the import code as an exercise for you. In this example I am using reflection to read the attributes and store them in a class (ImportProperties) that we are using for the actual import. The variable _dataType is of type Object. I wanted this to be as generic as possible so that I could use this for any type of import, not just for the Person Class.
private List GetAttributes(Object dataType) {
PropertyInfo[] props = dataType.GetType().GetProperties();
PropertyInfo prop;
List<importproperties> lst = new List<importproperties>();
for (int i = 0; i < props.GetLength(0); i++) {
prop = props[i];
if (prop.GetCustomAttributes(typeof(ImportDescriptor), false).Length > 0) {
ImportDescriptor importDesc = (ImportDescriptor)prop.GetCustomAttributes(typeof(ImportDescriptor), false).GetValue(0);
ImportProperties import = new ImportProperties();
import.DisplayName = importDesc .DisplayName;
import.Desc= importDesc.Desc;
import.Required = importDesc .Required;
lst.Add(import);
}
}
return lst;
}
Since you can have multiple attributes per target we are only going to be looking for the ImportDescriptor, you can extend this to read all attributes.
Also, since this is using reflection and a list, you need to make sure you are using System.Reflection, and System.Collections.Generic in order to use PropretyInfo.
Labels: .NET
posted by Tom Becker at
|

Friday, August 7, 2009
Token startelement in state epilog would result in an invalid xml document.
I was creating an XML document and kept running into this same error over and over again. It seems that it is the default error for any sort of syntax problem with your XML documents. So I would venture to guess that there are lots of ways of fixing it, but what worked for me was pretty simple (as most syntax errors are). I didn't have a root element. So make sure you always have a root or else!
See below for my code for writing an XML Doc
string filepath = GetPath("myXML.xml"); //get full path
xmlTextWriter writer = new XmlTextWriter(filepath, null);
writer.WriteStartDocument();
writer.WriteStartElement("root"); //must have!!!!
foreach (Person p in myPeeps) {
writer.WriteStartElement("person");
writer.WriteStartElement("name");
writer.WriteString(p.Name);
writer.WriteEndElement();
writer.WriteStartElement("address");
writer.WriteString(p.address);
writer.WriteEndElement();
writer.WriteStartElement("title");
writer.WriteString(p.Title);
writer.WriteEndElement();
writer.WriteStartElement("age");
writer.WriteString(p.age);
writer.WriteEndElement();
writer.WriteEndElement();
}
writer.WriteEndElement();
writer.WriteEndDocument();
writer.Flush();
writer.Close();
Labels: .NET
posted by Tom Becker at
|

Friday, June 12, 2009
Extension Methods
So while running around playing with Linq, I just happened across
another article by ScottGu, that talks about extension methods. And I have decided that they are truly awesome.
Extension methods allow you to add methods to existing types. In ScottGu's article he adds a called IsValidEmailAddress method to the string type. I originally had great plans on using this in a project to add some extension methods to a base type so they would show up on all the children. And then I realized that I could do the same thing by just writing the function in the base class instead. Same result. So the real use for these things are when you cannot modify the type definition.
So below is the extension method that I originally was going to use. It has all the syntax you need and it worked. I just realized that it was overkill, however awesome it may be. Lookup and LookupElement are parent classes for all of the lookup objects in the project. Lookup is a list of lookupElements.
public static string GetTextFromValue(this Lookups.Lookup L, int ID){
string text = "";
foreach (Lookups.LookupElement le in L) {
if (le.Value == ID){
text = le.Text;
break;
}
}
return text;
}So after building this a new method would show up in IntelleSense when you used a Lookup object. And you would use it just like you would a normal method call.
Labels: .NET
posted by Tom Becker at
|

Linq, Lambda Expressions and Predicate Delegates
I have recently been giving the opportunity to play around a bit more with Linq and while playing around with that I have run into the related topics of Lambda Expressions and Predicates. This post will be broken up into 3 sections (can we guess what they are?) and will just briefly provide an over view for each.
Linq
Linq stands for language-integrated query, and it allows you to query your data sets in code instead of heading back to the database in order to get a subset, and without having to loop through code. The syntax is very similar to SQL.
For example lets say I had a list of people, and I wanted to pull back everyone who lived in Richmond. Previously I would have to go back to the database and reselect my list of people or maybe loop through the list and do it that way. But using Linq I can do this much easier.
List<People> myPeeps = new List<People>();
//Fill list
var results = from p in myPeeps
where p.Location= "Richmond"
orderby p.Name
select p;
As you can see this syntax is very similar syntax to SQL. You can now take the results and bind them a control, or do any sort of computations on it.
Lambda Expressions
Lambda Expressions are
defined by MSDN as "...an anonymous function that can contain expressions and statements, and can be used to create delegates or expression tree types."
So what exactly that means I'm not to sure, but it makes it real easy to filter things out inline and simplifies the above Linq query a bit. Using the same situation above the query changes to
myPeeps.Where(p => p.Location== "Richmond");
Pretty simple no? It doesn't have all the same power as Linq since you can really order or use multiple criteria and the like, but it is very simple and easy to use.
Predicates Delegates
Predicates are
defined as "...the method that defines a set of criteria and determines whether the specified object meets those criteria." What that means is that you can define a function that returns a boolean to evaluate if your item in a list meets certain criteria. Again using the above example, I define the actual predicate delegate.
private bool IsRichmonder(People p) {
return p.Text == "Richmond";
}
And once that is done, I just pass the predicate into the select clause on my list.
myPeeps.Select(IsRichmonder);
Summary
All of these examples have been pretty simple, but I hope you can see the power of all of these methods when properly leveraged.
I relied on ScottGu's
articles to learn about these and to write this post
Labels: .NET
posted by Tom Becker at
|

Tuesday, May 26, 2009
Writing to a file with C#
It had been a while since I had to write a file with .Net, I don't think I really had done it since vanilla ASP. As I remember it wasn't hard then and it really hasn't changed to much since then. See below for code on how to check to see if the directory exists, and then how to actually create and write to a file.
Check to see if path exists if not create it
if(!System.IO.Directory.Exists(path))
System.IO.Directory.CreateDirectory(path);
Create the file
public void WriteFile(string fileText, string fileName){
string fullPath = "<Where ever your path is>"
try{
FileInfo file = new FileInfo(fullPath);
StreamWriter stream = file.CreateText();
stream.WriteLine(fileText);
stream.Close();
}catch(Exception ex){
//handle exception
}
}
Labels: .NET
posted by Tom Becker at
|

Wednesday, January 14, 2009
Rendering an Image from a blob using an httpHandler
So I've written before on how to
upload a file to a blob in Oracle, but I haven't written about how to retrieve it. In this post I am specifically talking about images in this post but you can change out the MIME type and it would work the same.
I am going to show you how to use an IHTTPHandler in order to show your image. I used
this for reference.
So add to your project a new generic handler. It will pre-populate a few methods, and basically you just add to them. See my code below
Public Class ImageHandler
Implements System.Web.IHttpHandler
Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
If context.Request.QueryString("id") IsNot Nothing Then
Dim id As Integer = CInt(context.Request.QueryString("id"))
Dim blob As Byte()
blob = getImage(id)
If blob IsNot Nothing Then
context.Response.Clear()
context.Response.ContentType = "image/pjpeg"
context.Response.BinaryWrite(blob)
context.Response.End()
End If
End If
End Sub
ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return True
End Get
End Property
Private Function getImage(ByVal ID As Integer) As Byte()
'Select blob from the db
End Function
End Class
So after you have added this to your project you are ready to use it. There are many ways to do this, but I used an .Net image control. Either in the code behind or at design time, I defined the URL in the code behind when I bound the rest of the stuff on my page, but basically all you to have to do is link to the HttpHandler, and give it a query string with the ID you want. Example below
Me.imgProductImage.ImageUrl = "~/imagehandler.ashx?id=" & D
Labels: .NET
posted by Tom Becker at
|

Tuesday, December 23, 2008
.Net Resource Files
Resource files in .Net will allow you to create customized values for either different languages or if you are using an the same app for multiple people on different servers, you can store things like titles, names, and other specific version info that you don't want to hard code.
You can store the resource file (resx) in either the App_GlobalResources or the App_LocalResources folder depending on the scope of the resource.
The values in the resource file are stored as XML as key/value pairs. Pretty easy stuff, and you can store pictures, text, icons, or audio...anything really in here.
To get things out of the resource file you can either bind it to a label (or any other bindable control)
<asp:label id="label1" text="'<%$resources:ClassName,Property">' runat="Server" />
Where ClassName is the name of the resource file without the .resx extension on it, and Property is the key.
Or if you wan to access the key value pair programmatically you can access a global resource by using this
HttpContext.GetGlobalResourceObject("ClassName", "Property")or you can access a local resource by using
HttpContext.GetLocalResourceObject("virpath", "Property")where you pass in the virtual path of the local resource object.
I used
these two articles as reference
Labels: .NET
posted by Tom Becker at
|

Tuesday, December 2, 2008
Theming with SkinID
A month or so ago I made a post about
theming in .Net, and towards the end of it I said that sometimes on a page you may need to override the theme and create your own style and the example I gave was of a button having a specific style different from the rest.
What I left out of that post (and I actually spent the morning updating my code to reflect this) were SkinIDs. Inside of a skin file you can have multiple definitions for a single control. One of these will be set as default and the rest will be given a SkinID to denote it at the page level. So in my example with the button
<asp:Button ID="btnClear" Text="Clear" EnableTheming="False" CssClass="Button Clearbtn btn100"
CausesValidation="False" runat="Server" />
Would change to
<asp:Button ID="btnClear" Text="Clear" SkinID="ClearButton" CausesValidation="False" runat="Server" />
And I would have in my Skin file the following line.
<asp:button cssClass="Button Clearbtn btn100" SkinID="ClearButton" runat="Server"/>
One of the nicest things about this is all of your skinIDs will show up on your aspx pages, so Intellesence picks up your IDs so you don't have to remember all of them. It also cleans up the code a bit and you don't have so much repetition.
Labels: .NET
posted by Tom Becker at
|

Tuesday, November 25, 2008
Exporting a Girdview to Excel
I needed a quick way to export either a Gridview to an Excel file. I wanted something quick that I could call on a button click. So I put the following function in a class and you can call it from anywhere. You can also specify the file name of the export if you wish. It defaults to export.xls if you don't. You can easily use this for file types of than excel by changing the MIME type, a full list can be found
here.
The PrepareControlForExport sub will just remove the control and replace it with a literal so it will show up nice in your export.
Public Shared Sub Generate(ByVal Grid As GridView, Optional ByVal filename As String = "export")
HttpContext.Current.Response.Clear()
HttpContext.Current.Response.Buffer = True
HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=" & filename & ".xls")
HttpContext.Current.Response.ContentType = "application/vnd.ms-excel"
HttpContext.Current.Response.Charset = ""
Dim oStringWriter As System.IO.StringWriter = New System.IO.StringWriter()
Dim oHtmlTextWriter As System.Web.UI.HtmlTextWriter = New System.Web.UI.HtmlTextWriter(oStringWriter)
' Create a form to contain the grid
Dim table As Table = New Table
table.GridLines = Grid.GridLines
' add the header row to the table
If Grid.ShowHeader Then
PrepareControlForExport(Grid.HeaderRow.Controls(0))
table.Rows.Add(Grid.HeaderRow)
End If
' add each of the data rows to the table
For Each row As GridViewRow In Grid.Rows
PrepareControlForExport(row)
table.Rows.Add(row)
Next
' render the table into the htmlwriter
table.RenderControl(oHtmlTextWriter)
HttpContext.Current.Response.Write(oStringWriter.ToString())
HttpContext.Current.Response.End()
End Sub
' Replace any of the contained controls with literals
Private Shared Sub PrepareControlForExport(ByVal control As Web.UI.Control)
Dim i As Integer = 0
Do While (i < control.Controls.Count)
Dim current As Web.UI.Control = control.Controls(i)
If (TypeOf current Is LinkButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New Web.UI.LiteralControl(CType(current, LinkButton).Text))
ElseIf (TypeOf current Is ImageButton) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New Web.UI.LiteralControl(CType(current, ImageButton).AlternateText))
ElseIf (TypeOf current Is HyperLink) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New Web.UI.LiteralControl(CType(current, HyperLink).Text))
ElseIf (TypeOf current Is DropDownList) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New Web.UI.LiteralControl(CType(current, DropDownList).SelectedItem.Text))
ElseIf (TypeOf current Is CheckBox) Then
control.Controls.Remove(current)
control.Controls.AddAt(i, New Web.UI.LiteralControl(CType(current, CheckBox).Checked))
End If
If current.HasControls Then
PrepareControlForExport(current)
End If
i = (i + 1)
Loop
End Sub
Just pass in your gridview and filename and you are good to go. It should prompt you whether or not you want to save the file or open it.
Labels: .NET
posted by Tom Becker at
|

Wednesday, November 19, 2008
Creating a custom pager using Delegates
I wanted to create a way to handle the paging event of a gridview or datagrid with a few special requirements, I wanted to be able to
- change the page size,
- have previous, next, first and last buttons, and
- jump to a specific page.
The inbuilt paging option in the gridview does not allow you to do all of this. And instead of writing this for each grid that I wanted to use it in I created a user control, that does everything for you.
I will save you the details of the most of the code, but will point out the interesting bits, you can download a working example at the end of the post.
First the delegates. The user control has two delegates defined one to change the page (PageChangedEventHandler) and one to handle the page size changing (ItemsPerPageChangedEventHandler). Notice that in the definition of the delegates I have a custom eventArg class that has a few extra properties that I am going use.
Public Delegate Sub PageChangedEventHandler(ByVal sender As Object, ByVal e As DataNavigatorEventArgs)
Public Delegate Sub ItemsPerPageChangedEventHandler(ByVal sender As Object, ByVal e As DataNavigatorEventArgs)
Both Delegates have an event associated with them:
Public Event PageChanged As PageChangedEventHandler
Public Event CountChanged As ItemsPerPageChangedEventHandler
The user control has 3 properties that we will need to use on the page where you are using the user control. And of course all the button clicks where the magic happens. When the user clicks a button, changes page size, or jumps to a page, we raise the corresponding event, below is the example from clicking the 'first' button.
Private Sub btnFirst_Click(ByVal sender As Object, ByVal e As System.Web.UI.ImageClickEventArgs) Handles btnFirst.Click
Dim myE As New DataNavigatorEventArgs
_Current_Page = 0
myE.CurrentPage = _Current_Page
myE.TotalPages = _Page_count
ViewState("CurrentPage") = _Current_Page
ViewState("PageCount") = _Page_count
RaiseEvent PageChanged(sender, myE)
End Sub
The rest of the button clicks look pretty much the same just the logic of setting the current page is different.
So that is pretty much it for the user control.
In order to use it, you can just drag it on your page and in the code behind make sure you catch both events, example below.
Public Sub Paging(ByVal sender As Object, ByVal e As DataNavigatorEventArgs) Handles myPager.PageChanged
Me.grdTest.PageIndex = e.CurrentPage
'rebind grid
End Sub
Public Sub CountChanged(ByVal sender As Object, ByVal e As DataNavigatorEventArgs) Handles myPager.CountChanged
Me.grdTest.PageSize = e.ItemsPerPage
Me.grdTest.PageIndex = e.CurrentPage
'rebind grid
End Sub
Since this bit of code is essentially the same you can just copy paste between the pages and change variables names as needed.
Only one other bit of code on the aspx page and you are set. And this goes where you are binding the grid. You must tell the pager control who many items there are and what the current page is.
Me.grdTest.DataSource = dt
Me.grdTest.DataBind()
Dim itemCount As Integer = dt.Rows.Count
Me.myPager.ItemCount = itemCount
Me.myPager.Currentpage = Me.grdTest.PageIndex
And you are all set.
Download the
codeLabels: .NET
posted by Tom Becker at
|

Tuesday, October 21, 2008
Theming In .Net 2.0
Having a consistent look and feel for any web site is essential. It not only looks better when things are uniform, but it helps with user experience. If things look the same over the entire site they will learn and see patterns and provide for a better user experience over all. The move to using styles and CSS classes were a big step in the right direction by providing one place to update a style definition and it would bubble through the entire site. But what about specifics for a control in .Net? What if you want all of your gridviews to have paging set up a certain way? That is where skinning and theming come in. Applying a theme to a page will force all the controls on the page to display in a uniform way, and setting up a theme is very easy.
You can start by right clicking in the solution explorer in Visual Studio and adding a new ASP.Net folder called Theme and it will ask you the name for your theme. After that you will see two new folders in your project. One called 'App_Theme' that is built in by Microsoft. And a subfolder with the actual name of the theme you just provided. And in this folder is where you can add your skin. So right click on that folder and add a new item, and choose a skin file as the type. Once this opens you'll see that it has some comments at the top explaining how to use the skin file.
In here you can add any control that you can add on a control page. But why Microsoft decided not to have Intellesence on this file is beyond me. So after you have added all the controls that you want skinned, you can add the theme to your web.config file, or if you have multiple themes for a site you can define the theme in the page directive of each page.
I have included an example below of how my gridview generally looks in the skin file. As you can see you have a lot more options than you would if you were just using a CSS style.
<asp:GridView runat="server" BorderWidth="0" BorderStyle="None" CellSpacing="0" CellPadding="4" AutoGenerateColumns="False"
AllowSorting="True">
<headerstyle cssclass="HeaderStyle">
<rowstyle cssclass="RowStyle">
<alternatingrowstyle cssclass="AlternatingRowStyle">
<selectedrowstyle cssclass="SelectedItemStyle">
<editrowstyle cssclass="EditRowStyle">
<footerstyle cssclass="FooterStyle">
<pagerstyle cssclass="PagerStyle">
</asp:GridView>
With every rule however there are times when you are going to want to break the skin. You can do this on the page level by blanking out theme in the page directive, or you can do this at the control level. Below is an example of a button that I have a different style for than the rest of the buttons on the page. Notice the EnableTheming="False" is what actually does it. Remember that after this you will have no styles on this button, so remember you must set everything that you may have set in the theme.
<asp:Button ID="btnClear" Text="Clear" EnableTheming="False" CssClass="Button Clearbtn btn100" CausesValidation="False"
runat="Server" />
Labels: .NET
posted by Tom Becker at
|

Thursday, September 11, 2008
Multiple Exit Statements, The Great Debate
A coworker asked me about a function he was working on that lent itself to multiple exit points, and I tried to push him in the direction of having a single exit point at the end of the function, and using a local var to hold the return value.
I suggested that by doing so he increased style and readability. And after I told him that I kinda thought that my response lacked any sort of real substance. It was kinda just saying, 'because I said so'. But who am I to say what style is? So I thought back to my programming classes and how we always did it that way, without any real reasons why. I guess you could say I was what this
article called a 'structured programming purist.' Sure I may have slipped a few return statements into one function here and there, but it always felt that I was cheating.
So I went looking for a article that could explain why exactly one return statement should rule them all (very proud of myself for working in a LOTR reference). I came across a plethora of articles that all pretty much said the same thing.
There was a time when multiple returns were not good because of memory management. Since you had a single exit point you knew were all of your objects were getting cleaned up and you would miss anything as
explained here. But in the newer programming languages with managed memory this isn't an issue. Especially not with try/finally blocks and using statements. The same article had another link to an interesting experiment dealing with
monkeys.
It basically says that monkeys will do things because that is that is the way that it has always been done, even if they have no idea why things are being done. So I'm through being a monkey, Multiple exit statements are OK in my book; just don't tell my old professors.
PS. Best article I've written...LOTR and monkeys? awesome
Labels: .NET
posted by Tom Becker at
|

Tuesday, September 9, 2008
Viewstate thoughts
ASP.Net has had the ViewState around since it came around and it is a nice way of keeping around persistant variables across postbacks. It stores any object you may put in there as well as any control you have on that specific page. It is pretty useful, except when people misuse it or it just gets to darn big.
One of the biggest concerns about using viewstate would be storing secure data in it. If you view source on a page anyone can see the data. Yes it is "encrypted" in base-64 char array, but it is pretty easy to decrypt this and view it.
The reason I bring this up is there was an blog post from one of the Microsoft developers about how to identify pages with high viewstates. I was reading through it and she has a link to Fritz Onion's ViewState Decoder. So I downloaded it and was taking a peak around in my viewstate, and I never realized how easy it was to find things in there. See below for part of my decrypted viewstate. But as you can see the variable "ReportSelectedIndex" is something I have stored in viewstate and it was able to be exposed very easily. Now in this case it isn't sensative or anything, but it could have been.

So just a word to the wise and be careful of what you put in your viewstate, or at the very least encrypt what you put in there.
Labels: .NET
posted by Tom Becker at
|

Wednesday, August 20, 2008
Extending the .Net Validators
Been a while since I've had a .Net post. Haven't been doing to much development right now. Mostly maintenance work so haven't really be doing anything worthy of a post.
But my co-workers and I have been working on a set of tools that we all use that we should standardize. No sense in all of us writing the same code. One of the biggest differences is how we all handle our input validation. I have been using all the built in
RequiredFieldValidators (msdn),
CompareValidators (msdn), and the occasional
RegularExpressionValidator (mdsn) and others have been spinning their own solutions. So we all go together and hashed out what we all wanted out of our validation, and I ended up writing a custom validator that blended the options.
At first I was going to just try to extend the CompareValidator to add the data types that I/we wanted but that really isn't an option since you can't tap into the ValidationDataType that the control uses. So I ended up starting from scratch essentially and just extended the
BaseValidator (msdn) and just wrote my own validate function. See below for code.
Option Strict On
Option Explicit On
Imports System
Imports System.Web.UI
Imports System.Web.UI.WebControls
Namespace CustomControls
Public Class myValidator
Inherits BaseValidator
Public Enum FormatTypes
PhoneNumber
SSN
Email
DateTime
StrictAlpha
Alpha
Numeric
AlphaNumeric
ZipCode
URL
End Enum
Private _type As FormatTypes
'''
''' What kind of format do you want the data in
'''
Public Property DataType() As FormatTypes
Get
Return _type
End Get
Set(ByVal value As FormatTypes)
_type = value
End Set
End Property
Dim _isRequired As Boolean = False
Public Property Required() As Boolean
Get
Return _isRequired
End Get
Set(ByVal value As Boolean)
_isRequired = value
End Set
End Property
Protected Overrides Function EvaluateIsValid() As Boolean
Dim expression As String = ""
Dim stringToValidate As String = Me.GetControlValidationValue(Me.ControlToValidate)
Dim isValid As Boolean = False
If _isRequired And Trim(stringToValidate) = "" Then
isValid = False
ElseIf Not _isRequired And Trim(stringToValidate) = "" Then
isValid = True
Else
Select Case _type
Case FormatTypes.Email : expression = "^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}"
Case FormatTypes.PhoneNumber : expression = "((\(\d{3}\) ?)|(\d{3}[- \.]))?\d{3}[- \.]\d{4}(\s(x\d+)?){0,1}$"
Case FormatTypes.SSN : expression = "\d{3}-\d{2}-\d{4}"
Case FormatTypes.Alpha : expression = "^[a-zA-Z ,-.:/_?!']*$"
Case FormatTypes.AlphaNumeric : expression = "^[a-zA-Z0-9 ,-.:/_()?!]+$"
Case FormatTypes.DateTime : expression = "^(?=\d)(?:(?:31(?!.(?:0?[2469]|11))|(?:30|29)(?!.0?2)|29(?=.0?2.(?:(?:(?:1[6-9]|
[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00)))(?:\x20|$))
|(?:2[0-8]|1\d|0?[1-9]))([-./])(?:1[012]|0?[1-9])\1(?:1[6-9]|[2-9]\d)?\d\d(?:(?=\x20\d)\x20|
$))?(((0?[1-9]|1[012])(:[0-5]\d){0,2}(\x20[AP]M))|([01]\d|2[0-3])(:[0-5]\d){1,2})?$"
Case FormatTypes.Numeric : expression = "^[0-9]*$"
Case FormatTypes.StrictAlpha : expression = "^[a-zA-Z]*$"
Case FormatTypes.URL : expression = "^(http\:\/\/[a-zA-Z0-9_\-]+(?:\.[a-zA-Z0-9_\-]+)*\.[a-zA-Z]{2,4}(?:\/[a-zA-Z0-9_]+)
*(?:\/[a-zA-Z0-9_]+\.[a-zA-Z]{2,4}(?:\?[a-zA-Z0-9_]+\=[a-zA-Z0-9_]+)?)?(?:\&[a-zA-Z0-9_]+\=[a-zA-Z0-9_]+)*)$"
Case FormatTypes.ZipCode : expression = "(\d{5}-\d{4})|(\d{5})$"
End Select
If Regex.IsMatch(stringToValidate, expression) Then
isValid = True
Else
isValid = False
End If
End If
Return isValid
End Function
End Class
End Namespace
So that is the class. There are some pretty hefty regular expressions in there. But don't let them scare you. You set them and forget them. I had to break the lines a bit to get them to look nice on the screen.
So to get it on the page you are going to need to register the namespace. Example below:
<%@ Register TagPrefix="vld" Namespace="CustomControls">
Once you've got it registered (you can put it in the web.config file as well if you don't want to declare it on every page) you can actually use the control. You can use it just like you would with the RequiredFieldValidator. See example below:
<vld:myValidator ID="cusEmail" DataType="Email" required="false" ControlToValidate="txtEmail" ErrorMessage="Enter valid email address" Display="dynamic" runat="Server">*</vld:myValidator>
And thats pretty much it. The DataType property will list all of the values you have defined in the code file. To add more data types you can add it to the formatType enum and just add the regEx to the case statement in the validate function and you are good to go.
Labels: .NET
posted by Tom Becker at
|

Wednesday, July 16, 2008
Transactions in VB.Net and Oracle
This is going to be kinda a two part post. Each talking about an approach to the same problem. But first some background.
I am creating a questionnaire that is being saved to the database in a mutli-step process. 4 steps to be exact. If any one of those steps fail I want to be able to roll back to the beginning so I don't have a stub of a questionnaire floating around. I need that process to be
atomic.
I originally wrote it so that the 4 steps were independent of each other so that it could be as flexible as possible. And then the problem of the stubs came up. So I had to make it atomic. So since I already had four functions and 4 stored procedures in Oracle I created a transaction in .Net and just added it to my command objects (Part 1 of this article), but that didn't work for me. So then I went to combining all 4 procedures into one and using Oracle transactions (Part 2).
Part 1: .Net Transactions
.Net transactions aren't actually that hard, In my case I was using the
OracleTransaction class but there is a SQLTransaction class that works the same way for those of you using MS-SQL. Essentially you tie your transaction to your connection and your command object. You must use the same connection for each command object, but that is pretty much your only limitation. The most common implementation that I've seen is just passing the connection and the transaction to all the functions that needed it and that is what I did as well. Code examples below:
Private Sub Save()
Dim conn As New OracleConnection("ConnString")
Dim trans As OracleTransaction
conn.Open()
Try
trans = conn.BeginTransaction
saveThingOne(conn, trans)
saveThingTwo(conn, trans)
trans.Commit()
Catch ex As Exception
trans.Rollback()
End Try
End Sub
Private Sub saveThingOne(ByVal conn As OracleConnection, ByVal trans As OracleTransaction)
Using comm As New OracleCommand("Save_Thing_One_Stored_Procedure", conn, trans)
comm.CommandType = CommandType.StoredProcedure
comm.Parameters.Add("IN_ID", OracleType.Number).Value = intID
comm.Parameters.Add("IN_THING_ONE", OracleType.VarChar, 60).Value = strThingONe
comm.ExecuteNonQuery()
End Using
End Sub
Private Sub saveThingTwo(ByVal conn As OracleConnection, ByVal trans As OracleTransaction)
Using comm As New OracleCommand("Save_Thing_Two_Stored_Procedure", conn, trans)
comm.CommandType = CommandType.StoredProcedure
comm.Parameters.Add("IN_ID", OracleType.Number).Value = intID
comm.Parameters.Add("IN_THING_TWO", OracleType.VarChar, 60).Value = strThingTwo
comm.ExecuteNonQuery()
End Using
End Sub
However, in my current environment we use stored procedures for all of our database interactions. And that being the case it makes using the .Net transactions impossible to use. Now I don't know if the above code would work in a MS-SQL environment, but in an Oracle environment it does not. The best reason I can figure it is because Oracle treats a stored procedure as a transaction in and of it self. So when you get to the end of the stored procedure it does a full commit automatically...hence nothing to rollback. So I had to combine all 4 procedures into one massive one and use Oracle transaction statements to make sure everything is done at once.
Part 2: Oracle Transactions
There are a lot of articles out there about Oracle transactions, but I found that most of them had all the information that I needed separated out across multiple pages. So here it is all together.
As I mentioned above an Oracle stored procedure does a commit on successful completion of the procedure. But you can also explicitly tell it to do the commit any time you want to during its execution by calling the "commit;" command. You can also rollback at any point if you want to just by calling the "rollback;" command. If you put the two together you have the beginning of a nice way to ensure an atomic transaction.
The only other new part of the stored procedure you must add is a an exception clause. This as you may guess works much like a try/catch clause in VB. You can either catch specific Oracle errors by calling them by name, or you can do a catch all and just handle all of them the same way, which is what I did below. The only thing I would warn you about though, is that if you are having trouble with your procedure and are still testing I wouldn't put the exception clause in there quite yet. Oracle will catch and handle the error and end cleanly. You will not know that your code is bombing. It took me a while to figure out why it was performing a rollback and exiting clean.
So here is the code for a transaction in Oracle:
PROCEDURE SAVE_TWO_THINGS(
IN_THING_ONE IN VARCHAR2,
IN_THING_TWO IN VARCHAR2
)
IS
BEGIN
INSERT INTO TABLEONE
(ACTIVE, THING_DESC)
VALUES
('Y', IN_THING_ONE);
INSERT INTO TABLETWO
(ACTIVE, THING_DESC)
VALUES
('N', IN_THING_TWO);
COMMIT;
EXCEPTION WHEN OTHERS THEN ROLLBACK;
END;
Note that the 'OTHERS' keyword in my exception clause is where you would catch a specific oracle error, you can string together as many of those as you want to, but I would recommend using the 'OTHERS' as a kind of catch all at the end if you want to make sure you catch everything.
Summary: Unless you are using inline SQL to connect to your Oracle database then you're really not going to be able to use .Net transactions. So you are going to have to use the Oracle transaction. Many would argue that I should have done that from the beginning since Oracle is such a powerhouse that doing processing there isn't a big deal so any atomic transaction should be tried to be done in Oracle anyway, but I really think it is up to the programmer. It really is personal preferences.
Labels: .NET, Oracle, SQL
posted by Tom Becker at
|

Wednesday, July 9, 2008
Using statement versus Try/Catch
So I had a code review this morning and learned of a better way to handle some of my error handling and garbage collecting.
I was using a try/catch/finally block to handle catching errors when calling a database function and then doing all my disposes and clean up in the finally. Now if I was doing something with the error rather than just re-throwing it up to the next layer that would have been fine. But since I wasn't really handling the error at this point there was no reason for me to have all the over head of a try catch block. And as for my disposes there were more elegant solutions to make sure I dispose of all my objects. Enter the Using statement.
This was the first I heard of it. I have spent the afternoon changing most of my data layer code over to it. It allows you to explicitly define a variable that will automatically dispose of itself once it gets to the end of the using block. So it has a very narrow scope. And as for the errors, since those were bubbling up and being caught at the next level there was no need for me to catch them here.
So my code went from this using try/catch/finally:
Dim oConn As New OracleConnection
Dim oComm As OracleCommand
oConn.ConnectionString = "connString"
Try
oConn.Open()
oComm = New OracleCommand("procedurename", oConn)
oComm.CommandType = CommandType.StoredProcedure
oComm.Parameters.AddWithValue("PARAM", param)
oComm.ExecuteNonQuery()
Catch ex As Exception
Throw ex
Finally
oConn.Close()
oConn = Nothing
oComm = Nothing
End Try
To this using the 'Using statement':
using oConn as new OracleConnection("connString")
using oComm as New OracleCommand("procedurename", oConn)
oConn.Open()
oComm.CommandType = CommandType.StoredProcedure
oComm.Parameters.AddWithValue("PARAM", param)
oComm.ExecuteNonQuery()
end using
end using
I think it makes it look a lot cleaner and it removed about 10-15 lines of code per function.
Labels: .NET
posted by Tom Becker at
|

Monday, July 7, 2008
Cheat Sheets
I was just going through some old files and found a couple of cheat sheets that I made for the interns at my last job. And I just thought that I'd share them with you all.
The first one is just some basic
.Net 2.0 information (Word). Function calls, loops, conditionals and the like.
The other one is base
SQL and T-SQL (Word). Selects, updates, loops, and conditional. It is pretty basic although it does have some 'GROUP BY' and 'HAVING' clauses in there.
I don't know how much use they would be except for beginners, but it could be nice to put on your cube wall for easy reference.
Labels: .NET, SQL
posted by Tom Becker at
|

Monday, June 16, 2008
Taking a .Net app offline
There are times when you need to take an application off line for a period of time for maintenance or you just don't want people on the site for back up or something. I dunno.
With .Net 2.0 there is a really easy way to do it, and there are no configuration settings you have to mess with in IIS or anywhere. You just have to drop a file named
app_offline.htm into the root of your site and blammo your app will show whatever text is in that file. There is one little pitfall though. The file size has to be at least 512 bytes or sometimes the .Net compiler won't recognize the file. So you can just put some junk in there in HTML contents, or you can write a really nice long message to your users
And when you want to bring the app back up, just remove or rename the file. Pretty neat little trick...
Labels: .NET
posted by Tom Becker at
|

Friday, June 13, 2008
.Net Mailbag
So I got an email from a co-worker who normally does ColdFusion work and is working his way into .Net, and he posed the following question that I thought would be a good post here.
Question:
If I'm not going to do anything dynamic with my label, is there a reason to use <asp:label> instead of just plain <label> in my ASPX code?
My Reponse:
Pretty sure you're gonna have to use the ASP label. When your page compiles it will change the name of the control you are referencing.
For example, if you have a text box that is just sitting out by itself called txtSomething. Once the page complies the textbox name will change to something along the lines of cp100_txtSomething.
Since this happens the traditional HTML label control will lose it's association. With the ASP label it will update the reference.
If you are not doing anything dynamic with that label however and want to save a little bit of memory, you can change the EnableViewstate property on the control to false and it won't bother storing it in the viewstate.
Labels: .NET
posted by Tom Becker at
|

Friday, May 23, 2008
Encrypting strings in .Net
Using query strings to pass values between pages is a very common practice in .Net, and many times you don't want users to be able to change the query string value to see another record. This can pose some problems especially if the data is in any way sensitive. So the one of the easiest ways to do this is to just encrypt the values and decrypt them when you need it.
There are many articles out there to do this and I guess I am just kinda adding to an article found
here. But I think add my own two cents and version of the code found on his site. I cleaned it up a little bit for my preferences and moved one or two things around.
First instead of having the functions pass in the symmetric key each time the function is called. I added a value in my web.config file that holds the key. This eliminates any sort of keying error and makes it easy to change if you want to for some reason.
<add key="EncryptionKey" value="!#$a8?2^" />The only real other change other than moving stuff outside the try/catch block that didn't need to be in there was to add this line:
stringToDecrypt = stringToDecrypt.Replace(" ", "+")The above article mentions that since we are adding the encrypted value to the query string browsers interpret a + as a space. So we have to replace it back the way it was before decrypting the string. The article relies on the caller function to handle that. I moved it inside my decrypt function so I don't have to remember to do it each time.
Here is my updated class. One thing to note is that I made them shared functions so I don't have to instantiate the class in order to use it.
Imports System
Imports System.IO
Imports System.Xml
Imports System.Text
Imports System.Configuration
Imports System.Security.Cryptography
Public NotInheritable Class Encryption
Public Shared Function Decrypt(ByVal stringToDecrypt As String) As String
Dim inputByteArray(stringToDecrypt.Length) As Byte
Dim key() As Byte = {}
Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
Dim encryptionKey As String = ConfigurationManager.AppSettings("EncryptionKey")
Dim des As New DESCryptoServiceProvider()
Dim ms As New MemoryStream()
Dim cs As CryptoStream
Try
stringToDecrypt = stringToDecrypt.Replace(" ", "+")
key = System.Text.Encoding.UTF8.GetBytes(Left(encryptionKey, 8))
inputByteArray = Convert.FromBase64String(stringToDecrypt)
cs = New CryptoStream(ms, des.CreateDecryptor(key, IV), CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
Dim encoding As System.Text.Encoding = System.Text.Encoding.UTF8
Return encoding.GetString(ms.ToArray())
Catch ex As Exception
Throw New Exception(ex.Message)
End Try
End Function
Public Shared Function Encrypt(ByVal stringToEncrypt As String) As String
Dim key() As Byte = {}
Dim IV() As Byte = {&H12, &H34, &H56, &H78, &H90, &HAB, &HCD, &HEF}
Dim encryptionKey As String = ConfigurationManager.AppSettings("EncryptionKey")
Dim des As New DESCryptoServiceProvider()
Dim ms As New MemoryStream()
Dim inputByteArray() As Byte
Dim cs As CryptoStream
Try
key = System.Text.Encoding.UTF8.GetBytes(Left(encryptionKey, 8))
inputByteArray = Encoding.UTF8.GetBytes(stringToEncrypt)
cs = New CryptoStream(ms, des.CreateEncryptor(key, IV), CryptoStreamMode.Write)
cs.Write(inputByteArray, 0, inputByteArray.Length)
cs.FlushFinalBlock()
Return Convert.ToBase64String(ms.ToArray())
Catch e As Exception
Return e.Message
End Try
End Function
End Class
Labels: .NET
posted by Tom Becker at
|

Monday, April 14, 2008
Health Monitoring in .NET 2.0
The app I have been working on has started to experience some weird issues on our new production server. The users are getting prompted for log in credentials while they are working. Normally that only happens when they are idle for 20 minutes. But the users have assured me this will happen within 5 minutes of them logging in. I checked all of the normal stuff, like making sure the default time out wasn't anything ridiculously small, or the worker process wasn't set to recycle every 3 minutes or something. Those were all normal.
So I started looking around the internet and I wasn't the only one having this strange problem with IIS6 on a windows 2003 server. It seems that for some reason my app was randomly restarting. But in order to confirm this I had to add some health monitoring for my app. Which is actually some pretty cool stuff.
The code itself is pretty simple (see below) and what it will do is let you know when any application event is happening (stopping, starting, halted that kinda thing). And it will add all of this neatly into the windows event viewer. All you need to do is add the code below to the
<healthmonitoring><rules> section of the global web.config file.
<add name="Application Lifetime Events Default" eventname="Application Lifetime Events" provider="EventLogProvider" profile="Default" mininstances="1" maxlimit="Infinite" mininterval="00:01:00" custom="" />
The above code is only using default .Net stuff. I was hoping for a few more events that I could add that would give me a better picture of what was happening, but it seems that there are only a few in-built ones that you can use. The rest you have to build yourself. I haven't looked into doing, but you can find how to
here.So I just need to let that run for a few days and see if my session time outs line up with my app restarts.
Labels: .NET
posted by Tom Becker at
|

Thursday, February 21, 2008
Event Validation Error
So I just spent the last hour or so here trying to figure out the following error:
Invalid postback or callback argument. Event validation is enabled using in configuration or <%@ Page EnableEventValidation="true" %> in a page. For security purposes, this feature verifies that arguments to postback or callback events originate from the server control that originally rendered them. If the data is valid and expected, use the ClientScriptManager.RegisterForEventValidation method in order to register the postback or callback data for validationSo if you've seen this error you no doubt have flat spots on your head from banging your head against the cube wall
The popular message out in the vast expanse of the internet is to just set the EnableEventValidation="false" either in the page directive or in the web.config file. Let me first state that, yes that will work. But more importantly let me tell you what a bad idea this is. This nice little feature protects you from you from
Cross site scripting (XSS) as well as many other nasty little things/people that are waiting to take down your site. So just get that idea out of your head unless you feel like writing your own validation code to make sure nothing gets in that you don't want to. Go ahead, I'll wait...
Ok, so now that you forgot about the cheap work around. Here are the two main things to look for (from my experience/research) . One, nested form tags. ASP.Net isn't a fan. Remember if you are using master pages, the child page does not need a form tag, that is in the master page. Second, and this is what i finally figured out was my problem. The postback was coming from an imagebutton inside of a gridview control. I was binding the gridview on each postback. So what was happening was, I was losing the select event when I re-bound the grid. So I stuck the function that was binding my grid inside a conditional !Page.IsPostBack.
So before you go and open up your site for some serious vulnerabilities, check to make sure your coding logic is sound and it isn't something small you've over looked.
Labels: .NET
posted by Tom Becker at
|

Monday, February 11, 2008
Moving items up or down in a listbox
So I really didn't think this was that complicated to do. Changing the order of items that are displayed in a standard list box. Nothing all that fancy. It being a Monday, I decided to try and not think and just to grab some code from somewhere on the internet.
I was surprised by the wide variety of different ways to do this and all of them seemed overly complicated. One involving a nested for loop or another messing with the data source and saying that it only worked when the box was bound. Craziness.
All of this seemed way to complicated. So I broke down and thought about it for a second, and came up with (I think) the easiest way to move an item up or down in a list box control in .Net.
'down button press
Private Sub btnDown_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnDown.Click
Dim index As Integer = Me.lbxSortOrder.SelectedIndex
Dim itemCount As Integer = Me.lbxSortOrder.Items.Count
Dim li As ListItem = Me.lbxSortOrder.Items(index)
Dim newIndex As Integer
If index = itemCount - 1 Then
newIndex = index
Else
newIndex = index + 1
End If
Me.lbxSortOrder.ClearSelection()
Me.lbxSortOrder.Items.Remove(li)
Me.lbxSortOrder.Items.Insert(newIndex, li)
li.Selected = True
End Sub
The up button press is the same exact thing except the text on the index needs to look like this:
If index = 0 Then
newIndex = 0
Else
newIndex = index - 1
End If
And thats it. I know it was simple, I thought about not posting this cause of its simplicity, but by looking what else was out there, I'll add my two cents.
Labels: .NET
posted by Tom Becker at
|

Monday, January 28, 2008
FormsAuthentication vs WindowsAuthentication
Well it seems that I have wasted an entire day last work working on authentication and a log out for the application that I'm working on. I say wasted cause it won't work with my project but it was pretty interesting to work with. Here's the run down.
The users want to be able to log out of the web application that I'm building for them. Not an unreasonable request. But there are standards in place that say I must use this homegrown application called AppSec to handle all of our security needs. Keeps everyones security in one place, pretty nice right? But there is a caveat to using AppSec. We must use WindowsAuthentication in order to talk to the AppSec web service.
I thought that we could get around this by using FormsAuthentication and logging into a windows domain that way. But how AppSec requires that IIS have anon. turned off in order to work. So back to square one.
But here is the code to log someone in and out of a windows domain using FormsAuthentication, in the .Net 2.0 framework.
Private Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As String, _
ByVal lpszDomain As String, _
ByVal lpszPassword As String, _
ByVal dwLogonType As Integer, _
ByVal dwLogonProvider As Integer, _
ByRef phToken As IntPtr) As Boolean
' Declare the logon types as constants
Const LOGON32_LOGON_INTERACTIVE As Long = 2
Const LOGON32_LOGON_NETWORK As Long = 3
' Declare the logon providers as constants
Const LOGON32_PROVIDER_DEFAULT As Long = 0
Const LOGON32_PROVIDER_WINNT50 As Long = 3
Const LOGON32_PROVIDER_WINNT40 As Long = 2
Const LOGON32_PROVIDER_WINNT35 As Long = 1
That is the function that you will have to call in order to log in. Here is the function call:
isvalid = ValidateLogin(username, password, domain)
If isvalid Then
FormsAuthentication.RedirectFromLoginPage(username, True)
Else
'display error message
End If
Now you have to change your web.config file to use forms authentication instead of Windows
<authentication mode="Forms">
<forms loginurl="~/login.aspx" name="TestLogin" timeout="20" path="/" protection="All" />
</authentication >
After that you should be able to log in to your windows domain.
And to log out is just as easy:
FormsAuthentication.SignOut()
I got most of this code from
this AspAlliance article, but at the time of posting the text of the article doesn't seem to be loading.
Labels: .NET
posted by Tom Becker at
|

Tuesday, January 8, 2008
Uploading a file into an Oracle Blob
I was actually pleasantly surprised how easy it was to upload a blob into an Oracle database from a .NET app. I had been putting off this part of the app off for quite some time, and I am just about done with the rest of it so I thought it was about time. And I'll share the code here with you:
I just used a standard ASP.Net file upload control in the front end (not included here), and the code behind was just as simple
'file upload control
fileName = Me.fupAttach.FileName
'friendly name for the file
friendlyName = Me.txtFriendlyName.Text
'quick description
FileDesc = Me.txtFileDesc.Text
'Since a blob is just a byte array, the file upload control has a nice built in
'option to convert the file into a byte[]
Dim btAry As Byte() = Me.fupAttach.FileBytes
'The rest is just basic Oracle
Dim conn As New OracleConnection
Dim comm As OracleCommand
conn.ConnectionString = .Common.ProjectConnectionString
conn.Open()
comm = New OracleCommand("############", conn)
comm.CommandType = CommandType.StoredProcedure
comm.Parameters.Add("IN_FILE_NAME", OracleType.VarChar, 500).Value = fileName
comm.Parameters.Add("IN_FRIENDLY_NAME", OracleType.VarChar, 1).Value = friendlyName
comm.Parameters.Add("IN_FILE_DESC", OracleType.VarChar, 220).Value = FileDesc
comm.Parameters.Add("IN_FILE_BLOB", OracleType.Blob).Value = btAry
comm.ExecuteNonQuery()
And that is it. Like I said pretty easy. I was actually very surprised how little I found on the internet to do this. Most of the other examples I found were using a standard HTML upload filed, back from classic ASP days.
Hope this helps.
Labels: .NET, Oracle
posted by Tom Becker at
|
