2010-02-22 5 views
6

J'ai un fichier de configuration qui doit être modifié serveur par serveur, de sorte qu'une fois qu'un logiciel est installé sur le serveur, le fichier de configuration d'un programme d'installation client est configuré pour correspondre au serveur paramètres, puis copiés dans un dossier public sur le Web pour le déploiement. Depuis que je change le fichier de configuration, je dois aussi reconstruire les fichiers * .manifest et * .application, et si je comprends bien, ma seule vraie option pour cela est d'utiliser Mage.exe à partir du SDK Win7. . Pour corriger le fichier * .manifest avec le hachage approprié à partir du fichier de configuration modifié, je lance:Problèmes de déploiement Mage.exe

mage -nouvelle application -fd -ToFile "\ Application Files" \ Application Files \ < appName> _1_0_0_0" .. \ _1_0_0_0 \ < appName> exe.manifest » -Name "< appName>" -Version "1.0.0.0" -CertFile "key.pfx" -password "< mot de passe>"

puis, pour fixer le * .application fichier avec le hachage approprié du fichier * .manifest modifié, je cours:

mage -new Déploiement -I t -t "< appName> .application" -v "1.0.0.0" -appManifest ". \ Fichiers d'application \ < appName> _1_0_0_0 \ < appName> .exe.manifest "-pu" http: // < adresse_hôte>/< path>/Fichiers d'application/< appName> _1_0_0_0/< appName> .exe.manifest "-CertFile" key.pfx "-password" "

Maintenant, tout cela fonctionne, et je reçois le message que les fichiers ont été signés avec succès. Lorsque je tente d'installer l'application cliente cependant, il est évident que quelque chose a mal tourné quand je reçois un journal d'erreur avec le message:

+ Deployment manifest is not semantically valid. 
+ Deployment manifest requires <deployment> section. 

En regardant le fichier * .Application, il contient des informations supplémentaires sous la noeud « de déploiement », que le même fichier directement à partir de la fonction de publication de VS2008 n'a pas:

<deployment install="true"> 
    <subscription> 
    <update> 
     <expiration maximumAge="0" unit="days" /> 
    </update> 
    </subscription> 
    <deploymentProvider codebase="http://<hostaddress>/<path>/Application Files/<appName>_1_0_0_0/<appName>.exe.manifest" /> 
</deployment> 

le VS2008 publier version dispose simplement:

<deployment install="true" /> 

Lorsque Je supprime les informations supplémentaires et définit le nœud de déploiement sur un nœud à terminaison automatique, puis re-signe le fichier, tout fonctionne comme prévu.

Est-ce un problème connu et existe-t-il un moyen de faire en sorte que Mage crée le fichier sans les informations supplémentaires dans le noeud de déploiement afin qu'il fonctionne correctement?

EDIT: En tant que solution temporaire, je charge les fichiers dans un XmlDocument et les modifie pour les adapter, puis les signer à nouveau. En outre, je suis maintenant confronté au problème d'être encore incapable de déterminer comment ajouter une icône au déploiement, de sorte que l'élément de menu Démarrer obtient une icône autre que l'icône générique.

+0

J'ai un cas d'utilisation très similaire à des problèmes similaires. Je répondrai si je trouve une solution. –

+0

il suffit d'utiliser le drapeau -appc sur mage –

+0

Nathan, consultez ma réponse et voir si cela vous aide. L'utilisation de Mage.exe devrait fonctionner correctement pour vous. –

Répondre

2

Voici ma mise en œuvre. J'ai passé beaucoup de temps sur ce petit bout de code, et je n'ai toujours pas trouvé toutes les bonnes options pour que Mage gère toute la génération du fichier .application sans intervention. Je vais dire qu'il y a probablement beaucoup d'optimisations à apporter à ce code. Cependant, cela peut toujours être utilisé comme un tremplin pour aider quelqu'un. Pour que la méthode suivante fonctionne, vous devez la déployer au moins une fois à partir de ClickOnce dans VS, puis conserver le fichier .application de ce déploiement. Vous DEVEZ supprimer les fichiers .application et .manifest dans le dossier de déploiement.

Après que je l'ai déplacé tous les fichiers d'application Config.Instance.ServerSettings.ClientLocation + "<AppName>_<version>":

DirectoryInfo filedir = new DirectoryInfo(Config.Instance.ServerSettings.ClientLocation); 

