Tag archive for 'net'

07
Feb

Web site vs web application in Visual Studio

Rob Conery got me thinking about web site maintenance and I put forward a brief comment on the two distinct types and how Visual Studio handles them which I have expanded upon here.

Web site

Primarily for working with ad-hoc web sites that have programmed elements. Easily identified by customer-specific content present in aspx files.

No solution or project files are required and the pages and source can reside locally (file system, IIS) or remotely (FTP, WebDev/FrontPage extensions) via the File > Open > Web Site... menu option.

Code-behind and classes are typically stored on the web server which compiles them in-memory on demand. Changes can be made to the files without restarting the application and losing sessions.

For Against
Quick edit, test, deploy cycle Syntax errors at runtime
No need to compile or restart app Can't create an installer
Source always available Source on server useful to hackers

Web application

Web application projects were introduced as an add-on for Visual Studio 2005, later rolled in to VS 2005 SP1 and made a full first-class citizen with Visual Studio 2008.

Like the name implies these are primarily for web applications, those times when you have written a product or solution that happens to have a web interface.

Web application projects exist on your local drive and are treated like any other VS project type and can be added to existing solutions are subject to full compilation, validation and build steps.

Deployment is typically via MSI installers however you can also utilise the addition Web Deployment Projects add-in which allows you to deployment directly to servers which is useful for deploying to test environments.

For Against
Controlled build & deploy process Deployment causes application restart
No class files on web server, dll only Can't deploy individual classes
Syntax errors at compile time  

Hybrid

Sander and I were discussing this article and thought an interesting solution might be to use the Web Application model for local development but to use the Publish option to publish all solution files to an intermediate directory.

Then in the intermediate directory just remove the bin/applicationname.dll file and copy to the target. This should prevent an application restart unless the web.config or global.asax/global.asax.vb files have been modified.

[)amien

31
Jan

The pragmatic .NET developer

Long-time friend, fellow co-host of the GSDF and the coding genius behind the open-source Ogre3D engine Steve Streeting has written an interesting piece on Open source adoption; countering the fear and doubt. I have no doubt that this was fuelled by a lengthy discussion last night in the Ship & Crown pub - a common ritual after our GSDF meetings.

The reasons why I adopted .NET as my primary platform despite being tied to a single-supplier are:

  • Ease of deployment & set-up
  • Low resistance to adoption
  • Great tool integration
  • Official & community support
  • Love for C# and the CLR

The ALT.NET movement

Many .NET developers are reluctant to look wider afield but this is not exclusively the case and a person focused on the .NET platform but open to selecting beneficial alternatives to the Microsoft prescription is exactly what the ALT.NET moniker was coined to encapsulate.

SourceForge lists over 6,000 open-source C# projects alone and many well-known open source Java & PHP projects have made their way to the .NET platform. NHibernate, NUnit, NCover, Spring.NET & DotNetNuke alongside new .NET developments such as xUnit.NET, SubSonic, Subtext etc.

Best of breed

Where a non-Microsoft option is functionally superior or more cost effective I will consider it whether it is proprietary or open source.

I do not however select a solution simply because it is considered the "best of breed" at that particular moment. Integration, training, availability of support and experienced developers, deployment, cost, barriers to entry and roadmaps must be taken into account.

Given that Microsoft provide the .NET platform anything 'in-the-box' scores highly in many of these areas.

Sometimes a non-Microsoft solution comes out on top or there is a compelling reason to adopt it anyway. This is why my toolkit already contains Subversion, TortoiseSVN, AnkhSVN, Reflector and NUnit.

It's also why I currently run Mac OS X alongside Vista, use WordPress as my blogging platform, prepare my presentations with KeyNote and use OmniFocus to organise my life.

Robust alternative projects

I have concerns about longevity and support on projects from companies and hobbyists regardless of whether they are open source or proprietary.

NDoc, CVS & NullableTypes are three I've used which died when an alternative commercial or open source project gained more momentum and SourceForge is seemingly littered with thousands of dead projects.

If a project you rely upon dies you have one of a number of options:

  1. Migrate to something new (gained little from open source)
  2. Fix bugs and problems yourself (time spent working outside your business domain)
  3. Have a support contract with somebody else to work on it (single-supplier scenario?)

Competition is important

Competition is important but I can not, in a professional capacity, recommend to customers something that I believe is less suitable in the interest of keeping the competition healthy.

Confusion about choice

I hit this one first hand developing my final-year degree project which required development of a web site in Java.

The number of choices for Java was incredibly confusing despite knowing the syntax. J2SE or J2EE? JSP, Struts, Spring or another servlet package? What about the database and ORM? Application server? What versions work together? What overlaps? Would I be able to get experienced developers? If not how long to train them up?

