Mon, 19 Dec 2005

ClickOnce Always Updates All Files!

Arrgh!

Microsoft's ClickOnce is supposed to make deployment easy--and one of the things it does is that when the application is updated, it is only supposed to transfer those DLL files that have changed. Unfortunately, this isn't working for me: ClickOnce is always updating the entire application.

I found out from a post on MSDN Forums that ClickOnce doesn't use the assembly version numbers to determine what has changed. Instead, it uses a hash of the assembly file contents.

This seems reasonable, because a developer may screw up and forget to increment assembly version numbers before doing a publish. Reasonable, until you do some poking around and realize that every time you publish the app (in Visual C# 2005 Express Edition, at the very least) all of the assemblies are rebuilt, whether you have changed the code or not, and the rebuild causes the files to change! ARRGH!

You can see this from the following console session:

-bash-2.05b$ hexdump -C Solve_0_3_0_0/Freestyle.Solve.AppConfig.dll.deploy  > v0.txt
-bash-2.05b$ hexdump -C Solve_0_3_0_1/Freestyle.Solve.AppConfig.dll.deploy  > v1.txt
-bash-2.05b$ diff v0.txt v1.txt
9c9
< 00000080  50 45 00 00 4c 01 03 00  98 61 a7 43 00 00 00 00  |PE..L....a.C....|
---
> 00000080  50 45 00 00 4c 01 03 00  5c 63 a7 43 00 00 00 00  |PE..L...\c.C....|
539,541c539,541
< 00002f90  73 3e 7b 46 44 36 36 43  44 31 38 2d 41 45 45 39  |s>{FD66CD18-AEE9|
< 00002fa0  2d 34 43 38 43 2d 39 33  42 38 2d 38 33 42 33 30  |-4C8C-93B8-83B30|
< 00002fb0  31 44 44 37 32 43 39 7d  00 43 6f 6d 70 69 6c 65  |1DD72C9}.Compile|
---
> 00002f90  73 3e 7b 44 43 33 37 45  36 32 34 2d 44 36 46 31  |s>{DC37E624-D6F1|
> 00002fa0  2d 34 30 36 44 2d 41 32  38 45 2d 35 36 33 46 36  |-406D-A28E-563F6|
> 00002fb0  31 36 30 44 37 32 44 7d  00 43 6f 6d 70 69 6c 65  |160D72D}.Compile|
1130,1131c1130,1131
< 00005480  00 79 00 4e 00 61 00 6d  00 65 00 00 18 cd 66 fd  |.y.N.a.m.e....f.|
< 00005490  e9 ae 8c 4c 93 b8 83 b3  01 dd 72 c9 00 08 b7 7a  |...L......r....z|
---
> 00005480  00 79 00 4e 00 61 00 6d  00 65 00 00 24 e6 37 dc  |.y.N.a.m.e..$.7.|
> 00005490  f1 d6 6d 40 a2 8e 56 3f  61 60 d7 2d 00 08 b7 7a  |..m@..V?a`.-...z|
-bash-2.05b$

I used ildasm to look at my assemblies. The first difference is in the "Time-date stamp". Okay, that makes sense enough.

The second difference has to do with some sort of private class that is being created because I'm using a static array initializer. I guess it uses a GUID to guarantee that its custom name won't conflict with anything that gets used in my program.

The third difference is the pure hex representation of the GUID.

So, how can this be fixed? I've looked for an option in Visual C# 2005 Express to only rebuild changed source files when a publish is done, but I haven't found anything. So, I'm left with two possible solutions:

1) Do the publish manually, using the commandline tools.

2) Write a program to fix up a ClickOnce publishing folder after a publish is done, and correct entries in the manifest file. I could compare assembly versions instead of file hashes. The only problem will be ensuring that the ClickOnce manifest files maintain cryptographic integrity (I'll probably have to re-sign them, *bleh*)

posted at: 22:01 | path: / | permanent link to this entry