Walkthrough: Download assemblies on demand with the ClickOnce deployment API
Article
By default, all of the assemblies included in a ClickOnce application are downloaded when the application is first run. However, you may have parts of your application that are used by a small set of your users. In this case, you want to download an assembly only when you create one of its types. The following walkthrough demonstrates how to mark certain assemblies in your application as "optional", and how to download them by using classes in the System.Deployment.Application namespace when the common language runtime (CLR) demands them.
To get the public key token for the assembly, use the following command:
Windows Command Prompt
sn -T ClickOnceLibrary.dll
Create a new file using your text editor and enter the following code. This code creates a Windows Forms application that downloads the ClickOnceLibrary assembly when it is required.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using System.Deployment.Application;
using Microsoft.Samples.ClickOnceOnDemand;
namespaceClickOnceOnDemand
{
[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Unrestricted=true)]
publicclassForm1 : Form
{
// Maintain a dictionary mapping DLL names to download file groups. This is trivial for this sample,// but will be important in real-world applications where a feature is spread across multiple DLLs,// and you want to download all DLLs for that feature in one shot.
Dictionary<String, String> DllMapping = new Dictionary<String, String>();
publicstaticvoidMain()
{
Form1 NewForm = new Form1();
Application.Run(NewForm);
}
publicForm1()
{
// Configure form. this.Size = new Size(500, 200);
Button getAssemblyButton = new Button();
getAssemblyButton.Size = new Size(130, getAssemblyButton.Size.Height);
getAssemblyButton.Text = "Test Assembly";
getAssemblyButton.Location = new Point(50, 50);
this.Controls.Add(getAssemblyButton);
getAssemblyButton.Click += new EventHandler(getAssemblyButton_Click);
DllMapping["ClickOnceLibrary"] = "ClickOnceLibrary";
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
/*
* Use ClickOnce APIs to download the assembly on demand.
*/private Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly newAssembly = null;
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment deploy = ApplicationDeployment.CurrentDeployment;
// Get the DLL name from the Name argument.string[] nameParts = args.Name.Split(',');
string dllName = nameParts[0];
string downloadGroupName = DllMapping[dllName];
try
{
deploy.DownloadFileGroup(downloadGroupName);
}
catch (DeploymentException de)
{
MessageBox.Show("Downloading file group failed. Group name: " + downloadGroupName + "; DLL name: " + args.Name);
throw (de);
}
// Load the assembly.// Assembly.Load() doesn't work here, as the previous failure to load the assembly// is cached by the CLR. LoadFrom() is not recommended. Use LoadFile() instead.try
{
newAssembly = Assembly.LoadFile(Application.StartupPath + @"\" + dllName + ".dll," +
"Version=1.0.0.0, Culture=en, PublicKeyToken=03689116d3a4ae33");
}
catch (Exception e)
{
throw (e);
}
}
else
{
//Major error - not running under ClickOnce, but missing assembly. Don't know how to recover.throw (new Exception("Cannot load assemblies dynamically - application is not deployed using ClickOnce."));
}
return (newAssembly);
}
privatevoidgetAssemblyButton_Click(object sender, EventArgs e)
{
DynamicClass dc = new DynamicClass();
MessageBox.Show("Message: " + dc.Message);
}
}
}
VB
Imports System
Imports System.Windows.Forms
Imports System.Deployment.Application
Imports System.Drawing
Imports System.Reflection
Imports System.Collections.Generic
Imports Microsoft.Samples.ClickOnceOnDemand
Namespace Microsoft.Samples.ClickOnceOnDemand
<System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Unrestricted:=true)> _
Class Form1
Inherits Form
' Maintain a dictionary mapping DLL names to download file groups. This is trivial for this sample,' but will be important in real-world applications where a feature is spread across multiple DLLs,' and you want to download all DLLs for that feature in one shot. Dim DllMapping as Dictionary(OfString, String) = new Dictionary(ofString, String)()
PublicSubNew()
' Add button to form.Dim GetAssemblyButton AsNew Button()
GetAssemblyButton.Location = New Point(100, 100)
GetAssemblyButton.Text = "Get assembly on demand"AddHandler GetAssemblyButton.Click, AddressOf GetAssemblyButton_Click
Me.Controls.Add(GetAssemblyButton)
DllMapping("ClickOnceLibrary") = "ClickOnceLibrary"AddHandler AppDomain.CurrentDomain.AssemblyResolve, AddressOf CurrentDomain_AssemblyResolve
EndSub
<STAThread()> _
SharedSub Main()
Application.EnableVisualStyles()
Application.Run(New Form1())
EndSubPrivateFunction CurrentDomain_AssemblyResolve(ByVal sender AsObject, ByVal args As ResolveEventArgs) AsAssemblyIf ApplicationDeployment.IsNetworkDeployed ThenDim deploy As ApplicationDeployment = ApplicationDeployment.CurrentDeployment
' Get the DLL name from the Name argument.Dim nameParts() asString = args.Name.Split(",")
Dim dllName asString = nameParts(0)
Dim downloadGroupName asString = DllMapping(dllName)
Try
deploy.DownloadFileGroup(downloadGroupName)
Catch de As DeploymentException
EndTry' Load the assembly.Dim newAssembly AsAssembly = NothingTry
newAssembly = Assembly.LoadFile(Application.StartupPath & "\\" & dllName & ".dll," & _
"Version=1.0.0.0, Culture=en, PublicKeyToken=03689116d3a4ae33")
Catch ex As Exception
MessageBox.Show("Could not download assembly on demand.")
EndTry
CurrentDomain_AssemblyResolve = newAssembly
Else
CurrentDomain_AssemblyResolve = NothingEndIfEndFunctionPrivateSub GetAssemblyButton_Click(ByVal sender AsObject, ByVal e As EventArgs)
Dim ourClass AsNew DynamicClass()
MessageBox.Show("DynamicClass string is: " + ourClass.Message)
EndSubEndClassEndNamespace
Start your application deployed with ClickOnce from a Web browser by entering the URL to the deployment manifest. If you call your ClickOnce application ClickOnceOnDemand, and you upload it to the root directory of adatum.com, your URL would look like this:
Create a .NET project and learn to add packages and manage package dependencies in your project. Use the .NET Core CLI and NuGet registry to add libraries and tools to your C# applications through Visual Studio Code.