.NET has many options too but I can start with the .NET Framework and get right into solving the domain problem. If the going gets tough I may have taken a wrong turn and need a different solution. That could involve choosing an alternative component or framework but now I'll know what problem I'm trying to solve when I go looking.

Developers on complex projects felt that WebForms wasn't ideal - it is hard to maintain, the output bloated with leaky implementation (ViewState) but it serves many developers well enough.

Open-source projects such as MonoRail addressed this taking cues from Ruby on Rails. Microsoft acknowledge this and add a similar MVC framework going so far as to support additional engines and components allowing elements of MonoRail to be used. Those guys could drop the glue required to get their engines into the pipeline and just concentrate on engines if they wish.

What works for me

Stay small and focused until you feel friction.

Friction isn't always technical or immediately obvious. It might be future plans and it's often people. It might be what isn't there and will never be.

Time lost on friction is not spent developing your domains features.

If another solution causes less friction, use it but don't underestimate unknowns.

I guess that's just being pragmatic.

[)amien

28
Jan

Language Integrated Query: An introduction talk tomorrow

I'm just finishing up the slides, notes and writing code samples for my LINQ presentation at the Guernsey Software Developer Forum tomorrow evening.

Hopefully the broader scope of this presentation will mean a few new faces - the previous talks on Subversion and web application security might have been a little specific for a such a small audience (Guernsey is around 70,000 people on an island 9 miles long).

As always I will put the presentation up here afterwards but will also revise the older ones with the new style and put up both PowerPoint and Keynote versions under an open licence as well as a couple of cheat sheets.

Is there any interest in adding audio narration and transcripts?

This presentation is now available on-line.

[)amien

24
Nov

Calculating Elf-32 in C# and .NET

Because you can never have enough hashing algorithms at your disposal this one is compatible with the elf_hash function that forms part of the Executable and Linkable Format.

using System;
using System.Security.Cryptography;

public class Elf32 : HashAlgorithm
{
	private UInt32 hash;

	public Elf32()
	{
		Initialize();
	}

	public override void Initialize()
	{
		hash = 0;
	}

	protected override void HashCore(byte[] buffer, int start, int length)
	{
		hash = CalculateHash(hash, buffer, start, length);
	}

	protected override byte[] HashFinal()
	{
		byte[] hashBuffer = UInt32ToBigEndianBytes(hash);
		this.HashValue = hashBuffer;
		return hashBuffer;
	}

	public override int HashSize
	{
		get { return 32; }
	}

	public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer)
	{
		return CalculateHash(seed, buffer, 0, buffer.Length);
	}

	private static UInt32 CalculateHash(UInt32 seed, byte[] buffer, int start, int size)
	{
		UInt32 hash = seed;

		for (int i = start; i < size; i++)
			unchecked {
				hash = (hash << 4) + buffer[i];
				UInt32 work = (hash & 0xf0000000);
				if (work != 0)
					hash ^= (work >> 24);
				hash &= ~work;
			}
		return hash;
	}

	private byte[] UInt32ToBigEndianBytes(UInt32 x)
	{
		return new byte[] {
			(byte)((x >> 24) & 0xff),
			(byte)((x >> 16) & 0xff),
			(byte)((x >> 8) & 0xff),
			(byte)(x & 0xff)
		};
	}
}

[)amien

22
Nov

Publishing .NET applications with prerequisites

Now .NET 3.5 is shipping I took the opportunity to update one of our internal applications and elected to have it install the necessary components (in this case the .NET Framework 3.5) using the Download prerequisites from the same location as my application option.

When trying to install the application via the IIS web server the installer would fail with a download error.

A little testing later I realised the publishing mechanism had placed .msu and .msp files for prerequisites onto the server and of course IIS 6.0 does not serve unknown MIME types.

Both .msu and .msp extensions must be added into the MIME database as application/octet-stream via MMC.

And all was well again.

[)amien

19
Nov

Calculating CRC-64 in C# and .NET

Seeing how the CRC-32 C# class I posted some time ago continues to get lots of Google hits I thought I'd post a CRC-64 version which will no doubt be far less popular being the more limited use. Again, do not use this as a secure message signature, it's really for backward compatibility with legacy systems.

Unlike the previous CRC-32 version this one uses a pre-generated constant (well, readonly) table as the generation code was quite slow.

using System;
using System.Security.Cryptography;

public class Crc64 : HashAlgorithm
{
	public const UInt64 DefaultSeed = 0x0;

