Posts Tagged ‘Framework 2.0’

October 1st, 2007

Anything For Sale By Owner

Anything For Sale By Owner LogoAs I alluded in a post a couple of weeks ago, I have been a bad blogger. And I have neglected my community of readers. However I would like to tell you what I have been doing in the last couple of months while I have been neglecting my blog.

I recently got involved in creating a startup as the lead developer for an online classifieds site called Anything For Sale By Owner. From the ground up this was conceived as a middle-ground between craigslist and ebay where every listing would be charged at a static rate of $1.00/month. The $1.00 is a way to week out the crap from craigslist and the death-by-fees from ebay.

The description is pretty straight forward but the more interesting tid-bits that I know my readers are interested in are as follows:

.NET/C#

We choose .NET mostly because it is what I knew and .NET for me has always been stable, predictable, and performed really well on server-side applications. The alternative was PHP and even through we wrote many of the processing layers by our self (i.e. REST Web Service Handler) the time to deployment was greatly accelerated because of all the work the Microsoft ASP.NET Team has put in to the product. The user of Master Pages and Web Services made for an easy separation between content and display.

MySQL

We choose MySQL for a whole host of reasons mostly based around the costs associated with a single Microsoft SQL Server Standard Edition license. Other reasons we choose MySQL was for scalability, because not only could we install 5 database servers (hardware included) for the same price we could purchase 1 MSSQL database server for but also because the master/slave replication of the databases seemed to be an easier process when we needed to scale horizontally.

REST Web Services/AJAX

We followed the Digg Model for exposing web services and each web service could be changed around to provide output through JSON, RSS, ATOM, KML (where applicable), and XML. I even did a write up about a month ago on the JSON Serializer that I developed for this website. This was very important for the AJAX we needed to control many aspects of the user experience.

Open Search

Open search was one of the value add features that wasn’t in the original spec but was an easy add-on because we already had the Web Services in place to leverage. You can view our open search XML definition file here. If you are unfamiliar with Open Search this is how A9.com defines it:

OpenSearch is a set of simple formats for the sharing of search results. Any website that has a search feature can make their results available in OpenSearch format. Other tools can then read those search results.

So that little search box in the upper right hand corner of your browser is an example of an Open Search client.

SEO

Search Engine Optimization is a very important part of any website today. Because for most new sites and even some of the older ones, Google is going to be the largest most ignored user of the site. Not only will Google look at every single page on your site every week, which I dare any human to try and accomplish, they will also be the largest organic promoter of your site.

One of the corner stones of SEO is easily readable URL’s that contain descriptive keywords. This means you have to have a good URL Rewriter in place. We choose Ionic’s ISAPI Rewriter that integrated nicely with IIS 6.0. However that left a big gap between using Visual Studio’s Intigrated Web Server (which doesn’t support ISAPI) and a full blown IIS Server. The benifits are pretty obvious for running the Intigrated Web Server that comes with Visual Studio, for one you don’t always have to have IIS that comes with Windows XP always running and the host of security problems that comes with it, two I was running Windows Vista and IIS 7.0 has some huge differences from IIS 6.0.

So I sat down one night and wrote my own Apache mod_rewrite compatible HttpModule for running the same rule-set that I defined for Ionic’s ISAPI Rewriter, to fill in the gap and make developing on my local machine as close as running the live web site on IIS 6.0.

If anybody is interested I offer the Url Rrewriter as a free download:

Front End Design

I am a software developer and usually don’t get invovled in the artsy end of the web site design. So I will let my co-worker Tom Lauck describe how he developed the front-end for Anything For Sale By Owner.

So all in all I believe that this website has a very good chance of making in the Wild Wild West that the Internet is, however that is probably just the ramblings of a proud father. Be on the look out for some major marketing campaigns in the NYC Times Square region.

Tags: , , , , , , , , , , ,

Posted in ASP.NET, C#, Portfolio, Programming, Rant, SEO, SQL | kick it on DotNetKicks.com | Bookmark | View blog reactions | 1 Comment »

August 24th, 2007

Creating a more accurate JSON .NET Serializer

Recently I have been diving in to the world of REST and all the great things that come along with that. If you are not familiar with REST and what it means to have a REST Web Service for your site, you can go through the Digg API, which should give you a pretty good idea. My company has been contracted to build the framework for a new Web 2.0 initiative of one of our clients. You cannot do Web 2.0 if you are not using some kind of AJAX/REST combination.

With the inclusion of Microsoft AJAX.NET are some very useful tools that have been added to the web services library. My current focus in System.Web.Script.Serialization.JavaScriptSerializer, which takes you objects and turns them in to a JSON string that can be evaluated by JavaScript and reversed in to an object. JSON (pronounced Jason) is very useful in AJAX because you do not have to retrieve and parse XML through the XML Browser Request that powers current AJAX implementations.

