2010-02-22 23 views
6

Mam plik konfiguracyjny, który wymaga zmiany na serwerze, tak aby po zainstalowaniu na nim naszego oprogramowania, plik konfiguracyjny instalatora klienta został skonfigurowany tak, aby odpowiadał konkretnemu serwerowi. ustawień, a następnie skopiowane do folderu publicznego w sieci w celu wdrożenia.Problemy z instalacją Mage.exe

Ponieważ zmieniam plik konfiguracyjny, muszę również odbudować pliki * .manifest i * .application, a jak rozumiem, moją jedyną realną opcją jest użycie Mage.exe z Win7 SDK . Aby naprawić plik * .manifest z poprawnym hashem ze zmodyfikowanego pliku konfiguracyjnego, uruchamiam:

mage -new Application -fd ". \ Application Files \ < appName> _1_0_0_0" -ToFile ". \ Application Files \ _1_0_0_0 \ < appName> .exe.manifest”-Name "< appName>" -version "1.0.0.0" -CertFile "key.pfx" -password "< hasło>"

a następnie, aby naprawić * Plik .application z poprawnym hashem ze zmodyfikowanego * pliku manifestu. Uruchamiam:

mage -new Deployment -I t -t "< appName> .application" -v "1.0.0.0" -appManifest ". \ Pliki aplikacji \ < appName> _1_0_0_0 \ < appName> .exe.manifest "-puryn "http: // < hostaddress>/< ścieżka>/Pliki aplikacji/< appName> _1_0_0_0/< appName> .exe.manifest" -CertFile" key.pfx "-password" "

Teraz wszystko działa i otrzymuję wiadomość, że pliki zostały pomyślnie podpisane. Kiedy próbuję zainstalować aplikację kliencką choć to oczywiste, że coś poszło na opak, kiedy pojawia się dziennik błędów z komunikatem:

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

W patrząc na plik * .application, posiada kilka dodatkowych informacji w ramach „wdrożenie” węzeł, który sam plik bezpośrednio z funkcji publikowania w VS2008 nie ma:

<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> 

VS2008 opublikować wersję po prostu posiada:

<deployment install="true" /> 

Kiedy Usuwam dodatkowe informacje i ustawię węzeł wdrażania na węzeł samo kończący się, a następnie ponownie podpisuję plik, wszystko działa zgodnie z oczekiwaniami.

Czy jest to znany problem i czy istnieje sposób zmotywowania maga do utworzenia pliku bez dodatkowych informacji w węźle wdrażania, aby działał poprawnie?

EDYCJA: Jako tymczasowe rozwiązanie, ładuję pliki do XmlDocument i modyfikuję je, aby odpowiadały, a następnie ponownie podpisywały pliki. Ponadto mam teraz do czynienia z problemem, który nie pozwala jeszcze określić sposobu dodania ikony do wdrożenia, więc element menu Start otrzymuje ikonę inną niż ikona ogólna.

+0

Mam bardzo podobny przypadek użycia z podobnymi problemami. Odpowiem, jeśli znajdę rozwiązanie. –

+0

po prostu użyj flagi -appc na maga –

+0

Nathan, sprawdź moją odpowiedź i zobacz, czy to ci pomaga. Korzystanie z Mage.exe powinno działać dobrze. –

Odpowiedz

2

Oto moja implementacja. Spędziłem dużo czasu nad tym małym fragmentem kodu i nadal nie znalazłem wszystkich odpowiednich opcji, aby Mag obsługiwał całą generację pliku .application bez interwencji. Powiem, że prawdopodobnie istnieje wiele optymalizacji, które można by wprowadzić do tego kodu. Jednak może to nadal służyć jako trampolina, aby komuś pomóc.

Aby następująca metoda działała, należy ją wdrożyć przynajmniej raz z poziomu ClickOnce w VS, a następnie po prostu zachować plik .application z tego obrazu stanowiska. MUSISZ usunąć pliki .application i .manifest w folderze wdrażania.

Po I zostały przeniesione wszystkie pliki aplikacji do 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 dla "nędznego". – Tim

1

Jeśli twoim celem jest, aby zmodyfikować swój manifest aplikacji pomiędzy środowiskami Nie jestem pewien, dlaczego chcesz utworzyć nową. Po prostu zmodyfikuj swój obecny. Piszę skrypt powershell, który robi to, czego potrzebujesz i więcej ... W moim przypadku mam bootstrapper konfiguracji, ale odpowiedni kod, którego potrzebujesz, znajduje się na samym dole.

Dla programu instalacyjnego bootstrapper nie można zrezygnować z podpisanego programu startowego, więc musiałem znaleźć plik DLL innej firmy, aby go zignorować. (Delcert) http://forum.xda-developers.com/showthread.php?t=416175 mam, że matka w kontroli źródła w przypadku znika ona z internetowej jeden dzień :)

znajdź sekcję #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"}