	private static readonly UInt64[] table = new UInt64[] {
		0x0000000000000000L, 0x01b0000000000000L, 0x0360000000000000L,
		0x02d0000000000000L, 0x06c0000000000000L, 0x0770000000000000L,
		0x05a0000000000000L, 0x0410000000000000L, 0x0d80000000000000L,
		0x0c30000000000000L, 0x0ee0000000000000L, 0x0f50000000000000L,
		0x0b40000000000000L, 0x0af0000000000000L, 0x0820000000000000L,
		0x0990000000000000L, 0x1b00000000000000L, 0x1ab0000000000000L,
		0x1860000000000000L, 0x19d0000000000000L, 0x1dc0000000000000L,
		0x1c70000000000000L, 0x1ea0000000000000L, 0x1f10000000000000L,
		0x1680000000000000L, 0x1730000000000000L, 0x15e0000000000000L,
		0x1450000000000000L, 0x1040000000000000L, 0x11f0000000000000L,
		0x1320000000000000L, 0x1290000000000000L, 0x3600000000000000L,
		0x37b0000000000000L, 0x3560000000000000L, 0x34d0000000000000L,
		0x30c0000000000000L, 0x3170000000000000L, 0x33a0000000000000L,
		0x3210000000000000L, 0x3b80000000000000L, 0x3a30000000000000L,
		0x38e0000000000000L, 0x3950000000000000L, 0x3d40000000000000L,
		0x3cf0000000000000L, 0x3e20000000000000L, 0x3f90000000000000L,
		0x2d00000000000000L, 0x2cb0000000000000L, 0x2e60000000000000L,
		0x2fd0000000000000L, 0x2bc0000000000000L, 0x2a70000000000000L,
		0x28a0000000000000L, 0x2910000000000000L, 0x2080000000000000L,
		0x2130000000000000L, 0x23e0000000000000L, 0x2250000000000000L,
		0x2640000000000000L, 0x27f0000000000000L, 0x2520000000000000L,
		0x2490000000000000L, 0x6c00000000000000L, 0x6db0000000000000L,
		0x6f60000000000000L, 0x6ed0000000000000L, 0x6ac0000000000000L,
		0x6b70000000000000L, 0x69a0000000000000L, 0x6810000000000000L,
		0x6180000000000000L, 0x6030000000000000L, 0x62e0000000000000L,
		0x6350000000000000L, 0x6740000000000000L, 0x66f0000000000000L,
		0x6420000000000000L, 0x6590000000000000L, 0x7700000000000000L,
		0x76b0000000000000L, 0x7460000000000000L, 0x75d0000000000000L,
		0x71c0000000000000L, 0x7070000000000000L, 0x72a0000000000000L,
		0x7310000000000000L, 0x7a80000000000000L, 0x7b30000000000000L,
		0x79e0000000000000L, 0x7850000000000000L, 0x7c40000000000000L,
		0x7df0000000000000L, 0x7f20000000000000L, 0x7e90000000000000L,
		0x5a00000000000000L, 0x5bb0000000000000L, 0x5960000000000000L,
		0x58d0000000000000L, 0x5cc0000000000000L, 0x5d70000000000000L,
		0x5fa0000000000000L, 0x5e10000000000000L, 0x5780000000000000L,
		0x5630000000000000L, 0x54e0000000000000L, 0x5550000000000000L,
		0x5140000000000000L, 0x50f0000000000000L, 0x5220000000000000L,
		0x5390000000000000L, 0x4100000000000000L, 0x40b0000000000000L,
		0x4260000000000000L, 0x43d0000000000000L, 0x47c0000000000000L,
		0x4670000000000000L, 0x44a0000000000000L, 0x4510000000000000L,
		0x4c80000000000000L, 0x4d30000000000000L, 0x4fe0000000000000L,
		0x4e50000000000000L, 0x4a40000000000000L, 0x4bf0000000000000L,
		0x4920000000000000L, 0x4890000000000000L, 0xd800000000000000L,
		0xd9b0000000000000L, 0xdb60000000000000L, 0xdad0000000000000L,
		0xdec0000000000000L, 0xdf70000000000000L, 0xdda0000000000000L,
		0xdc10000000000000L, 0xd580000000000000L, 0xd430000000000000L,
		0xd6e0000000000000L, 0xd750000000000000L, 0xd340000000000000L,
		0xd2f0000000000000L, 0xd020000000000000L, 0xd190000000000000L,
		0xc300000000000000L, 0xc2b0000000000000L, 0xc060000000000000L,
		0xc1d0000000000000L, 0xc5c0000000000000L, 0xc470000000000000L,
		0xc6a0000000000000L, 0xc710000000000000L, 0xce80000000000000L,
		0xcf30000000000000L, 0xcde0000000000000L, 0xcc50000000000000L,
		0xc840000000000000L, 0xc9f0000000000000L, 0xcb20000000000000L,
		0xca90000000000000L, 0xee00000000000000L, 0xefb0000000000000L,
		0xed60000000000000L, 0xecd0000000000000L, 0xe8c0000000000000L,
		0xe970000000000000L, 0xeba0000000000000L, 0xea10000000000000L,
		0xe380000000000000L, 0xe230000000000000L, 0xe0e0000000000000L,
		0xe150000000000000L, 0xe540000000000000L, 0xe4f0000000000000L,
		0xe620000000000000L, 0xe790000000000000L, 0xf500000000000000L,
		0xf4b0000000000000L, 0xf660000000000000L, 0xf7d0000000000000L,
		0xf3c0000000000000L, 0xf270000000000000L, 0xf0a0000000000000L,
		0xf110000000000000L, 0xf880000000000000L, 0xf930000000000000L,
		0xfbe0000000000000L, 0xfa50000000000000L, 0xfe40000000000000L,
		0xfff0000000000000L, 0xfd20000000000000L, 0xfc90000000000000L,
		0xb400000000000000L, 0xb5b0000000000000L, 0xb760000000000000L,
		0xb6d0000000000000L, 0xb2c0000000000000L, 0xb370000000000000L,
		0xb1a0000000000000L, 0xb010000000000000L, 0xb980000000000000L,
		0xb830000000000000L, 0xbae0000000000000L, 0xbb50000000000000L,
		0xbf40000000000000L, 0xbef0000000000000L, 0xbc20000000000000L,
		0xbd90000000000000L, 0xaf00000000000000L, 0xaeb0000000000000L,
		0xac60000000000000L, 0xadd0000000000000L, 0xa9c0000000000000L,
		0xa870000000000000L, 0xaaa0000000000000L, 0xab10000000000000L,
		0xa280000000000000L, 0xa330000000000000L, 0xa1e0000000000000L,
		0xa050000000000000L, 0xa440000000000000L, 0xa5f0000000000000L,
		0xa720000000000000L, 0xa690000000000000L, 0x8200000000000000L,
		0x83b0000000000000L, 0x8160000000000000L, 0x80d0000000000000L,
		0x84c0000000000000L, 0x8570000000000000L, 0x87a0000000000000L,
		0x8610000000000000L, 0x8f80000000000000L, 0x8e30000000000000L,
		0x8ce0000000000000L, 0x8d50000000000000L, 0x8940000000000000L,
		0x88f0000000000000L, 0x8a20000000000000L, 0x8b90000000000000L,
		0x9900000000000000L, 0x98b0000000000000L, 0x9a60000000000000L,
		0x9bd0000000000000L, 0x9fc0000000000000L, 0x9e70000000000000L,
		0x9ca0000000000000L, 0x9d10000000000000L, 0x9480000000000000L,
		0x9530000000000000L, 0x97e0000000000000L, 0x9650000000000000L,
		0x9240000000000000L, 0x93f0000000000000L, 0x9120000000000000L,
		0x9090000000000000L
	};