if (filedir.Exists) 
{ 
    FileInfo[] files = filedir.GetFiles(); 

    // Find the current .application file. 
    FileInfo appinfo = null; 
    foreach (FileInfo fi in files) 
    { 
     if (fi.Name == "<AppName>.application") 
     { 
      appinfo = fi; 
      break; 
     } 
    } 

    if (appinfo != null) 
    { 
     XmlDocument applocinfo = new XmlDocument(); 
     applocinfo.Load(appinfo.FullName); 

     // Get the location of the files from the .application file. 
     string codebase = applocinfo["asmv1:assembly"]["dependency"]["dependentAssembly"].Attributes["codebase"].Value.Replace("AppName.exe.manifest", ""); 

     XmlDocument xDoc = new XmlDocument(); 
     xDoc.Load(Path.Combine(Path.Combine(filedir.FullName, codebase), "AppName.exe.config")); 

     foreach (XmlNode xn in xDoc["configuration"]["appSettings"].ChildNodes) 
     { 
      if (xn.Attributes != null && xn.Attributes["key"] != null && xn.Attributes["key"].Value == "Clnt_Host") 
      { 
       // Here is where I'm modifying my config file, the whole purpose in this wretched deployment process. 
       xn.Attributes["value"].Value = Config.Instance.ClientSettings.Host; 
       break; 
      } 
     } 

     xDoc.Save(Path.Combine(Path.Combine(filedir.FullName, codebase), "<AppName>.exe.config")); 

     Process p = new Process(); 
     p.StartInfo = new ProcessStartInfo(Path.Combine(filedir.FullName, "Mage.exe")); 
     p.StartInfo.WorkingDirectory = filedir.FullName; 

     FileInfo fi = new FileInfo(Path.Combine(Path.Combine(filedir.FullName, codebase.TrimStart('.')), "<AppName>.exe.manifest")); 
     if (fi.Exists) 
      fi.Delete(); 

     // Write a new .manifest file as an Application file. (-new Application -ToFile ".\codebase\<AppName.exe.manifest") 
     // Include the files from the codebase directory in the manifest (-fd ".\codebase\") 
     // Give the application a name to use in the start menu (-name "<AppName>") 
     // Assign a version number to the deployment (-Version "<version>") 
     // Give the application an icon to use in the start menu (-IconFile "64x64.ico") 
     // Sign the manifest (-CertFile "<KeyName>.pfx -Password <password>) 
     p.StartInfo.Arguments = "-new Application -fd \".\\" + codebase.TrimEnd('\\') + "\" -ToFile \".\\" + Path.Combine(codebase, "<AppName>.exe.manifest") + "\" -Name \"<AppName>\" -Version \"" + codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\') + "\" -CertFile \"<KeyName>.pfx\" -Password <Password> -IconFile \"64x64.ico\""; 

     while (p.StartInfo.Arguments.Contains(".\\.\\")) 
      p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\"); 

     Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information); 

     p.Start(); 

     while (!p.HasExited) 
     { 
      Thread.Sleep(100); 
     } 

     // Make a new deployment manifest (-new Deployment -t "<AppName>.application") 
     // Make the application available offline (-I t) 
     // Use the files from the .manifest we just made (-AppManifest ".\codebase\<AppName>.exe.manifest") 
     p.StartInfo.Arguments = "-new Deployment -I t -t \"<AppName>.application\" -v \"" + codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\') + "\" -AppManifest \".\\" + codebase + "<AppName>.exe.manifest\" -pu \"http://" + Config.Instance.ClientSettings.Host + "/client/" + codebase.Replace('\\', '/') + "<AppName>.exe.manifest\""; 

        while (p.StartInfo.Arguments.Contains(".\\.\\")) 
      p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\"); 

     Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information); 

     p.Start(); 

     while (!p.HasExited) 
     { 
      Thread.Sleep(100); 
     } 

     xDoc = new XmlDocument(); 
     xDoc.Load(Path.Combine(filedir.FullName, "<AppName>.application")); 

     // Add to the Deployment manifest (.application) to make the application 
     // have a minimum required version of the current version,and makes a 
     // subscription so that the application will always check for updates before 
     // running. 
     if (xDoc["asmv1:assembly"]["deployment"]["subscription"] != null) 
     { 
      xDoc["asmv1:assembly"]["deployment"].RemoveChild(xDoc["asmv1:assembly"]["deployment"]["subscription"]); 
      xDoc["asmv1:assembly"]["deployment"].RemoveChild(xDoc["asmv1:assembly"]["deployment"]["deploymentProvider"]); 
      XmlAttribute node = xDoc.CreateAttribute("minimumRequiredVersion"); 
      node.Value = codebase.Substring(codebase.IndexOf('_') + 1, codebase.Length - (codebase.IndexOf('_') + 1)).Replace('_', '.').TrimEnd('\\'); 
      xDoc["asmv1:assembly"]["deployment"].Attributes.Append(node); 

      xDoc["asmv1:assembly"]["deployment"].InnerXml = "<subscription><update><beforeApplicationStartup /></update></subscription>"; 
     } 

     xDoc.Save(Path.Combine(filedir.FullName, "<AppName>.application")); 

     // Sign the deployment manifest (.application) (-Sign "\<AppName>.application" -CertFile "<AppName>.key" -Password <password> 
     p.StartInfo.Arguments = "-Sign \"<AppName>.application\" -CertFile \"<AppName>.pfx\" -Password <password>"; 

     while (p.StartInfo.Arguments.Contains(".\\.\\")) 
      p.StartInfo.Arguments = p.StartInfo.Arguments.Replace(".\\.\\", ".\\"); 

     Logger.Instance.LogInfo("Starting application: " + p.StartInfo.FileName + "\n\tWith arguments: " + p.StartInfo.Arguments, Logger.InfoType.Information); 

     p.Start(); 

     while (!p.HasExited) 
     { 
      Thread.Sleep(100); 
     } 
    } 
} 
+0

