Monday, 30 June 2008

The ternary prize

The ternary operator uses 2 symbols (? and :) to separate a conditional statement and 2 possible expressions. They can be used to represent a simple If...Else...End If statement on a single line:
condition ? expression1 : expression2

If the condition is true, expression 1 is evaluated. Alternatively, if the condition is false, expression 2 is evaluated.

Example:

Random random = new Random( DateTime.Now.Millisecond );

string response = random.Next( 1, 9 ) < 5 ? "the number is less than 5" : "the number is greater than or equal to 5";

Saturday, 28 June 2008

How do I calculate the maximum page index when paging in C#.NET?

using System;

public static class PagingUtility
{
/// <summary>
/// Calculates the maximum page index
/// </summary>
/// <param name="itemCount">Number of items to be paged</param>
/// <param name="pageSize">Number of items on each page</param>
/// <returns>Maximum page index (>=1)</returns>
public static int MaximumPageIndex( int itemCount, int pageSize )
{
int returnValue = 1;

if ( itemCount > 0 && itemCount > pageSize && pageSize > 0 )
{
returnValue = itemCount / pageSize;

int remainder = itemCount % pageSize;

if ( remainder > 0 )
{
returnValue++;
}
}

return returnValue;
}
}

Thursday, 19 June 2008

How do I remove the port number from a URL in C#.NET?

Regular Expression:
:{1}\d*

Using C#.NET, the above regular expression can be applied to a URL to strip the port number (along with ":"):

Regex regex = new Regex( @":{1}\d{1,}" );
string url = regex.Replace( "http://andrewgunn.blogspot.com:81/", string.Empty );

Festival essentials

I went to the Download 2008 last weekend and wanted to share my list of things to remember for those festival newbies (and so I don't forget anything next time):
  • Antiseptic hand wash (no water requried)
  • Baby wipes
  • Beer
  • Ear plugs
  • Eye mask
  • Headache tablets (extra strong)
  • Sleeping bag
  • Sunglasses
  • Sun cream
  • Tent
  • Ticket
  • Toilet paper
  • Towel
  • Water
If you think of anything else, let me know.

Monday, 9 June 2008

How do I submit web requests at runtime in C#.NET?

This utility class will make a web request programmatically and return the response as a string. I use it for calling ReST services that simply return custom XML which is then parsed using my serialization techniques mentioned in a previous post.

using System;
using System.IO;
using System.Net;
using System.Runtime.Serialization;
using System.Text;

public class WebRequestResult
{
private HttpStatusCode outcome;

public HttpStatusCode Outcome
{
get { return outcome; }
set { outcome = value; }
}

private string response;

public string Response
{
get { return response; }
set { response = value; }
}
}

public enum HTTPMethod
{
DELETE,
GET,
POST,
PUT
};

public static class WebRequestUtility
{
private const string DEFAULT_CONTENT_TYPE = "text/plain";
private const string XML_CONTENT_TYPE = "text/xml";

#region No authentication
public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, WebHeaderCollection headers )
{
return Submit( uri, null, null, httpMethod, DEFAULT_CONTENT_TYPE, headers, null );
}

public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, string data )
{
return Submit( uri, null, null, httpMethod, DEFAULT_CONTENT_TYPE, null, data );
}

public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, WebHeaderCollection headers, string data )
{
return Submit( uri, null, null, httpMethod, DEFAULT_CONTENT_TYPE, headers, data );
}

public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, string contentType, WebHeaderCollection headers )
{
return Submit( uri, null, null, httpMethod, contentType, headers, null );
}

public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, string contentType, string data )
{
return Submit( uri, null, null, httpMethod, contentType, null, data );
}

public static WebRequestResult Submit( string uri, HTTPMethod httpMethod, string contentType, WebHeaderCollection headers, string data )
{
return Submit( uri, null, null, httpMethod, contentType, headers, data );
}
#endregion

#region Username/password authentication
public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod )
{
return Submit( uri, username, password, httpMethod, DEFAULT_CONTENT_TYPE, null, null );
}

public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod, WebHeaderCollection headers )
{
return Submit( uri, username, password, httpMethod, DEFAULT_CONTENT_TYPE, headers, null );
}