	private UInt64 seed;
	private UInt64 hash;

	public Crc64()
	{
		seed = DefaultSeed;
		Initialize();
	}

	public Crc64(UInt64 seed)
	{
		this.seed = seed;
		Initialize();
	}

	public override void Initialize()
	{
		hash = seed;
	}

	protected override void HashCore(byte[] buffer, int start, int length)
	{
		hash = CalculateHash(hash, buffer, start, length);
	}

	protected override byte[] HashFinal()
	{
		byte[] hashBuffer = UInt64ToBigEndianBytes(hash);
		this.HashValue = hashBuffer;
		return hashBuffer;
	}

	public override int HashSize
	{
		get { return 64; }
	}

	public static UInt64 Compute(UInt64 seed, byte[] buffer)
	{
		return CalculateHash(seed, buffer, 0, buffer.Length);
	}

	private static UInt64 CalculateHash(UInt64 seed, byte[] buffer, int start, int size)
	{
		UInt64 crc = seed;

		for (int i = start; i < size; i++)
			unchecked {
				crc = (crc >> 8) ^ table[(buffer[i] ^ crc) & 0xff];
			}

		return crc;
	}

	private byte[] UInt64ToBigEndianBytes(UInt64 x)
	{
		return new byte[] {
			(byte)((x >> 56) & 0xff),
			(byte)((x >> 48) & 0xff),
			(byte)((x >> 40) & 0xff),
			(byte)((x >> 32) & 0xff),
			(byte)((x >> 24) & 0xff),
			(byte)((x >> 16) & 0xff),
			(byte)((x >> 8) & 0xff),
			(byte)(x & 0xff) };
	}
}