I found the attribute support lacking in the JavaScriptSerializer when compared to the XmlSerializer, ScriptIgnoreAttribute compared to XmlRootAttribute, XmlAttributeAttribute, XmlIgnoreAttribute, XmlElementAttribute, XmlArrayAttribute, and XmlArrayItemAttribute. So I decided to extend the JavaScriptSerializer to use the XML attributes to serialize my objects and give me greater control over how they were written in to JSON text form. The added benefit was that my XML and JSON outputs serialized the exact same way when the web service generated them. Below I have included the code.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Web.Script;
using System.Web.Script.Serialization;
using System.Xml.Serialization;

namespace ManagedFusion.Script.Serializer
{
	public class XmlJavaScriptConverter<T> : JavaScriptConverter
	{
		public override object Deserialize(IDictionary<string,string> dictionary, Type type, JavaScriptSerializer serializer)
		{
			throw new Exception("The method or operation is not implemented.");
		}

		public override IDictionary<string,string> Serialize(object obj, JavaScriptSerializer serializer)
		{
			return SerializeObject(obj);
		}

		private IDictionary<string,string> SerializeObject(object obj)
		{
			IDictionary<string,string> values = new Dictionary<string,string>();
			Type type = obj.GetType();

			foreach (FieldInfo info in type.GetFields(BindingFlags.Public | BindingFlags.Instance))
				if (!info.IsDefined(typeof(XmlIgnoreAttribute), true))
					values.Add(SerializeName(info), SerializeValue(info.GetValue(obj), info));

			foreach (PropertyInfo info2 in type.GetProperties(BindingFlags.GetProperty | BindingFlags.Public | BindingFlags.Instance))
			{
				if (!info2.IsDefined(typeof(XmlIgnoreAttribute), true))
				{
					MethodInfo getMethod = info2.GetGetMethod();
					if ((getMethod != null) && (getMethod.GetParameters().Length <= 0))
						values.Add(SerializeName(info2), SerializeValue(getMethod.Invoke(obj, null), info2));
				}
			}

			return values;
		}

		private string SerializeName(MemberInfo member)
		{
			string name = null;

			if (member.IsDefined(typeof(XmlElementAttribute), true))
			{
				object[] attrs = member.GetCustomAttributes(typeof(XmlElementAttribute), true);

				if (attrs.Length > 0)
				{
					XmlElementAttribute attr = attrs[0] as XmlElementAttribute;

					name = attr.ElementName;
				}
			}

			if (member.IsDefined(typeof(XmlAttributeAttribute), true))
			{
				object[] attrs = member.GetCustomAttributes(typeof(XmlAttributeAttribute), true);

				if (attrs.Length > 0)
				{
					XmlAttributeAttribute attr = attrs[0] as XmlAttributeAttribute;

					name = attr.AttributeName;
				}
			}

			if (member.IsDefined(typeof(XmlArrayAttribute), true))
			{
				object[] attrs = member.GetCustomAttributes(typeof(XmlArrayAttribute), true);

				if (attrs.Length > 0)
				{
					XmlArrayAttribute attr = attrs[0] as XmlArrayAttribute;

					name = attr.ElementName;
				}
			}

			if (String.IsNullOrEmpty(name))
				name = null;

			return name ?? member.Name;
		}

		private object SerializeValue(object obj, MemberInfo member)
		{
			if (obj == null)
				return obj;

			// make sure the object isn't an easily handled primity type
			if (Type.GetTypeCode(obj.GetType()) != TypeCode.Object)
				return obj;

			if (obj is IDictionary)
				return obj;

			if (obj is ICollection)
			{
				IList<object> list = new List<object>();
				object[] attrs = member.GetCustomAttributes(typeof(XmlArrayItemAttribute), true);
				string arrayName = null;

				if (attrs.Length > 0)
				{
					XmlArrayItemAttribute attr = attrs[0] as XmlArrayItemAttribute;

					arrayName = attr.ElementName;
				}

				if (String.IsNullOrEmpty(arrayName))
				{
					foreach (object o in (obj as ICollection))
					{
						if (Type.GetTypeCode(o.GetType()) != TypeCode.Object)
							list.Add(o);
						else
							list.Add(SerializeObject(o));
					}
				}
				else
				{
					foreach (object o in (obj as ICollection))
					{
						IDictionary<string,object> list2 = new Dictionary<string,object>();

						if (Type.GetTypeCode(o.GetType()) != TypeCode.Object)
							list2.Add(arrayName, o);
						else
							list2.Add(arrayName, SerializeObject(o));

						list.Add(list2);
					}
				}

				return list;
			}

