2012-06-21 13 views
5

Tôi đang làm việc để tự động hoá trình cài đặt cho ứng dụng .NET 4.0 ClickOnce WPF, cần một vài mục được đặt trong app.config tệp. Tôi đã trải qua quá trình khó khăn của việc tìm kiếm các bước cụ thể mà tôi phải tuân theo bằng cách sử dụng Mage.exe (tức là, cập nhật và ký lại các tệp kê khai ứng dụng và triển khai) và bây giờ tôi đang cố gắng tự động hóa nó để cài đặt.Cập nhật tệp kê khai triển khai cho ứng dụng ClickOnce lập trình dẫn đến thiếu phần tử <compatibleFrameworks>, được yêu cầu trong 4.0

tôi chọn sử dụng .deploy phần mở rộng để giảm thiểu các vấn đề với IIS/Internet   cơ chế bảo mật Explorer, vì vậy về cơ bản các thuật toán như sau (dựa trên Signing and re-signing manifests in ClickOnce (Saurabh Bhatia)Update Configuration of a ClickOnce WPF Application Using Mage or MageUI, như nguồn chính số những người khác):

  1. Chuyển đến thư mục \Application Files\App_%HighestVersion%\
  2. Di .deploy ext ension cho các tập tin mà có nó
  3. Run   mage -u %app%.exe.manifest -cf cert.pfx
  4. Restore .deploy mở rộng
  5. Run   mage -u %app%.application -appm %app%.exe.manifest -cf cert.pfx
  6. Sao chép %app%.application 2 cấp độ lên (để ..\.. - triển khai gốc)

đó làm việc hoàn toàn nếu được thực hiện thủ công. Tôi có thể chạy tệp .cmd, được tùy chỉnh cho các chi tiết môi trường (đường dẫn, v.v.), nhưng sau đó tôi cần phải bao gồm mage.exe trong triển khai và liệu Microsoft có cho phép chúng tôi làm điều đó không. Vì vậy, tôi đang cố gắng để thực hiện hành động tương tự trong lớp 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); 

Bây giờ, đây là kicker. Mọi thứ hoạt động hoàn hảo với ngoại lệ của bước 5. Khi ứng dụng được tải xuống máy của người dùng có vấn đề với tệp kê khai triển khai:

  • Tệp kê khai triển khai không có giá trị ngữ nghĩa.
  • Tệp kê khai triển khai bị thiếu < compatibleFrameworks>.

Thật vậy, phần này không còn hiện diện nữa (tuy nhiên, nó nằm trong% ứng dụng% gốc .ứng dụng!). Kết quả tương tự được mô tả trong ClickOnce - .NET 4.0 errors: "Deployment manifest is not semantically valid" and "Deployment manifest is missing <compatibleFrameworks>", nhưng là kết quả của một quá trình khác (msbuild). Phần này là mới (và cần thiết) cho 4.0 biểu hiện, vì vậy tôi chỉ đoán là bằng cách nào đó khi ManifestWriter vẫn thay đổi đĩa nó hiện nó trong một thời trang 3,5? Tôi ba kiểm tra xem một thư viện chính xác được sử dụng (C: \ Program Files (x86) \ Tham chiếu Assemblies \ Microsoft \ Framework.NETFramework \ v4.0 \ Microsoft.Build.Tasks.v4.0.dll). Điều gì mang lại?

Thay một câu trả lời cho đến nay tôi đã cố gắng để thêm phần thiếu bằng tay:

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

Nhưng điều đó không có tác dụng, không có vấn đề mà tôi đặt mã này, trước khi dm.ResolveFiles() , dm.UpdateFileInfo() hoặc ManifestWriter.WriteManifest (..)!

kết quả của tôi cũng tương tự như câu hỏi để Stack Overflow MageUI.exe removes compatibleFrameworks element hoặc Why does Mage.exe not generate a compatibleFrameworks attribute? hoặc MageUI.exe is not including a compatibleFrameworks element, nhưng tôi không sử dụng mageui, mage hoặc thậm chí msbuild ở tất cả!

Điều gì đang xảy ra?

+0

Như một giải pháp khác, bạn đã cố gắng trực tiếp thao tác XML biểu hiện thay vì sử dụng API chưa? Nó đã làm việc cho chúng tôi trong quá khứ - bạn có toàn quyền kiểm soát nội dung, làm bất cứ điều gì bạn muốn, và sau đó ký lại vào tập tin khi bạn đã hoàn tất. –

+0

Astrogator - có cơ hội nào để bạn có thể chia sẻ kịch bản cho bạn không? Tôi sắp bắt đầu một quá trình rất giống nhau. Cảm ơn! –

+0

Xin chào @ErickT! Vâng, thuật toán là khá nhiều đặt ra ở đây. Mã này được thực hiện bởi msiexec.exe thông qua một hành động tùy chỉnh, mà tôi chỉ định trong dự án Visual Studio 2010 thiết lập - không có 'kịch bản' cho mỗi se. Hãy cho tôi biết, nếu điều đó là không đủ rõ ràng, và tôi sẽ cố gắng để lộ nhiều hơn nữa. – Astrogator

Trả lời

8

Tự tìm hiểu. Thủ phạm là ManifestReader.ReadManifest ("DeployManifest", sPathMft, true).

MSDN cho biết, [preserveStream đối số] "chỉ định xem có giữ lại luồng đầu vào trong thuộc tính InputStream của đối tượng tệp kê khai kết quả hay không. Được sử dụng bởi ManifestWriter để hoàn nguyên đầu vào không được trình bày trong biểu diễn đối tượng."

Wording sang một bên, thiết đúng là không đủ bởi chính nó: dm.CompatibleFrameworks.Count vẫn sẽ là 0, nhưng bây giờ việc bổ sung các CompatibleFramework mục này sẽ có ảnh hưởng!

Đối với người khác trong cùng một thuyền, tôi làm điều đó trước khi 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, nhờ gợi ý của bạn!   Đồng ý, mặc dù tôi thích làm việc với các đối tượng API (so với XML).
Một cách khác là gọi số mage (trực tiếp hoặc từ tệp .cmd), vì có vẻ như chúng tôi are allowed để phân phối lại nó.


Tôi cũng đã thêm phần sau, mà không có tác động về vấn đề riêng của mình, nhưng có thể khá quan trọng đối với bất cứ ai đi theo con đường tương tự (/client là gốc rễ triển khai, và có thể tùy chỉnh):

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

Tôi cũng cần thêm các bài tương thích. Tôi cũng đã cố gắng làm thêm CompatibleFrameworks như thế này (mà không làm việc)

dm.CompatibleFrameworks.Add(...); 

giải pháp của tôi là để thiết lập:

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

Sau này thế hệ Manifest là đúng.

Hãy cẩn thận Nếu bạn đặt TargetFrameworkMoniker trước khi WriteManifest bạn có <compatibleFrameworks> hai lần và tệp ứng dụng của bạn bị hỏng. Đây là giải pháp của tôi cho việc này:

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); 
Các vấn đề liên quan