惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

H
Help Net Security
博客园 - Franky
GbyAI
GbyAI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
爱范儿
爱范儿
IT之家
IT之家
酷 壳 – CoolShell
酷 壳 – CoolShell
aimingoo的专栏
aimingoo的专栏
博客园_首页
MongoDB | Blog
MongoDB | Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Recent Announcements
Recent Announcements
Scott Helme
Scott Helme
有赞技术团队
有赞技术团队
M
MIT News - Artificial intelligence
C
CERT Recently Published Vulnerability Notes
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Jina AI
Jina AI
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
L
LangChain Blog
L
LINUX DO - 最新话题
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Hacker News: Front Page
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
G
Google Developers Blog
Google DeepMind News
Google DeepMind News
AI
AI
T
Troy Hunt's Blog
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Vercel News
Vercel News
Microsoft Security Blog
Microsoft Security Blog
罗磊的独立博客
S
Secure Thoughts
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
人人都是产品经理
人人都是产品经理
Blog — PlanetScale
Blog — PlanetScale
博客园 - 司徒正美
Apple Machine Learning Research
Apple Machine Learning Research
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 三生石上(FineUI控件)
S
Security @ Cisco Blogs
Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
Attack and Defense Labs
Attack and Defense Labs

博客园 - 沉默天蝎的学习汇集

由浅入深:Python 中如何实现自动导入缺失的库?(转) itchat初步解读登录(转) 转:【开源必备】常用git命令 2.转发。基于itchat的微信消息同步机器人 1、初学探讨PYTHON的itchat和wxpy两库 学习git 新手。这个写的不错 转:android学习帖子大汇集 bat 切换单位和宿舍IP地址(转) (转)C#2Android [转]HTTP调试工具:Fiddler的使用方法介绍 转帖:麻雀虽小,五脏俱全-C# 创建windows服务、socket通讯实例 C# WinForm开发系列 - 文章索引 (转自peterzb) 非常经典的网络蜘蛛示例,我是转载在这里的 - 沉默天蝎的学习汇集 - 博客园 (转)三种模拟自动登录和提交POST信息的实现方法 (转自Timon's wang blogs)C#实现web信息自动抓取 (转)c#操作注册表大全 - 沉默天蝎的学习汇集 - 博客园 sql2005安装产生问题解决汇集 (转自斯克迪亚的博客)学柯南,用电脑拨电话! 看完最新的柯南后很好奇,正好有人写到了就转来了 转贴:VS2008如何转换为VS2005
使用VS2005的 ClickOnce 技术实现按需下载组件
沉默天蝎的学习汇集 · 2010-08-12 · via 博客园 - 沉默天蝎的学习汇集

默认情况下,首次运行 ClickOnce 应用程序时,会下载该应用程序中包含的所有程序集。但是一些特殊的场景我们可能不希望它这么干,而是希望按照一定规测或者需要用到某个组件的时候再下载。

比如我们可能会有下面一些应用场景的需求:

1、我开发的这个客户端程序是要收费的。但是免费用户也可以使用部分功能。我在技术实现上把收费用户使用的功能封装到了A.dll 组件了,我希望免费用户根本无法获得A.dll,只有收费用户才能获得A.dll,并加载A.dll中的收费功能。

2、我整个应用程序非常大,我不希望我每次更新,用户都需要把所有应用程序都下载下来,用户应该只需要下载他用到的功能组件。

下面我们就来实现一个简单的按需下载的例子,我们完全可以在这个例子基础上,实现上述提到的应用场景1。

演示步骤:

一、新建一个 类库 Project

定义类库输出应用程序名为:OnDemandAssembly,即这个类库编译后产生的文件名为 OnDemandAssembly.dll

这个类库中有如下代码,我们用这段代码来模拟上面提到场景中的一些需要按需加载的功能或者是收费的功能,我们将在主程序中调用这个功能:

using System;

namespace OnDemandAssembly
{
    public class DynamicClass
    {
        public string Message
        {
            get
            {
                return "郭红俊测试ClickOnce按需加载功能。";
            }
        }

    }
}