			return SerializeObject(obj);
		}

		public override IEnumerable<Type> SupportedTypes
		{
			get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(T) })); }
		}
	}
}

Then to serialize the object in my code I have the following code in place.

JavaScriptSerializer jsSerializer = new JavaScriptSerializer();
jsSerializer.RegisterConverters(new List<JavaScriptConverter>(new JavaScriptConverter[] { new XmlJavaScriptConverter<T>() }));
string response = jsSerializer.Serialize(SerializableObject);

The serializer from above outputs the following code.

{"timestamp":"\/Date(1187968133328)\/","maxCount":10,"count":1,"terms":[{"term":"dvd hollywood"}]}

From this object as the reference.

[XmlRoot("search")]
public class GetTermsResponse
{
	private string[] _terms;
	private int _maxCount;

	[XmlAttribute("timestamp")]
	public DateTime TimeStamp
	{
		get { return DateTime.Now; }
		set { ; }
	}

	[XmlAttribute("maxCount")]
	public int MaxCount
	{
		get { return _maxCount; }
		set { _maxCount = value; }
	}

	[XmlAttribute("count")]
	public int Count
	{
		get { return Terms.Length; }
		set { ; }
	}

	[XmlArray("terms")]
	[XmlArrayItem("term")]
	public string[] Terms
	{
		get { return _terms; }
		set { _terms = value; }
	}
}

So that wasn’t too hard the next step for this code is to make it so it can deserialize the JSON string back to an object, but the chances of that happening are almost 100/1 against the use of that functionality, because POST using JSON is a very dangerous activity and shouldn’t be attempted unless you know all the problems that may occur. So this code above should work in most real world examples. Happy coding.

Tags: , , ,

Posted in ASP.NET, C#, Programming | kick it on DotNetKicks.com | Bookmark | View blog reactions | 2 Comments »

May 11th, 2007

Understanding C#: ?? Operator

The ?? operator returns the left-hand operand if it is not null, or else it returns the right operand.

int? i = null;
int count = i ?? 0;

The value that count is set to is 0. The ?? operator is short hand for:

int? i = null;
int count = i.HasValue ? i.Value : 0;

Or

int? i = null;
int count = 0;
if (i.HasValue)
	count = i.Value;

The Understanding C# series at Coder Journal will be an on going project to help the readers to better understand the C# programming language that doesn’t get covered except at the more advanced levels.

Tags: ,

Posted in C#, Programming | kick it on DotNetKicks.com | Bookmark | View blog reactions | No Comments »

March 27th, 2007

Creating a Vista like Search Box

Introduction

In this post we are going to go over what it takes to create a control, and more specifically a Vista Search Box like control.

Definition of Current Search Box

The first thing to do when creating a new control for Windows Forms is determine all the states of the control. In our case the control states are rather simple:

Inactive:
Vista (Inactive)

Active:
Vista (Active)

Text Entered:
Vista (Text Entered)

Button Active:
Vista (Button Active)

Creating the Search Box

The next objective is to determine the inputs, outputs, and events for the control.

Inputs:

  • Text
  • Button Click

Outputs:

  • Text

Events:

  • Text Changed

So now that we have all the inputs, outputs, and events determined, we can start creating the control. The first thing to determine is if we already have a good starting point control that does mostly everything we need. You may be thinking that TextBox Control is a perfect starting point. Normally I would agree with you, but there are certain properties of the TextBox Control that provides states to our search box that shouldn’t be available, such as Multi-Line TextBox, and Password TextBox, both of these examples fall outside of the scope of what our TextBox is suppose to accomplish.

So that leaves us with Control, which is the basis, for all Graphical Objects in the Windows Form library. The pros of using Control over an already established object is that you get to define the exact inputs, outputs, and events that you need. We now need to define all the appearance related properties for our SearchTextBox.

  • HoverButtonColor
  • ActiveBackColor
  • ActiveForeColor
  • InactiveBackColor
  • InactiveForeColor
  • InactiveFont
  • InactiveText
[Category("Appearance")]
[DefaultValue(typeof(Color), "GradientInactiveCaption")]
public Color HoverButtonColor
{
	get { return _hoverButtonColor; }
	set { _hoverButtonColor = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Color), "WindowText")]
public Color ActiveForeColor
{
	get { return _activeForeColor; }
	set { _activeForeColor = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Color), "Window")]
public Color ActiveBackColor
{
	get { return _activeBackColor; }
	set { _activeBackColor = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Color), "GrayText")]
public Color InactiveForeColor
{
	get { return _inactiveForeColor; }
	set { _inactiveForeColor = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Color), "InactiveBorder")]