public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod, string data )
{
return Submit( uri, username, password, httpMethod, DEFAULT_CONTENT_TYPE, null, data );
}

public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod, string contentType, WebHeaderCollection headers )
{
return Submit( uri, username, password, httpMethod, contentType, headers, null );
}

public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod, string contentType, string data )
{
return Submit( uri, username, password, httpMethod, contentType, null, data );
}
#endregion

public static WebRequestResult Submit( string uri, string username, string password, HTTPMethod httpMethod, string contentType, WebHeaderCollection headers, string data )
{
WebRequestResult result = new WebRequestResult();

StringBuilder response = new StringBuilder();

HttpWebRequest httpWebRequest = null;
HttpWebResponse httpWebResponse = null;

try
{
httpWebRequest = ( HttpWebRequest )WebRequest.Create( uri );

if ( !string.IsNullOrEmpty( username ) && !string.IsNullOrEmpty( password ) )
{
CredentialCache credentialCache = new CredentialCache();
credentialCache.Add( new Uri( uri ), "Basic", new NetworkCredential( username, password ) );

httpWebRequest.Credentials = credentialCache;
}

if ( headers != null )
{
foreach ( string key in headers.Keys )
{
httpWebRequest.Headers.Add( key, headers[key] );
}
}

httpWebRequest.Method = httpMethod.ToString();
httpWebRequest.ContentType = contentType;

if ( !string.IsNullOrEmpty( data ) )
{
using ( StreamWriter streamWriter = new StreamWriter( httpWebRequest.GetRequestStream() ) )
{
streamWriter.WriteLine( data );
}
}
else
{
httpWebRequest.ContentLength = 0;
}

httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();

if ( httpWebResponse != null )
{
result.Outcome = httpWebResponse.StatusCode;

using ( StreamReader streamReader = new StreamReader( httpWebResponse.GetResponseStream() ) )
{
while ( streamReader.Peek() != -1 )
{
response.Append( streamReader.ReadLine() );
}
}
}
}
catch ( WebException exception )
{
httpWebResponse = exception.Response as HttpWebResponse;

if ( httpWebResponse != null )
{
result.Outcome = httpWebResponse.StatusCode;
}
else
{
result.Outcome = HttpStatusCode.InternalServerError;
}

response.Append( exception.Message );
}
catch ( Exception exception )
{
result.Outcome = HttpStatusCode.InternalServerError;

response.Append( exception.Message );
}
finally
{
try
{
if ( httpWebRequest != null )
{
httpWebRequest.GetRequestStream().Close();
}
}
catch { }

try
{
if ( httpWebResponse != null )
{
httpWebResponse.GetResponseStream().Close();
}
}
catch { }
}

result.Response = response.ToString();

return result;
}

#region No authentication
public static WebRequestResult SubmitXML( string uri, HTTPMethod httpMethod, WebHeaderCollection headers, string xml )
{
return Submit( uri, httpMethod, XML_CONTENT_TYPE, headers, xml );
}
#endregion

#region Username/password authentication
public static WebRequestResult SubmitXML( string uri, string username, string password, HTTPMethod httpMethod, string xml )
{
return Submit( uri, username, password, httpMethod, XML_CONTENT_TYPE, xml );
}

public static WebRequestResult SubmitXML( string uri, string username, string password, HTTPMethod httpMethod, WebHeaderCollection headers, string xml )
{
return Submit( uri, username, password, httpMethod, XML_CONTENT_TYPE, headers, xml );
}
#endregion
}

How do I disable AutoComplete in ASP.NET?

Popular web browsers have a feature called AutoComplete which saves information that has previously been inputted. Web addresses, form data and username/passwords are usually recorded to make life easier in the future.

As a developer, you may want to disable this feature for some types of input including credit card information. ASP.NET has the ability to override the user's choice with the autocomplete attribute by setting it to off. This can be added to a form tag or an individual TextBox control.

Examples:

<form runat="server" autocomplete="off"></form>

<asp:TextBox ID="tbCreditCardNumber" runat="server" autocomplete="off" />

(Runtime)
tbCreditCardNumber.Attributes.Add( "autocomplete", "off" );

Alternatively, you can use the AutoCompleteType attribute on an individual TextBox control and set it to Disabled to achieve the same result.

Example:

<asp:TextBox ID="tbCreditCardNumber" runat="server" AutoCompleteType="Disabled" />

(Runtime)
tbCreditCardNumber.AutoCompleteType = AutoCompleteType.Disabled;

Saturday, 7 June 2008

ASP.NET Wizard - How do I modify templated buttons at runtime?

Accessing a Wizard's templated buttons at runtime is quite tricky and not very elegant using this approach - any better ideas/solutions are more than welcome!

<asp:Wizard ID="MyWizard" runat="server">
<StartNavigationTemplate>
<asp:Button ID="btnNext" runat="server" CommandName="MoveNext" Text="Next" />
</StartNavigationTemplate>
</asp:Wizard>

Control startNavigationTemplate = MyWizard.FindControl( "StartNavigationTemplateContainerID" ) as Control;

if ( startNavigationTemplate != null )
{
Button nextButton = startNavigationTemplate.FindControl( "btnNext" ) as Button ;

if ( nextButton != null )
{
// Do something.
}
}

To manipulate buttons in the step and finish navigiation templates, use StepNavigationTemplateContainerID and FinishNavigationTemplateContainerID respectively.

Stored procedure parameters - Default values

SQL Server stored procedures are good for separating data logic - I like to keep all things SQL together in one resource. I don't like using inline code because it can easily become out-of-date and requries more effort if several applications connect to the database(s). The only problem I had with stored procedures is that I ended up with numerous variations of the same thing (mainly selects). Using default parameters, it is possible to have a single select stored procedure that will always return the same data but the criteria is dynamic.

This example will use the following table:

User ( ID uniqueidentifier, Username nvarchar( 50 ), Password nvarchar( 50 ) )

The stored procedure has 3 parameters; @ID, @Username and @Password mapping to the 3 columns (ID, Username and Password) respectively. The default value of null means that they are optional parameters meaning you can specify none or a combination. Any value(s) passed in will be used in WHERE clause of the SELECT statement. Values of NULL (default) have no effect on the criteria because of the ISNULL check.

Example:

select * [User]
where [ID] = isnull( @ID, [ID] )

If @ID is NULL, the value from the ID column will be used; basically checking if it's equal to itself and returning all of the data inside the table. When the value isn't NULL, only row(s) containing that ID will be returned.


Stored procedure:

create procedure [SelectUser]

@ID uniqueidentifier = null
@Username nvarchar( 50 ) = null
@Password nvarchar( 50 ) = null

as

select * from [User]
where [ID] = isnull( @ID, [ID] ) and [Username] = isnull( @Username, [Username] ) and [Password] = isnull( @Password, [Password] )

Split SQL statements in C#.NET