二、新建一个 Window 应用程序

我们将在这个Window 应用程序中加载上述类库。

为了便于我们演示这个程序,请确保这个Window程序具备以下功能:

1、有一个 textbox 控件,这个控件在 Window 的OnLoad 事件中,把应用程序的目录显示在这里,方便我们去监控是否上述 OnDemandAssembly.dll 组件被加载了。

代码如下:

private void Form1_Load(object sender, EventArgs e)
{
    this.textBox1.Text = Application.StartupPath;
}

2、由一个  Button  按钮,点击这个按钮后,我们把 OnDemandAssembly.dll 组件中的 Message 信息显示出来,代码如下:

private void button1_Click(object sender, EventArgs e)
{
    DynamicClass o = new DynamicClass();
    MessageBox.Show(o.Message);
}

Window程序关于ClickOnce设置比较特殊的地方:

我们来配置ClickOnce发布的一些特殊参数,确保可以按需下载需要的组件

本文中没有详细描述ClickOnce设置的各个步骤和参数,如果你对ClickOnce不是很熟悉,建议你首先看一些ClickOnce的入门文章再来看本文。

比如:http://blog.oracle.com.cn/155011/viewspace_3603.html 这里提供的ClickOnce 文章(这里是提供了一个word压缩文件下载,文章在压缩的Word文件中)

选择我们的Window程序,在右键菜单中选择属性,在属性页中选择发布(Publish)标签页。

然后点击 Application File 按钮,我们来设置,需要发布的文件。如下图:

VS2005发布设置中,选择需要发布那些文件的按钮位置

上述按钮打开的窗口如下:

我们在打开的窗口中,设置 OnDemandAssembly.dll 文件的 发布状态为 Include,

并在 Download Group 中为OnDemandAssembly.dll 文件新建的一个下载组,我们这里把这个新的下载组命名为 DemandAssembly01 。

说明:

默认情况下,我们用ClickOnce 第一次安装,或者升级程序的时候,系统只下载 Required 组的文件,其他组的文件系统不下载,需要我们自己编码来下载。

其他ClickOnce的设置跟我们平常使用的时候一样来设置。本文忽略这部分。

我们这时候发布这个程序,我们下载安装后,就会发现OnDemandAssembly.dll 文件不在安装目录下,点击这个程序的按钮,就会报异常,找不到需要的应用程序集

OnDemandAssembly.dll 组件。

下面我们来编码实现,如果应用程序找不到 OnDemandAssembly.dll 组件,就从网上下载这个组件的功能

1、窗口的构造函数中增加 AssemblyResolve 事件的处理逻辑

public Form1()
{
    InitializeComponent();

    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{

}

说明:AppDomain.AssemblyResolve 事件 在对程序集的解析失败时发生。

2、下面我们编码实现 AssemblyResolve  事件的处理逻辑

using System.Reflection;
using System.Deployment.Application;

// 如果我们有多个文件都需要按需下载的话,每个文件影射到那个下载分组,就是这个实体来记录的

Dictionary<String, String> DllMapping = new Dictionary<String, String>();

public Form1()
{
    InitializeComponent();
    DllMapping["OnDemandAssembly"] = "DemandAssembly01";
    AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}

Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
    Assembly newAssembly = null;

    // 是 ClickOnce 部署方式
    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");
        }
        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);
}

一些问题说明:

Q:上述代码中,如果我们这个组件OnDemandAssembly.dll 有最新版本了,并且发布了,但是客户端还是一个老的版本的话,这个逻辑我们没有处理呀?

A:问题这个问题,就是代表你对 ClickOnce 的原理还是不懂,OnDemandAssembly.dll 有最新版本,那你就必须再重新发布一个版本的ClickOnce代码,这时候发布的版本号就不一样了。客户端下不同版本号的ClickOnce 程序是存在不同目录下的(当然服务器也是一样)。

系统检查到你的新版本程序发布后,会为新的版本号建立目录,这个目录下如果你没有用过OnDemandAssembly.dll 的功能,是不会有OnDemandAssembly.dll 组件的,继而上述问题是可以不用考虑的。