Wednesday, August 12, 2009

MSI Package Uninstall Issue

So what happens, you write some C# code to go with your WIX installer. The C# code only runs on uninstallation. But ... during development you write some dodgy code, it causes an exception which makes the uninstallation fail.

Take a look here,

http://blogs.msdn.com/astebner/archive/2005/12/24/507294.aspx

And here,

http://www.advancedinstaller.com/user-guide/qa-forced-uninstall.html

I found that msizap didn't work for me, but what did was going to the directory '%windir%\installer' and searching for the most recent file, editing it with orca, and removing the custom action causing a problem did the trick nicely.

More on WIX

Since my last blog post I have found a lot more out about WIX which is worth noting. It is pretty easy to add a custom action like this,


The custom actions can also be written in C# by selecting 'new project' in visual studio and selecting 'C# custom action project'.

Here is a bit more info,


Here is some more about dealing with databases from WIX,


Later on I will try and give some more specific examples from the WIX package I am creating. It is pretty complicated though so it is hard to know where to start.

Tuesday, August 11, 2009

WIX Installing Database

WIX is very powerful, but can be quite fiddly to get running.

Take a look at this if you are installing a database and want to select the database server and credentials,


Also look at the WIX manual,


Once you have done the code to select the database server and credentials you can put that connection string into an XML file using code like this,

Monday, August 10, 2009

MD5 Encryption

A good link to do with MD5 encryption,


Scroll down to this too,

string hashedPass = MD5(aComplicatedSaltString + password);

Which is a comment someone made about adding in extra, not just the password, perhaps a user name too. This will make the string more complicated, and thus add a bit more security.

I saw another site once which I cannot find any more. It mentioned about creating what I believe was basically a salt and making that salt a random guid. The random guid is stored in the database in a separate field.

What was the purpose of this? That particular example was looking at a database which has a lot of similar rows. If you saw the rows in the database you would be able to see which fields were the same between rows because the hash values would match. If you add in a salt the data could be the same between rows, but their hash values would be different.

Here is similar code,


You can also use AES to hash information into product keys,

Insert Vs Update in a DB

I have come across this problem a lot with my database coding. We have some data to insert into the database. Depending on whether the data is new or existing will determine whether we do an insert or an update statement on the database.

I find that this solves the problem very nicely,

if exists(select * from Table where key = 'rowId1')
begin
update Table set datavalue = 'newValue', datavalue1 = 'newValue' where key = 'rowId1'
end
else
begin
insert into Table values ('newValue','newValue', etc, etc)
end

Simple and sweet.

ntext Database Type

The ntext database type is a unicode variable length data type in SQL server. SQL server profiler creates these fields if you save a profile to a trace table.

If we try to filter one of these trace tables like this,

select * from TraceTable where TextData like '%value%'

That is fine, but if we try to do this,

select * from TraceTable where TextData = 'value'

We get an error like this,

The data types ntext and varchar are incompatible in the equal to operator.

The solution is this,

select * from TraceTable where cast(textdata as varchar(100)) = 'value'

Thursday, August 6, 2009

Dealing with UAC

What happens if your application wants to update itself, or change files which UAC will not allow you to update without elevation. The solution is to not elevate your whole application. This would defeat the purpose of UAC in the first place.

One solution is to create a new project in VS, which might be a console app that you run invisibly for instance. The console app will do some file copying or whatever else needs UAC elevation and that is all. Right click the new UAC project you have created and add an 'application manifest file'.

Make sure this is in the manifest file,

<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>

And you will be away. So back to your unelevated program, calling this console app from your unelevated code can be done like this. What this will do when you call process.Start() is prompt for UAC elevation,

Process process = new Process();
process.StartInfo.CreateNoWindow = true;
process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
process.Exited += new EventHandler(process_Exited);

I have left most of it out, but the important thing there is that I have said it should have no window, and the style should be hidden. I have also defined an exit event so that I can pick up when the UAC app has finished.

WPF and MVVM

Just a note really, here is MVVM explained,


I have implemented something very similar to MVVM, kind of a half MVVM. What mine was missing was commands. The VM should have commands so that these commands can be used from XAML. This will reduce your code behind.

The Acid Test Part #2

Over a year ago I tested my browsers with the acid tests. I wonder whether there has been any improvement? Since then we have the addition of the chrome browser as well.


100/100 - Chrome (I got a message saying the link test failed)
72/100 - Firefox 3.5
20/100 - IE8 (I also got the message saying that the link test failed)

So does that mean IE8 is still not up to scratch? Or is my IE8 running in some funny mode that has stuffed up the results.

IE8 gets acid 2 100% correct,


On mine the nose was out by probably only 1 pixel on chrome and firefox 3.5 - extremely close

Wednesday, August 5, 2009

Bulk Inserting Into Your Database

So you have a list of domain objects you want to bang into the database really quickly. You don't want to change anything about the items, and the properties on the domain object map one to one to database field names.

There is a way to do it really fast using the SqlBulkCopy class - especially if you are inserting hundreds or thousands of rows at one time. Here is some code that does it for you,

public class BulkInserter
{
private object lockObject = new object();

public void BulkInsertRows<T>(List<T> insertionList, string connectionString,
string databaseTableName)
{
lock (lockObject)
{
DataTable dt = ConvertTo<T>(insertionList);

using (SqlBulkCopy bulkCopy = new SqlBulkCopy(connectionString,
SqlBulkCopyOptions.Default))
{
bulkCopy.BulkCopyTimeout = 60;
bulkCopy.DestinationTableName = databaseTableName;
bulkCopy.WriteToServer(dt);
}
}
}

private DataTable ConvertTo<T>(IList<T> list)
{
DataTable table = CreateTable<T>();
Type entityType = typeof(T);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);

foreach (T item in list)
{
DataRow row = table.NewRow();

foreach (PropertyDescriptor prop in properties)
{
row[prop.Name] = prop.GetValue(item);
}

table.Rows.Add(row);
}

return table;
}

private DataTable CreateTable<T>()
{
Type entityType = typeof(T);
DataTable table = new DataTable(entityType.Name);
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(entityType);

foreach (PropertyDescriptor prop in properties)
{
table.Columns.Add(prop.Name, prop.PropertyType);
}

return table;
}
}

So what is the code doing? You pass in a list of domain objects, and the CreateTable and ConvertTo methods convert this list into a DataTable. This DataTable is what the SqlBulkCopy class uses to do the bulk insert.

The first method has a parameter databaseTableName. In hind site there is probably a better way to do that, perhaps typeof(T).Name or something similar.

Unit Tests That Involve Dates

How do you unit test some code that uses DateTime.Now? What if you want to move the day one week into the future and test that your logic works as expected.

There are a couple of options. Instead of using DateTime.Now straight in your code you can pass in a parameter to your method which is the date time that you want to use in your logic. This would mean when you call this method from a unit test you could pass in any date you want. The normal code will still just use DateTime.Now though. This is a bit messy but in some instances this is not too bad.

The other option is to create a static class like this,

public static class SystemTime
{
public static Func Now = () => DateTime.Now;
}

This means you can replace the DateTime.Now calls in your code to SystemTime.Now(). This will default to being the equivalent of DateTime.Now,

SystemTime.Now()

In your unit test you can move the time on by five minutes like this,

SystemTime.Now = () => DateTime.Now.AddMinutes(5);

And then continue to unit test the code as though we are five minutes in the future.