Keeping Windows Applications Up-To-Date via Auto-Updates
As a developer of commercial Windows and .Net applications and components, one problem I’ve had to grapple with on many occasions is how to automatically distribute patches or updates for applications or components we sell. Our goal was to update-enable applications we develop, allowing them to poll for and, optionally, automatically apply designated patches or updates.
In this article, I outline some of the options for creating auto-update applications and describe, in detail, the approach we finally took.
Overview
Our solution needed to be easy to implement on the client
side, but also flexible enough to allow us to perform update-related activities that could potentially perform unusual tasks specific to the application. It should provide simple, ‘native’ support for typical update activities; like installing updated files or assemblies, adjusting registry entries, or launching a downloaded executable (It should support the ability to launch software installers built by Visual Studio or other installer creation tools). Ideally the solution would also support customized, application-specific tasks - starting or stopping services, for example. Also, it would need to be a component that we can easily embed in our end-user applications and utilities, although it would also be nice to be able to deploy the solution as
a stand-alone ‘agent’ which runs independently of our applications.
We
wanted our solution to be robust enough to allow us to customize the behavior
and UI of the update process with minimal effort. Some examples of customization features we were interested in
included:
- The ability to enable end-users of an application using this update component to do things like manually check for updates via a button or menu option
- Control over whether the update check, download, and application process happen transparently, or prompt the user first
- The ability to override UI elements like prompt and progress forms and indicators with customized versions providing custom look-and-feel
Since we
can’t predict where our applications (or applications incorporating our components) will be deployed, we want the communication between the client and the server to be over the HTTP protocol - ensuring maximum compatibility with secure, fire-walled environments. Furthermore, end-users of these update-enabled applications will essentially be ‘anonymous’ to us - we don’t necessarily know anything about the network environment where our app lives. The process should therefore be client-driven - the agent should poll for updates then request them if any are available.
Finally, the solutions needed to be relatively inexpensive.
To Build or not to Build
I began by looking at the commercial and open-source solutions. While a number of commercial products are available, I found that many of them tended to be strongly focused on managing the desktop in an Enterprise environment. Features like the ability to inventory the desktop, compliance and vulnerability
management, the ability to push software packages to named sets of machines, and robust reporting are all valuable for administrators of internal networks, but are overkill for our use-case. We just wanted a simple, embeddable agent
which polls for updates for the specific apps it’s embedded in.
There are some commercial solutions which are more focused on update-enabling specific apps, but they tend to be complicated to implement, not very customizable, not
embeddable, or not .NET-friendly. The commercial products also tend to be moderately to prohibitively expensive.
Open source solutions seem to be completely lacking for this use-case on the .NET platform. A notable exception is ’sample’ application available from Microsoft’s
.NET Framework Windows Forms website. The .Net Application Updater Component described there (and available for download) seemed to be closer to what I was looking for in terms
of a simple, lightweight component which can be embedded in an app. The component is dropped into your app, then polls a server for “manifests” available for that application and, if any are available, downloads the files described there. Unfortunately, the Updater Component is truly a sample application. Setup of the host is done manually, managing the host
manifests and file repository is entirely manual, and there is virtually no client-side support for user prompting, custom progress UI’s, etc. It is left to the developer to build out more robust features beyond simple update download. Update support is also limited exclusively to downloading files and assemblies. Still, the approach of using a lightweight client component that connects over HTTP via web services to perform simple update downloads was in line with the kind of solution I was looking for.
Ultimately, given the mismatch between commercial products and the features we required and the lack of robustness in free solutions, we chose to develop our own solution.
A Web-based Patch and Update Solution
Based on our requirements and the nature of our end-users, we determined that that our solution would have the following characteristics:
- A client-side component agent that would be both very simple to implement, but also provide access to more detailed API’s allowing the developer to have more control over the process with an investment greater implementation effort. It would support the ability to easily embed the agent component in update-enabled apps and we would also create a stand-alone agent - essentially an application using the component that runs in the SysTray. A config file would contain the identity of the update-enable application as well as settings controlling the agent behavior. These settings would also be exposed by the API, enabling the developer to control the agent behavior programmatically, if desired.
- The update framework would support the ability to deliver new or updated files (which could include assembly .dlls), the ability to create and update client registry entries, the ability to invoke a custom .Net Installer assembly, and the ability to download and invoke an executable. Furthermore, the framework would be extensible, allowing us to add new custom update actions in the future, if need be.
- We would create a web-based host application for managing the patches or updates available for a given application. Patches or updates would be published as “Manifests” describing the update contents, which would consist of “Manifest Items” of one of the aforementioned types. The client agent would communicate with this host via web services. The agent would poll the host for any Manifests appropriate to the application and current version it is associated with, then download the manifest contents, if desired - also via a web service. The administration application would be role-based, allowing the System Administrator to control the privileges of users defining Manifests in the system.
- The client would provide default UI elements, such as progress indicators and prompts before downloading or applying updates. It would be possible to disable individual and/or all prompts, enabling “silent mode”. The client would also support ability to override UI elements with customized versions, providing custom look-and-feel.
We also decided early on to design in some feature that would allow us to ‘productize’ our solution for sale to other developer’s who want to build similar auto-update capabilities into their apps without investing all the time and effort we did. These features included support for managing updates for multiple companies, tools for simplifying certain processes, installers for the client SDK and server web applications, extra effort in terms of the usability of the web-based hosting application, as well as two levels of administrative roles in that app. A full list of the features in the final product, EverUpate, can be foundhere.
Design Details
Host Application
We built the Host application using ASP.Net with a SQL Server database. The database schema consists of primarily of Company, Application, Manifest, ManifestItem, and User tables. A
Category table provides a folder-based organizational structure for Manifest Items. An intersection table representing a many-to-many relationship between ManifestItem and Categories provides the ability to define a Manifest Item once, but have it appear in multiple places in the Manifest Item organizational folders. Another intersection table between ManifestItem and
Manifest allows one item to be associated with multiple manifests. This is useful when some component is used in multiple different applications, for instance.
Fig 1 - General Table Schema
Application
Id
CompanyId
Name
Application
Id
CompanyId
Name
Category
Id
Name
ParentId
CompanyId
CategoryManifestItems
Id
CategorryId
ManifestItemId
Company
Id
Name
Manifest
Id
CompanyId
AppId
Version
FinalVersion
Name
RebootRequired
BackupFiles
ManifestItem
Id
CompanyId
Name
Action
Type
Sequence
Version
RegistryTarget
FileSize
FileName
TargetPath
Args
User
Id
CompanyId
UserId
Role
FirstName
LastName
ManifestItemManifest
Id
ManifestId
ManifestItemId
Rather than developing a lot of custom code for querying these tables and for persisting data to them, we leveraged an opensource ORM (Object Relational Mapping) package calledOJB.NET. ORM’s, like OJB.NET provide object-based access to relational databases, saving you from having to write a bunch of custom persistence code. While OJB.NET seems to be very much a grass-roots effort and is not as mature as similar packages that exist in the Java world (Hibernate, for example), it met our purposes well. I recommend you consider a package like this any time you’re considering developing a database persistence layer.
The manifest management console was constructed almost entirely in ASP.NET with C# under the covers. As I mentioned earlier, since we anticipated marketing our final product to other developers, we put a fair amount of effort into usability - we pursued a “console” look-and-feel, used folder metaphors where appropriate, and generally tried to “keep it simple”. I say the app was almost entirely ASP.NET because there is one notable component that is not. Namely, our file-upload widget. HTML forms do not support uploading multiple files very well - either requiring you to upload one file at a time, or rendering multiple file-type input controls, each with its own ‘browse’ button. Either way, uploading a lot of file, which is a fairly common task when your assembling a patch manifest, is a real chore. We therefore developed a Java applet for our file upload. The applet provides much better usability in terms of navigating your local hard drive and choosing multiple files for upload to the server. It is also well supported across various browsers. If you’re interested in seeing the management console, a demo can be accessed here.
Fig 2 - Manifest Management Console
Click to enlarge
Client Agent
The client was implemented as an assembly which is included in any application. Fig 3 illustrates, at a high level, how the client library functions. As of this writing, the developer of the update-enabled application creates an instance of the Controller object, then invokes ExecuteUpdate() (see the object model in Fig 4 for more detail of key classes). Controller, as well as many of the classes it interacts with, consults a Config file, mentioned earlier. Several of the Config properties define which implementations of the IManifestProcessor, IUpdateHandler, and IUpdateProcessor interfaces to invoke. This provide a point of extensibility for advanced developers, but default implementations are included, so normally no custom development is required if the standard update behavior is acceptable.
When ExecuteUpdate() is invoked, the client library contacts the host web services via the UpdateProxy class. It first calls IsUpdateAvailable() then, if there are updates for the Application/Version reported, it calls GetUpdateList() to retrieve a list of appropriate Manifests. Finally, the file contents of each Manifest are downloaded via GetManifestItemFiles() and then the MasterInstaller is invoked for each Manifest. Depending on other Config settings, the end-user may be prompted at various points during this process, or some or all of the process may happen transparently. MasterInstaller creates instances of the four specific installer classes, one for each ManifestItem entry. File installer manages placing files (including assemblies and locked files) on the file system, RegistryInstaller supports the creation or update of registry entries, and RunInstaller supports running a downloaded batch or executable file.
The download of the files associated with a manifest is performed by the GetManifestItemFile web service operation. Since the files in a manifest are frequently binary and could be quite large, the underlying SOAP request needs to support large binary file transfers. We leveraged the DIME support provided by Microsoft’s Web Services Enhancements 2.0 (WSE 2.0). This requires WSE 2.0 to be installed on both the client and server, but allowed us to return large binary object by simply constructing DimeAttachments and attaching them to the response SoapContext. Since Microsoft provides a free runtime installare for WSE 2.0, we simply make it a prerequisite in our agent setup program and refer the end user to the Microsoft site if it isn’t detected at install time.
Fig 3 - Client Agent Block Diagram
Click to enlarge
Of course, this has been a brief description of a fairly complex process. The process, and the details of implementing custom functionality or UI elements via the supported extensibility points, is described in much more detail in the EverUpdate Client Agent Developers Guide.
Fig 4 - Client Agent Object Model
Click to enlarge
Conclusion
While there are a number of products out there for patch management, we felt like a simple solution for update-enabling .NET applications with minimal effort was missing. The solution we developed meets our requirements in terms of the kind of updates we want to be able to perform, while requiring only a couple lines of code at the minimum, without sacrificing flexibility. You may find, as I did, that other options on the market don’t fit the bill. If, however, your requirements are similar to ours, you may want to consider taking a closer look at the product of our efforts to address auto-update of .NET end-user application.
Source: High Quality Article Database - 365articles.com
Comments (0)