public Color InactiveBackColor
{
	get { return _inactiveBackColor; }
	set { _inactiveBackColor = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Cursor), "IBeam")]
public override Cursor Cursor
{
	get { return base.Cursor; }
	set { base.Cursor = value; }
}

[Browsable(false)]
public override Color ForeColor
{
	get { return base.ForeColor; }
	set { base.ForeColor = value; }
}

[Browsable(false)]
public override Color BackColor
{
	get { return base.BackColor; }
	set { base.BackColor = value; }
}

[Category("Appearance")]
[DefaultValue(DefaultInactiveText)]
public string InactiveText
{
	get { return _inactiveText; }
	set { _inactiveText = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Font), "Microsoft Sans Serif, 8.25pt")]
public Font ActiveFont
{
	get { return base.Font; }
	set { base.Font = value; }
}

[Category("Appearance")]
[DefaultValue(typeof(Font), "Microsoft Sans Serif, 8.25pt, style=Bold, Italic")]
public Font InactiveFont
{
	get { return _inactiveFont; }
	set { _inactiveFont = value; }
}

[Browsable(false)]
public override Font Font
{
	get { return base.Font; }
	set { base.Font = value; }
}

[Category("Appearance")]
public override string Text
{
	get { return searchText.Text; }
	set { searchText.Text = value; }
}

note: You will notice three different attributes on most of the class properties. They are Category, DefaultValue, Browsable, these are outside of the scope of this article, but I will tell you they effect how the Visual Studio IDE interacts with the SearchTextBox and its available properties at design time.

Next thing we need to do is hook up all the controls events to our specified properties so it acts as we expect it to as defined in our states above. The Control Events we are going to use in order to accomplish the for states that were listed above are: GotFocus, LostFocus, ForeColorChanged, BackColorChanged, Click, and TextChanged.

  • GotFocus
    Occurs when the control receives focus.
  • LostFocus
    Occurs when the control loses focus.
  • ForeColorChanged
    Occurs when the ForeColor property value changes.
  • BackColorChanged
    Occurs when the value of the BackColor property changes.
  • Click
    Occurs when the control is clicked.
  • TextChanged
    Occurs when the Text property value changes.

note: Please see the code listed below for how these events were implemented for our SearchTextBox.

Look & Feel

Well the Control Object isn’t quite as full featured as some of the other controls in the library. So in order to give our SearchTextBox a border to make it look more like a text box we need to tell Windows to draw it with some Native Constants that Windows uses. I am not going to go much in to what all this means, but I will tell you that it draws a thin border around the control.

protected override CreateParams CreateParams
{
	[SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
	get
	{
		CreateParams createParams = base.CreateParams;
		createParams.ExStyle |= NativeConstants.WS_EX_CONTROLPARENT;
		createParams.ExStyle &= ~NativeConstants.WS_EX_CLIENTEDGE;

		// make sure WS_BORDER is present in the style
		createParams.Style |= NativeConstants.WS_BORDER;

		return createParams;
	}
}

The next and last thing we need to do to complete our control is set some more attributes that tells the Visual Studio IDE how to interact with our control.

	[Designer(typeof(CoderJournal.Controls.Design.SearchTextBoxDesigner))]
	[DefaultEvent("TextChanged")]
	[DefaultProperty("Text")]
	public partial class SearchTextBox : Control

The Designer Attribute is important because it tells Visual Studio IDE how to render our control. The most important part of the designer class which is outlined in the source package is it’s ability to control how our control is sized. Because when you have a normal TextBox Control you can only size it vertically if the multi-line property is not set. So in order to duplicate this behavior we need to create this designer class.

public override SelectionRules SelectionRules
{
	get
	{
		return base.SelectionRules & ~(SelectionRules.BottomSizeable | SelectionRules.TopSizeable);
	}
}

Example of Use

SearchTextBox searchText = new SearchTextBox();
searchText.TextChanged += delegate(object sender, EventArgs e) {
	outputLabel.Text += Environment.NewLine + searchText.Text;
}

Our Search Box

The following may note be the exact look and feel of Windows Vista, mostly for technical reasons, but there are also some legal ones too. However for the most part you should find the functionality the same.

Inactive:
My Code (Inactive)

Active:
My Code (Active)

Text Entered:
My Code (Text Entered)

Button Active:
My Code (Button Active)

Application & Source

The following is a download of the application and the source of the code that we just went over. Please use the following source code in anyway that you see necessary, just please give my self, Nick Berardi, and this post reference when you use it in its current or modified form. This code comes with no warranty, and for legal reasons is not supported by me.

If you have any questions or comments about this article or the code please feel free to reply below.

Tags: , , , ,

Posted in C#, How To, Programming | kick it on DotNetKicks.com | Bookmark | View blog reactions | 7 Comments »