Have you ever wanted to split a series a SQL statements? Probably not, but here is a code sample anyway! It works by looping through the string and splits the statements on semi-colons (only if they aren't part of some text). I used this on a website that executed SQL code where I wanted to show feedback for each query.



using System;
using System.Collections.Generic;

public class StringUtility
{
public static string SplitSQLStatements( string sql )
{
List<string> sqlStatements = new List<string>();

char separator = ';';

bool isQuoted = false;

int substringStartIndex = 0;

if ( sql.Contains( ";" ) )
{
for ( int characterIndex = 0; characterIndex < sql.Length; characterIndex++ )
{
if ( sql[characterIndex] == '\'' )
{
isQuoted = !isQuoted;
}
else if ( sql[characterIndex] == separator && !isQuoted )
{
sqlStatements.Add( sql.Substring( substringStartIndex, characterIndex + 1 - substringStartIndex ).Trim() );

substringStartIndex = characterIndex + 1;

if ( sql.IndexOf( separator, substringStartIndex, sql.Length - substringStartIndex ) == -1 )
{
break;
}
}
}
}

if ( !sql.EndsWith( separator.ToString() ) )
{
sql = string.Format( "{0};", sql );
}

if ( substringStartIndex < sql.Length - 1 )
{
sqlStatements.Add( sql.Substring( substringStartIndex, sql.Length - substringStartIndex ).Trim() );
}

return sqlStatements.ToArray();
}
}

Remove HTML from strings in C#.NET

If you want to remove tags such as HTML or XML (basically anything between < and >) from a string, use this regular expression to replace them with another value (nothing in this example):

string regularExpresion = "<[^<>]*>";

string body = "<html>this<br />is<br />a<br />test</html>";

Regex regex = new Regex(regularExpresion, RegexOptions.IgnoreCase | RegexOptions.Multiline);

string bodyNoHTML = regex.Replace(body, "").Trim();

Input:
<html>1<br />2<br />2<br />4</html>

Output:
1234

HTML substring in C#.NET

Getting a substring of text containing HTML tags is more tricky than you think. Assume that you want the first 10 characters of the following:

"<p>this is paragraph 1<p><p>this is paragraph 2</p>"

The output would be:

"<p>this is"

As you can see, the returned text contains an unclosed P tag. If this is rendered to a page, subsequent content will be affected by the open P tag. Ideally, the preferred output would close any unclosed HTML tags in reverse of when they were opened:

"<p>this is</p>"

Here is a function that returns a subtring of HTML, making sure that no tags are left unclosed:

using System;
using System.Collections.Generic;

public static class StringUtility
{
public static string HTMLSubstring( string html, int length )
{
if ( html == null )
{
throw new ArgumentNullException( "html" );
}

List<string> unclosedTags = new List<string>();

bool isQuoted = false;

if ( html.Length > length )
{
for ( int i = 0; i < html.Length; i++ )
{
char currentCharacter = html[i];

char nextCharacter = ' ';

if ( i < html.Length - 1 )
{
nextCharacter = html[i + 1];
}

// Check if quotes are on.
if ( !isQuoted )
{
if ( currentCharacter == '<' && nextCharacter != ' ' && nextCharacter != '>' )
{
if ( nextCharacter != '/' ) // Open tag.
{
int startIndex = i + 1;

if ( startIndex < html.Length )
{
int finishIndex = html.IndexOf( ">", startIndex );

if ( finishIndex > 0 )
{
if ( html[finishIndex - 1] != '/' )
{
string tag = html.Substring( startIndex, finishIndex - startIndex );

if ( tag.Contains( " " ) )
{
int temporaryFinishIndex = html.IndexOf( " ", startIndex );

tag = html.Substring( startIndex, temporaryFinishIndex - startIndex );
}

if ( !tag.Equals( "br", StringComparison.InvariantCultureIgnoreCase ) )
{
unclosedTags.Add( tag );
}
}

int tagLength = finishIndex + 1 - i;

length += tagLength;

i = finishIndex;
}
}
}
else if ( nextCharacter == '/' ) // Close tag.
{
int startIndex = i + 2;

if ( startIndex < html.Length )
{
int finishIndex = html.IndexOf( ">", startIndex );

if ( finishIndex > 0 )
{
string tag = html.Substring( startIndex, finishIndex - startIndex );

// FILO.
int index = unclosedTags.LastIndexOf( tag );

if ( index >= 0 )
{
unclosedTags.RemoveAt( index );

int tagLength = finishIndex + 1 - i;

length += tagLength;

i = finishIndex;
}
}
}
}
}
}
else
{
if ( currentCharacter == '"' )
{
isQuoted = false;
}
}

if ( i >= length )
{
html = string.Format( "{0}...", html.Substring( 0, i ) );

unclosedTags.Reverse();

foreach ( string unclosedTag in unclosedTags )
{
html += string.Format( "</{0}>", unclosedTag );
}
}
}
}

return html;
}
}

How do I remove whitespace from XML in C#.NET?

Once again... thanks Neil!

using System;
using System.Text.RegularExpressions;

public static class XMLUtility
{
public static string RemoveWhitespace( string xml )
{
Regex regex = new Regex(@">\s*<");
xml = regex.Replace(xml, "><");

return xml.Trim();
}
}

How do I create a StringWriter with encoding in C#.NET?

Simple, yet effective.

using System;
using System.IO;
using System.Text;

public class StringWriterWithEncoding : StringWriter
{
public StringWriterWithEncoding( StringBuilder builder, Encoding encoding )
: base( builder )
{
_encoding = encoding;
}

Encoding _encoding;

public override Encoding Encoding
{
get { return _encoding; }
}
}

XML serialization in C#.NET

Have you ever tried to parse XML using the .NET framework? I have, and I can never remember the right/wrong way to do it. I normally spend hours on the internet before finding the same solution that I found during my previous attempt. Not anymore! Instead of interacting with the XML directly, convert it to an object that can be easily manipulated. This post shows how to deserialize an XML string into an object and serialize it back into an XML string using attributes from the System.Xml.Serialization namespace in the target class. The important ones that I've highlighted are XmlRoot, XmlAttribute and XmlElement. They're pretty self explanitory - they basically map a class to a root node, a class member to an attribute within a node and a class member to an element node respectively. When declaring these attributes, you specify the name of the attribute/node used in the string XML to establish the relationship. If your class uses exactly the same naming convention as the XML structure, you could (in theory) leave out these attributes. In most cases, the 2 naming conventions differ. I would recommend using them regardless because it makes your application more future proof. If the name of an element node changes, you only have to update the corresponding attribute instead of renaming a class member which could cause problems elsewhere (in the same or even other applications).

This example includes a utility class with 2 important methods - DeserializeObject and SerializeObject. Both use generics so you pass the target class when calling either method. The XML sample can be deserialized to create a Person object. Alternatively, an existing Person object can be serialized to create a similar XML structure.

Utility class:

using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

public class XMLSerializationUtility
{
public static T DeserializeObject<T>( Encoding encoding, string xml )
{
try
{
using (MemoryStream memoryStream = new MemoryStream( StringToByteArray( encoding, xml ) ) )
{
using ( XmlTextWriter xmlTextWriter = new XmlTextWriter( memoryStream, encoding ) )
{
XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) );

return (T)xmlSerializer.Deserialize( memoryStream );
}
}
}
catch
{
return default( T );
}
}