+1 pour "misérable". – Tim

1

Si votre objectif est de modifier votre manifeste d'application entre les environnements Je ne sais pas pourquoi vous créez un nouveau. Il suffit de modifier votre actuel. Je poste un script PowerShell qui fait ce dont vous avez besoin et plus ... Dans mon cas, j'ai un programme d'amorçage, mais le code dont vous avez besoin est vers le bas. Pour le programme d'amorçage de l'installation, vous ne pouvez pas démissionner d'un programme d'amorçage signé. J'ai donc dû trouver une DLL tierce pour l'annuler. (Delcert) http://forum.xda-developers.com/showthread.php?t=416175 J'ai que la mère dans le contrôle de la source dans le cas où il disparaît de la web :)

une jours

Trouvez la section #Begin Resigning various Manifests

$root = "$PSScriptRoot" 
$ToolsPath = "C:\Tools" 
$CertFile = $ToolsPath + "\my cert.pfx" 
$CertPassword = "wouldn't you like to know" 

#Update the setup.exe bootstrappers update url 
Start-Process "$PSScriptRoot\setup.exe" -ArgumentList "-url=`"$ClickOnceUpdateUrl`"" -Wait 

#The bootstrappers signature is now invalid since we updated the url 
#We need to remove the old signature 
Start-Process 'C:\Tools\delcert.exe' -ArgumentList "`"$root\setup.exe`"" -Wait 

Write-Host "$root [writeline]" 
#Resign with signtool 
Invoke-Expression 'C:\Tools\signtool.exe sign /d "My Company" /f "$CertFile" /p "$CertPassword" "$root\setup.exe"' 

#update config properties 
$CodeBasePath = Convert-Path "$PSScriptRoot\Application Files\MyProduct_*" 
$ConfigPath = $CodeBasePath + "\MyProduct.dll.config.deploy" 
[xml] $xml = Get-Content $ConfigPath 

$Endpoint = $xml.SelectSingleNode('/configuration/appSettings/add[@key="MailCheckerEndpoint"]') 
$Endpoint.value = $MailCheckerEndpoint 

$ApiEndpoint = $xml.SelectSingleNode('/configuration/appSettings/add[@key="MyApi:ApiBaseUrl"]') 
$ApiEndpoint.value = $MyProductApiEndpoint 
$xml.Save($ConfigPath) 

#Begin Resigning various Manifests 
$AppManifestPath = Convert-Path "Application Files\MyCompany_*\MyCompany.dll.manifest" 

#Need to resign the application manifest, but before we do we need to rename all the files back to their original names (remove .deploy) 
Get-ChildItem "$CodeBasePath\*.deploy" -Recurse | Rename-Item -NewName { $_.Name -replace '\.deploy','' } 

#Resign application manifest 
Invoke-Expression 'C:\Tools\mage.exe -update "$CodeBasePath\MyCompany.dll.manifest" -certFile "$CertFile" -password "$CertPassword" -if "Application Files\MyCompany_1_2_35_0\Resources\ID.ico"' 

#Regisn deployment manifests in root and versioned folder 
Invoke-Expression 'C:\Tools\mage.exe -update "$CodeBasePath\MyCompany.vsto" -certFile "$CertFile" -password "$CertPassword" -appManifest "$AppManifestPath" -pub "My Company" -ti "http://timestamp.globalsign.com/scripts/timstamp.dll"' 
Invoke-Expression 'C:\Tools\mage.exe -update "$root\MyComapny.vsto" -certFile "$CertFile" -password "$CertPassword" -appManifest "$AppManifestPath" -pub "My company" -ti "http://timestamp.globalsign.com/scripts/timstamp.dll"' 

#Rename files back to the .deploy extension, skipping the files that shouldn't be renamed 
Get-ChildItem -Path "Application Files\*" -Recurse | Where-Object {!$_.PSIsContainer -and $_.Name -notlike "*.manifest" -and $_.Name -notlike "*.vsto"} | Rename-Item -NewName {$_.Name + ".deploy"} 
Questions connexes