To use this or the CRC-32 class to compute the hash for a file simply:

Crc64 crc64 = new Crc64();
String hash = String.Empty;

using (FileStream fs = File.Open("c:\\myfile.txt", FileMode.Open))
	foreach (byte b in crc64.ComputeHash(fs)) hash += b.ToString("x2").ToLower();

Console.WriteLine("CRC-64 is {0}", hash);

Whilst writing this I considered if I should implement some more advanced hashing algorithms missing from .NET like RIPEMD320 only to stumble across The Legion of Bouncy Castles C# Cryptography APIs which also includes generating PKCS #12 files and a whole bunch of encryption algorithms (but nothing as weak as CRC-64 ;-)

[)amien

06
Nov

Using GUIDs as row identifiers

Wade Wright is preaching that IDs in a database should always be GUIDs and lists four reasons. I commented there with my opinions but it hasn't shown up - some people like to censor if you don't agree with them completely. My points addressing each of his four 'reasons' were:

  1. Avoid round-trips when creating new business objects
    I don't know about you but I don't populate my IDs until I persist and not on object creation so this reason is useless.
  2. Data merging is easy
    Yes, this is a good reason to use GUIDs if you know merging is likely to happen.
  3. Type/table ignorance
    Basically he says here that a foreign key reference might relate to a row in any table which breaks relational concepts big time.
  4. Some weird anecdote I don't quite get

He does acknowledge that querying the database by hand is a bit of a pain but underestimates the Guid/uniqueidentifier performance penalty in SQL Server especially with regards to INSERTs (might be able to optimize there by having .NET generate the GUID instead of SQL Server).

He also fails to consider how a page full of GUIDs will bloat out HTML page size especially if they end up used in a number of full drop-down SELECT boxes or collapsible JavaScript tree on a single page although deflate and gzip compression should take care of that if you've turned it on.

There are many valid scenarios for using GUIDs as unique identifiers but one size does not fit all using them without consideration will likely lead to somewhere bad ;-)

If you are using them and space is tight such as uncompressed HTML or the GET/POST size down you can write and parse the Guid as Base64 instead of hex format which cuts a Guid of 81187ecf-c452-4550-9ed2-8a51e3c46da1 (36 bytes) to z34YgVLEUEWe0opR48RtoQ== (22-24 bytes) which soon adds up. To do that in C# and .NET simply:

string base64 = Convert.ToBase64String(guid.ToByteArray());
Guid guid = new Guid(Convert.FromBase64String(base64));

For a further squeeze you could use ASCII85 encoding with Jeff Atwood's ASCII85 implementation in C#.

[)amien

04
Nov

Object Initializers in .NET 3.5

One compiler improvement in .NET 3.5 is the object initializers feature that lets you concisely set properties of an object as you create it.

If you've ever used VB you may well have found and enjoyed the with keyword to write code such as:

Dim myObj As MyClass
myObj = New MyClass()
With myObj
  .ProductCode = "ABC123"
  .Quantity = 5
  .Cost = 567.89
End With

This is more concise than writing myObj several times over, especially if setting a large number of properties, but as C# has no such keyword many people resorted to providing helpful constructors to facilitate code like:

MyClass myObj = new MyClass("ABC123", 5, 567.89);

If all three of these properties are essential then this makes for a sensible constructor however many classes have a number of properties that are optional and class designers struggle to determine whether to make constructors that merely cut-down on typing and which of the various combinations of optional properties might make sense in having their own constructor.

Invariably the combination you might want doesn't exist and if it does the chances of being able to understand which properties are being set from one of a number of constructors that take parameters of similar types is quite low unless you go and take a peek with the IntelliSense.

Using object initializers you can stick to creating constructors that reflect parameters necessary to ensure your object is in a valid state and forget about providing helpful ones for those optional parameters. In our example if we assume the ProductCode is essential and the others are optional we can write code like:

MyClass myObj = new MyClass("ABC123") { Quantity = 5, Cost = 567.89 };

Which is both concise and easy to understand. It also requires no work on the part of the class designer and therefore works with all your existing classes. You can also nest them to set properties that require more complex types such as:

MyClass myObj = new MyClass("ABC123") {
   Quantity = 5,
   Cost = 567.89,
   Category = new Category("A") { Description = "New machine" }
};

This feature is no use if your objects are immutable in which case constructors are your only friend.

[)amien