public static string SerializeObject<T>( Encoding encoding, T obj )
{
try
{
MemoryStream memoryStream = new MemoryStream();

using ( XmlTextWriter xmlTextWriter = new XmlTextWriter( memoryStream, encoding ) )
{
XmlSerializer xmlSerializer = new XmlSerializer( typeof( T ) );
xmlSerializer.Serialize( xmlTextWriter, obj );

memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
}

return ByteArrayToString( encoding, memoryStream.ToArray() );
}
catch
{
return string.Empty;
}
}

private static Byte[] StringToByteArray( Encoding encoding, string xml )
{
return encoding.GetBytes( xml );
}

private static string ByteArrayToString( Encoding encoding, byte[] byteArray )
{
return encoding.GetString( byteArray );
}
}

Person class:

using System;
using System.Xml.Serialization;

[XmlRoot( "person" ) ]
public class Person
{
private Guid _id;

[XmlAttribute( "id" )]
public Guid ID;
{
get { return _id; }
set { _id = value; }
}

private string _name;

[XmlElement( "Name" )]
public string Name;
{
get { return _name; }
set { _name = value; }
}

private DateTime _dateOfBirth;

[XmlElement( "dob" )]
public DateTime DateOfBirth;
{
get { return _dateOfBirth; }
set { _dateOfBirth = value; }
}

}

XML:

<?xml version="1.0" encoding="utf-8"?>
<person id="0ADD2974-B14E-440B-B435-C0AF65E57ACF">
<name>Andrew Gunn</name>
<dob>1985-08-08T12:00:00Z</dob>
</person>

Deserialize string XML into a Person object:
Person person = XMLSerializationUtility.DeserializeObject<Person>( Encoding.UTF8, xml );

Serialize a Person object into string XML:
string xml = XMLSerializationUtility.SerializeObject<Person>( Encoding.UTF8, Person );

Nullable Types in C#.NET

Nullable types allow other value types to be represented as a "null value".

Both examples produce the same result, but I prefer the first because it confuses the hell out of people who don't know it's meaning and requires less coding:

int? x = null;
Nullable<int> y = null;

ASP.NET Wizard - Finish button CommandName

If you want to override the FinishNavigationTemplate template, the CommandName for the finish button is MoveComplete. I found several websites claiming it is MoveFinish but this won't trigger the event (definitely under the .NET 2.0 framework).

Example:

<asp:Wizard runat="server">
<FinishNavigationTemplate>
<asp:Button runat="server" CommandName="MoveComplete" Text="Finish" />
</FinishNavigationTemplate>
</asp:Wizard>