更新部署清单的ClickOnce应用程序编程导致缺少 元件,在4.0所需(Updating d

2019-07-30 02:15发布

我工作的自动化安装了.NET 4.0的ClickOnce的WPF应用程序,这需要在App.config文件中设置的几个项目。 我通过寻找我必须遵循使用特定步骤的棘手历程Mage.exe (即,更新和再签收的应用和部署清单),现在我想给它安装自动化。

我选择使用扩展指向.deploy以尽量减少问题的IIS / Internet Explorer安全机制,所以本质上的算法如下(根据在ClickOnce的(SAURABH巴蒂亚)签名和重新签名的清单使用法师一个ClickOnce WPF应用程序的更新配置或MageUI ,作为除其他主要来源):

  1. 转至\Application Files\App_%HighestVersion%\文件夹中
  2. 删除扩展指向.deploy为拥有它的文件
  3. 运行mage -u %app%.exe.manifest -cf cert.pfx
  4. 恢复扩展指向.deploy
  5. 运行mage -u %app%.application -appm %app%.exe.manifest -cf cert.pfx
  6. 副本%app%.application 2级了(到..\.. -部署根)

如果手工完成的作品完美。 我可以运行一个.cmd文件,定制环境细节(路径等),但后来我需要包括mage.exe的部署,以及微软是否允许我们这样做,对我来说是一个悬而未决的问题。 因此,我想执行的类似的操作Installer类:

X509Certificate2 ct = new X509Certificate2(sPathCert);

//  .. Remove .deploy extension (for files in the sPathApp folder).

sPathMft = Directory.GetFiles(sPathApp, "*.exe.manifest")[0];
ApplicationManifest am = ManifestReader.ReadManifest( "ApplicationManifest", sPathMft, false ) as ApplicationManifest;
if (am == null)
    throw new ArgumentNullException("AppManifest");
am.ResolveFiles();
am.UpdateFileInfo( );
ManifestWriter.WriteManifest(am, sPathMft);
SecurityUtilities.SignFile(ct, null, sPathMft);

//    .. Restore .deploy extensions to files touched above.

sPathMft = Directory.GetFiles(sPathApp, "*.application")[0];
DeployManifest dm = ManifestReader.ReadManifest("DeployManifest", sPathMft, false) as DeployManifest;
if (dm == null)
    throw new ArgumentNullException( "DplManifest" );
dm.ResolveFiles();
dm.UpdateFileInfo();
ManifestWriter.WriteManifest(dm, sPathMft);
SecurityUtilities.SignFile(ct, null, sPathMft);

File.Copy(sPathMft, sPathBin + "\\" + dm.AssemblyIdentity.Name, true);

现在,这里的起脚 。 一切步骤5的异常完美的作品当应用程序被下载到用户的计算机上有一个与部署清单的问题:

  • 部署清单是语义不合法。
  • 部署清单丢失<compatibleFrameworks>。

事实上,本节不再存在( 但它是在原有%的应用。应用%!)。 类似的结果被描述在ClickOnce的- .NET 4.0错误:“部署清单不是语义上有效的”和“部署清单丢失<compatibleFrameworks>” ,但是是不同的处理(的msbuild)的结果。 这部分是新的(要求)为4.0体现,所以我只能猜测是,不知何故,当ManifestWriter持续到磁盘的变化确实它在3.5时尚? 我三重检查,一个正确的库使用(C:\ Program Files文件(x86)的\参考大会\微软\ Framework.NETFramework \ V4.0 \ Microsoft.Build.Tasks.v4.0.dll)。 是什么赋予了?

代替回答的,到目前为止我试图手动添加缺少的部分:

dm.CompatibleFrameworks.Clear(); // Unnecessary as dm.CompatibleFrameworks.Count == 0 indeed!
CompatibleFramework cf = new CompatibleFramework();
cf.Version= "4.0";
cf.SupportedRuntime = "4.0.30319";
cf.Profile= "Client";
dm.CompatibleFrameworks.Add(cf);
cf = new CompatibleFramework();
cf.Version = "4.0";
cf.SupportedRuntime = "4.0.30319";
cf.Profile = "Full";
dm.CompatibleFrameworks.Add(cf);

但是,这并没有影响,无论在什么地方,我把这个代码,dm.ResolveFiles()之前,dm.UpdateFileInfo()ManifestWriter.WriteManifest(..)!

我的结果是类似的堆栈溢出问题MageUI.exe删除compatibleFrameworks元素为什么Mage.exe不会产生compatibleFrameworks属性?MageUI.exe不包括compatibleFrameworks元素 ,但我不使用mageuimage甚至msbuild根本!

这是怎么回事?

Answer 1:

理解了它自己。 罪魁祸首是ManifestReader.ReadManifest( “DeployManifest”,sPathMft, )。

MSDN说,[preserveStream参数]“指定是否对保存在输入流中所产生的清单对象的InputStream的属性。通过ManifestWriter用于重建未在对象表示所表示的输入。”

措辞不谈,设置真正是本身不够: dm.CompatibleFrameworks.Count仍然是0,但现在加入CompatibleFramework项目将有效果!

对于有人在同一条船上一样,我这样做之前dm.ResolveFiles( )

if(  dm.CompatibleFrameworks.Count <= 0  )
{
    CompatibleFramework cf= new CompatibleFramework( );
    cf.Profile= "Client";       cf.Version= "4.0";      cf.SupportedRuntime=    "4.0.30319";
    dm.CompatibleFrameworks.Add( cf );              //  cf= new CompatibleFramework( );
    cf.Profile= "Full";     //  cf.Version= "4.0";      cf.SupportedRuntime=    "4.0.30319";
    dm.CompatibleFrameworks.Add( cf );              /// no need for separate object
}

@davidair,感谢您的建议! 同意了,虽然我更喜欢用API对象(与XML)的工作。
另一种方法是调用mage (直接或从一个.cmd文件),因为它似乎我们被允许重新分配它。


我还增加了以下部分,它不会对问题本身产生影响,但可能是任何人都遵循同样的路径非常重要(/客户端部署的根,可定制):

dm.DeploymentUrl=   string.Format( "http://{0}/{1}/client/{1}.application",
                        Dns.GetHostName( ), Context.Parameters[ scTokVirtDir ] );
dm.UpdateMode=      UpdateMode.Background;
dm.UpdateUnit=      UpdateUnit.Weeks;
dm.UpdateInterval=  1;
dm.UpdateEnabled=   true;


Answer 2:

我还需要添加CompatibleFrameworks。 我也试着做添加这样的CompatibleFrameworks(不工作)

dm.CompatibleFrameworks.Add(...);

我的解决办法是设置:

dm.TargetFrameworkMoniker = ".NETFramework,Version=v4.0";                 

在此之后,清单生成是正确的。

要小心,如果你有WriteManifest之前设置TargetFrameworkMoniker的<compatibleFrameworks>两次,你的应用程序文件已损坏。 这是我对这个解决方案:

DeployManifest dm = ManifestReader.ReadManifest("DeployManifest", applicationFileName, false) as DeployManifest;
dm.ResolveFiles();
//doing stuff..
dm.UpdateFileInfo();
ManifestWriter.WriteManifest(dm, applicationFileName);
dm.TargetFrameworkMoniker = ".NETFramework,Version=v4.0";
ManifestWriter.WriteManifest(dm, applicationFileName);


文章来源: Updating deployment manifest for a ClickOnce application programmatically results in missing element, required in 4.0