Often when .NET WinForms applications are created, developers do not consider the various deployment options available and panic when it comes time for deployment and default to using ClickOnce. This is not a good strategy as the architecture of the application is not well considered with this in mind and limits the deployment options.
If WinForms intranet applications are going to scale, the various deployment options must be considered and a well architecured application designed otherwise the code soon becomes an unmaintainable mash of spaghetti that does not scale well, is difficult to maintain, and the morale of your development team deteriorates rapidly. There is also an added benefit in being able to mix languages if assemblies are correctly architectured. In a future post, I’ll go into more detail on a good architecture for scalable WinForms applications that also connect to service applications either through WCF or standard web services.
In this article, I’ll be concentrating on No Touch Deployment (NTD) as an alternative to using ClickOnce.
I originally wrote this article back in March 2008 when considering the redesign of a large VB.NET application that had gotten out of hand. The developers wanted to write in C# but due to the poor design the application was compiled into a single exe for deployment which hindered starting to use C# on new code and because the exe had become so large, the load time was slow.
No Touch Deployment is a useful feature if you want to reduce the deployment maintenance of your Windows Forms applications, especially on intranet applications.
NTD works by using a very thin client application that loads a remote assembly using reflection.
The remote assembly is downloaded into the local assembly cache, and the each time the application is loaded the assembly cache is checked to see if the assembly has already been downloaded or if the version has changed.
Any assemblies that the downloaded assembly references are also downloaded in the same way, but there is no need to use reflection to download the depended assemblies – you just referenced them in the same way that you normally do.
Simple deployment – no need for packaging – no messy ClickOnce dialogs. (You may need to package the launcher only unless you have a deployment mechanism to get it onto the user’s desktops some other way)
A simple static thin client application is used to launch the application.
Assemblies are downloaded on an as needed bases, so if a user does not use part of an application, the depended assemblies are not downloaded, this makes it ideal for intranet environments, reducing network traffic.
Setup a small launcher project that will load the main assembly. The launcher should be specified as a Windows Application to prevent the console window from showing.
The launcher need only have one function:
The remote assembly can either be specified as a Windows Application (exe) or a Class Library (dll).
If it is specified as a Windows Application, it has the benefit of also being able to be started without using the launcher.
The remote assembly looks something like this:
You don’t need the Main() function is using a dll, but it doesn’t hurt to leave it there incase you change your mind later.
The remote assembly references its dependent assemblies in the same way as you would normally.
Debugging in Visual Studio
The remote assembly needs to have the bin folder set as a virtual directory within the local IIS to allow startup, or for local development simply use the file reference. VS2008 will happily step into the remotely loaded assembly. This will require the developer to setup this virtual folder.
Alternatively, make the remote project a Windows Application (exe), include a static main function as per the code above, and the set the remote project as the startup application. This will run the application without using the launcher.
Another alternative is to create a second launcher application that references the main dll directly and keep that for development purposes only, i.e. do not distribute this.
The application is launched in the internet zone, so the application does not have local permissions.
Under Vista the Microsoft .NET Security Warning is displayed as shown below:
If the application is hosted on Vista (typically in a development environment), the referenced DLL may fail to download but throw a BadImageFormatException in the call to Assembly.Loadfrom(), saying a manifest was expected.
Changing the code to download from a file reference proves the assembly is OK.
If this error occurs, make sure the web service is setup to allow static content. This is activated through Windows features as shown in the image below: