Chuyển đổi cấu hình web không hoạt động


88

Trong ứng dụng .NET MVC 3.0, tôi có cấu hình sau appSettings:

web.config

<appSettings>
<add key="SMTPHost" value="mail.domain.com"/>
    <add key="SMTPUsername" value="user@gmail.com"/>
    <add key="SMTPPort" value="25"/>
    <add key="SMTPPwd" value="mypassword"/>
    <add key="EmailFrom" value="notific@gmail.com"/>
</appSettings>

Để gỡ lỗi, tôi đã xác định biến đổi cấu hình sau:

web.Debug.config

<appSettings>
    <add  key="SMTPPort" value="58" xdt:Transform="Replace" xdt:Locator="Match(key)" />
</appSettings>

Và tôi chạy ứng dụng ở chế độ gỡ lỗi, nhưng cổng SMTP của tôi vẫn lấy giá trị từ web.config, không phải web.Debug.config.

Bất cứ ai có thể đề xuất những gì có thể bị sai trong cấu hình này?

Câu trả lời:


156

Các biến đổi Web.config chỉ được áp dụng như một phần của hoạt động xuất bản.

Nếu bạn muốn điều này được thực hiện như một phần của app.confighoạt động xây dựng, thì bạn có thể sử dụng plugin SlowCheetah - XML ​​Transforms Visual Studio:

http://visualstudiogallery.msdn.microsoft.com/69023d00-a4f9-4a34-a6cd-7e854ba318b5


1
Cảm ơn bạn rất nhiều vì bạn đã tiết kiệm cho tôi rất nhiều thời gian.
HaBo

3
wow tôi đã mất 2 giờ để tìm câu trả lời này. Cảm ơn vì đã đăng nó, tôi sẽ nhổ tóc.
Peanut

Có vẻ như trong Visual Studio 2015 (Web), biến đổi .config hiện là một tính năng được tích hợp sẵn, vì vậy bạn không cần SlowCheetah nữa. Nhưng các biến đổi tích hợp sẵn sẽ chỉ áp dụng nếu bạn xuất bản ứng dụng, không phải nếu bạn chạy nó. Bạn có thể xem ở đây cách tôi đã giải quyết nó.
Matt,

1
Không chắc tại sao phải sử dụng điều này trong khi câu trả lời của @ komsky cung cấp một giải pháp đơn giản và sạch sẽ.
Csaba Toth

1
SlowCheetah rất tuyệt, nhưng từ tài liệu của riêng họ: "Đối với các dự án web, các tệp được chuyển đổi khi bạn xuất bản hoặc đóng gói ứng dụng của mình." Nói cách khác, không phải trong khi gỡ lỗi.
Doug

31

Rất tiếc, Visual Studio (2010 - 2019) không hỗ trợ trực tiếp nó khi bạn đang gỡ lỗi, nó chỉ dành cho xuất bản - ngay cả với phần mở rộng SlowCheetah (câu trả lời được đánh dấu) nó không hoạt động đối với tôi (chỉ dành cho các dự án sử dụng app.config hơn là web.config).

Lưu ý rằng có một cách giải quyết được mô tả tại codeproject .

Nó mô tả cách sửa đổi tệp .msproj để ghi đè lên web.config hiện tại bằng phiên bản đã chuyển đổi.

Trước tiên, tôi sẽ mô tả cách giải quyết đó là Tùy chọn 1 , nhưng gần đây tôi đã phát hiện ra một Tùy chọn 2 khác , dễ sử dụng hơn (vì vậy bạn có thể cuộn xuống tùy chọn 2 trực tiếp nếu muốn):


Tùy chọn 1: Tôi đã thêm các hướng dẫn lấy từ bài viết codeproject gốc (xem liên kết ở trên), vì ảnh chụp màn hình ở đó đã biến mất và tôi không muốn mất toàn bộ thông tin:

VS.Net không thực hiện bất kỳ chuyển đổi nào khi bạn đang phát triển và chỉ gỡ lỗi môi trường cục bộ của bạn. Nhưng có một số bước bạn có thể làm để điều này xảy ra nếu bạn muốn.

  • Đầu tiên, hãy tạo các cấu hình bạn muốn trong VS.Net , giả sử rằng bản gỡ lỗi và bản phát hành mặc định không đủ cho những gì bạn đang cố gắng thực hiện.
  • Nhấp chuột phải vào của bạn web.configvà chọn Add Config Transforms - thao tác này sẽ tạo một cấu hình chuyển đổi phụ thuộc cho từng cấu hình của bạn đã xác định.
  • Bây giờ bạn có thể đổi tên web.configthành web.base.config.
  • Thêm một web.configvào dự án của bạn. Nó không quan trọng những gì có trong nó bởi vì nó sẽ bị ghi đè mỗi lần chúng tôi làm một xây dựng nhưng chúng tôi muốn nó là một phần của dự án để VS.Net không cho chúng ta những "dự án của bạn không được cấu hình cho Debugging" pop- lên.
  • Chỉnh sửa .csprojtệp dự án của bạn và thêm TransformXmlnhiệm vụ sau vào mục tiêu AfterBuild. Ở đây bạn có thể thấy tôi sẽ chuyển đổi web.base.configtệp bằng cách sử dụng web.[configuration].configvà nó sẽ lưu nó dưới dạng web.config. Để biết chi tiết, vui lòng kiểm tra phần Hỏi & Đáp này của Microsoft và để biết hướng dẫn cách mở rộng bản dựng, hãy xem ở đó .

Lựa chọn 2:

Dựa trên câu trả lời này , tôi đã phát triển một ứng dụng console đơn giản, TransformConfig.exe (theo cú pháp C # 6.0):

using System;
using System.Linq;
using Microsoft.Web.XmlTransform;

namespace TransformConfig
{

  class Program
  {
    static int Main(string[] args)
    {
        var myDocumentsFolder = $@"C:\Users\{Environment.UserName}\Documents";
        var myVsProjects = $@"{myDocumentsFolder}\Visual Studio 2015\Projects";

        string srcConfigFileName = "Web.config";
        string tgtConfigFileName = srcConfigFileName;
        string transformFileName = "Web.Debug.config";
        string basePath = myVsProjects + @"\";
        try
        {

            var numArgs = args?.Count() ?? 0;
            if (numArgs == 0 || args.Any(x=>x=="/?"))
            {
                Console.WriteLine("\nTransformConfig - Usage:");
                Console.WriteLine("\tTransformConfig.exe /d:tgtConfigFileName [/t:transformFileName [/s:srcConfigFileName][/b:basePath]]");
                Console.WriteLine($"\nIf 'basePath' is just a directory name, '{basePath}' is preceeded.");
                Console.WriteLine("\nTransformConfig - Example (inside PostBuild event):");
                Console.WriteLine("\t\"c:\\Tools\\TransformConfig.exe\"  /d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config /b:\"$(ProjectDir)\\\"");
                Environment.ExitCode = 1;
                return 1;
            }

            foreach (var a in args)
            {
                var param = a.Trim().Substring(3).TrimStart();
                switch (a.TrimStart().Substring(0,2).ToLowerInvariant())
                {
                    case "/d":
                        tgtConfigFileName = param ?? tgtConfigFileName;
                        break;
                    case "/t":
                        transformFileName = param ?? transformFileName;
                        break;
                    case "/b":
                        var isPath = (param ?? "").Contains("\\");
                        basePath = (isPath == false)
                                    ? $@"{myVsProjects}\" + param ?? ""
                                    : param;
                        break;
                    case "/s":
                        srcConfigFileName = param ?? srcConfigFileName;
                        break;
                    default:
                        break;
                }
            }
            basePath = System.IO.Path.GetFullPath(basePath);
            if (!basePath.EndsWith("\\")) basePath += "\\";
            if (tgtConfigFileName != srcConfigFileName)
            {
                System.IO.File.Copy(basePath + srcConfigFileName,
                                     basePath + tgtConfigFileName, true);
            }
            TransformConfig(basePath + tgtConfigFileName, basePath + transformFileName);
            Console.WriteLine($"TransformConfig - transformed '{basePath + tgtConfigFileName}' successfully using '{transformFileName}'.");
            Environment.ExitCode = 0;
            return 0;
        }
        catch (Exception ex)
        {
            var msg = $"{ex.Message}\nParameters:\n/d:{tgtConfigFileName}\n/t:{transformFileName}\n/s:{srcConfigFileName}\n/b:{basePath}";
            Console.WriteLine($"TransformConfig - Exception occurred: {msg}");
            Console.WriteLine($"TransformConfig - Processing aborted.");
            Environment.ExitCode = 2;
            return 2;
        }
    }

    public static void TransformConfig(string configFileName, string transformFileName)
    {
        var document = new XmlTransformableDocument();
        document.PreserveWhitespace = true;
        document.Load(configFileName);

        var transformation = new XmlTransformation(transformFileName);
        if (!transformation.Apply(document))
        {
            throw new Exception("Transformation Failed");
        }
        document.Save(configFileName);
    }

  }
}

Đảm bảo rằng bạn thêm DLL "C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web\Microsoft.Web.XmlTransform.dll"làm tham chiếu (ví dụ này áp dụng cho VS 2015, đối với các phiên bản cũ hơn thay thế v14.0đường dẫn trong đường dẫn bằng số phiên bản thích hợp, ví dụ v11.0:).

Đối với Visual Studio 2017, các lược đồ đặt tên cho con đường đã thay đổi: Ví dụ, đối với phiên bản doanh nghiệp nó là ở đây: C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web.
Tôi giả định rằng đối với phiên bản chuyên nghiệp, bạn cần thay thế Enterprisetrong đường dẫn bằng Professional. Nếu bạn đang sử dụng phiên bản xem trước, hãy thay thế 2017bằng Preview.

Dưới đây là tổng quan về cách đường dẫn đã thay đổi đối với các phiên bản Visual Studio khác nhau (nếu bạn không có phiên bản Enterprise, bạn có thể cần phải thay thế Enterprisebằng Professionaltrong đường dẫn):

        Đường dẫn Microsoft.Web.XmlTransform.dllphiên bản VS (cho )
2015                   C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v14.0\Web
2017                   C:\Program Files (x86)\Microsoft Visual Studio\2017\
                          Enterprise\MSBuild\Microsoft\VisualStudio\v15.0\Web
2019                  C:\Program Files (x86)\Microsoft Visual Studio\2019\
                          Enterprise\MSBuild\Microsoft\VisualStudio\v16.0\Web

Biên dịch nó và đặt tệp .exe vào một thư mục, ví dụ C:\MyTools\.

Cách sử dụng: Bạn có thể sử dụng nó trong sự kiện xây dựng bài đăng của mình (trong thuộc tính dự án , chọn Tạo sự kiện , sau đó chỉnh sửa dòng lệnh Sự kiện sau xây dựng ). Các tham số dòng lệnh là (ví dụ):

"C: \ MyTools \ TransformConfig.Exe" /d:Web.config /t:Web.$(ConfigurationName).config /s:Web.Template.config / b: "$ (ProjectDir) \"

tức là đầu tiên là tên của tệp cấu hình, tiếp theo là tệp cấu hình biến đổi, tiếp theo là cấu hình mẫu tùy chọn, tiếp theo là đường dẫn đến dự án của bạn chứa cả hai tệp.

Tôi đã thêm thông số cấu hình mẫu tùy chọn vì nếu không, cấu hình hoàn chỉnh ban đầu của bạn sẽ bị ghi đè bởi biến đổi, điều này có thể tránh được bằng cách cung cấp mẫu.

Tạo mẫu chỉ cần sao chép Web.config gốc và đặt tên là Web.Template.config.

Ghi chú:

  • Nếu muốn, bạn cũng có thể sao chép TransformConfig.exetệp vào đường dẫn Visual Studio được đề cập ở trên nơi tệp đó Microsoft.Web.XmlTransform.dllcư trú và tham chiếu đến tệp đó trong tất cả các dự án của bạn nơi bạn cần chuyển đổi cấu hình của mình.

  • Đối với những người trong số các bạn đang thắc mắc tại sao tôi thêm các Environment.ExitCode = x;bài tập: Việc chỉ trả lại một int từ Main không giúp ích gì trong sự kiện xây dựng. Xem chi tiết tại đây.

  • Nếu bạn đang xuất bản dự án của mình và bạn đang sử dụng Web.Template.config, hãy đảm bảo rằng bạn đã xây dựng lại giải pháp của mình với cấu hình phù hợp (thường là Bản phát hành) trước khi xuất bản. Nguyên nhân là do Web.Config bị ghi đè trong quá trình gỡ lỗi và nếu không thì bạn có thể chuyển đổi tệp sai.


1
Có vẻ như bài đăng CodeProject đã bị viết. Anh ấy đã sử dụng ảnh chụp màn hình cho các mẫu mã của mình và bây giờ kể từ khi blog của anh ấy ngừng hoạt động, chúng đã bị mất vào lịch sử.
Eric Lloyd

3
Vâng, rất tiếc là ảnh chụp màn hình đã biến mất. Nhưng ít nhất văn bản bài báo vẫn còn đó, mô tả cách tiếp cận. Tôi đã thêm mô tả văn bản vào câu trả lời của mình để tránh bị mất.
Matt,

1
Đúng, có lẽ người ta có thể thử liên hệ với tác giả James Coleman tại codeproject để sửa nó ở đó. Tuy nhiên, không chắc liệu anh ta có còn hoạt động ở đó hay không. @ThomasTeilmann
Matt

Tôi nghĩ điều này có thể tương tự như những gì trong ảnh chụp màn hình bị mất. Có vẻ như đạt được cùng một kết quả cơ bản. stackoverflow.com/a/6437192/1003916
user1003916

22

Trả lời câu hỏi của bạn không đơn giản, vì nó đặt ra một vấn đề - nếu bạn muốn chuyển đổi Web.config bằng Web.debug.config - thì hiệu ứng chuyển đổi nên được lưu trữ ở đâu? Trong chính Web.config? Điều này sẽ ghi đè tệp nguồn chuyển đổi! Có lẽ đó là lý do tại sao Visual Studio không thực hiện chuyển đổi trong quá trình xây dựng.

Câu trả lời Matt trước đây là hợp lệ, nhưng bạn có thể muốn trộn chúng để có giải pháp chung hoạt động khi bạn thực sự thay đổi cấu hình giải pháp hoạt động từ gỡ lỗi sang phát hành, v.v. Đây là một giải pháp đơn giản:

  1. Tạo các chuyển đổi cấu hình của bạn cho các cấu hình (Gỡ lỗi, Phát hành, v.v.)
  2. Đổi tên Web.configtệp thành Web.base.config- các phép biến đổi sẽ tự động đổi tên cho phù hợp ( Web.base.Debug.config, v.v.)
  3. Thêm tệp XML TransformWebConfig.proj sau vào thư mục dự án của bạn:
<?xml version="1.0" encoding="utf-8" ?>
<Project ToolsVersion="4.0" DefaultTargets="TransformWebConfig" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <UsingTask TaskName="TransformXml" AssemblyFile="$(MSBuildExtensionsPath)\Microsoft\VisualStudio\v12.0\Web\Microsoft.Web.Publishing.Tasks.dll" />
  <Target Name="TransformWebConfig">
    <TransformXml Source="Web.base.config" Transform="Web.base.$(CurrentConfig).config" Destination="Web.config" />
  </Target>
</Project>
  1. Điều hướng đến thuộc tính dự án của bạn, chọn Tạo sự kiện và thêm nội dung sau vào dòng lệnh Hậu tạo sự kiện :
@if exist "%ProgramFiles(x86)%\MSBuild\12.0\bin" set PATH=%ProgramFiles(x86)%\MSBuild\12.0\bin;%PATH%
msbuild $(ProjectDir)transformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath)

Bây giờ, khi bạn xây dựng giải pháp của mình, tệp Web.config sẽ được tạo với các biến đổi hợp lệ cho cấu hình hoạt động.


Câu trả lời rõ ràng và tốt nhất. Một số câu hỏi: 1. Tại sao xác thực XML nói rằng elemnt TransformXml không hợp lệ trong phần tử Target? (các công trình xây dựng BTW). 2. Bây giờ điều này tạo ra Web.Config thực, tôi vẫn thêm Web.Config vào dự án. Bây giờ bất kỳ lúc nào tôi chuyển đổi giữa Gỡ lỗi / Phát hành, web.config sẽ thay đổi, nhưng tôi không nhất thiết phải cam kết điều đó mọi lúc vào repo nguồn.
Csaba Toth

1. Không thể thực sự biết cách VS xác thực XML này bằng lược đồ, nhưng cảnh báo này là phổ biến, vì vậy bạn có thể bỏ qua nó. 2. Nó phụ thuộc vào repo bạn đang sử dụng, nhưng bạn có thể sử dụng ví dụ như mục nhập tệp git.ignore.
komsky

4
Điều này hoạt động tốt đối với tôi - chỉ cần thay đổi số 12 trong tệp sự kiện xây dựng và tệp proj thành phiên bản hiện tại. Đối với sự kiện sau xây dựng, tôi đã sử dụng: '"$(MSBuildBinPath)\msbuild.exe" $(ProjectDir)TransformWebConfig.proj /t:TransformWebConfig /p:CurrentConfig=$(ConfigurationName) /p:TargetProjectName=$(TargetPath) và cập nhật v12.0thành v14.0tệp .proj.
Jovie

1
Đối với VS 2017 sửa đổi mỗi 12.0đến14.0
Csaba Toth

1
1) đừng quên đưa web.config đã tạo vào dự án web, hoặc nó sẽ không sao chép vào thư mục đích sau khi xuất bản. 2) nếu việc xây dựng máy chủ thiếu hai tập tin này, chỉ cần sao chép chúng vào máy chủ "Microsoft.Web.Publishing.Tasks", "Microsoft.Web.XmlTransform"
phiree

8

đối với VS 2017, tôi thấy câu trả lời ở đây là không chắc tại sao không ai tham chiếu nó ở trên vì nó dường như là một giải pháp rất phổ biến. Rất dễ dàng. Đảm bảo bạn thấy nhận xét từ IOrlandoni vào ngày 5 tháng 3 năm 2019 để làm cho nó hoạt động trong VS 2017 và tất cả các phiên bản.

Về cơ bản nó là một bước hai. Đầu tiên, bạn chỉnh sửa tệp .csproj, thêm đoạn mã bên dưới. Thứ hai, bạn tạo một cấu hình web.base.config mới và sao chép web.config hiện có vào đó. Sau khi làm điều đó, bất kỳ bản dựng nào sẽ ghi đè lên web.config của bạn bằng chuyển đổi mong muốn của bạn.

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
<Target Name="BeforeBuild">
    <TransformXml Source="Web.Base.config" 
        Transform="Web.$(Configuration).config" Destination="Web.config" />
</Target>  

Đây có lẽ là câu trả lời tốt nhất, nhưng IMO đang thiếu một mẹo nhỏ. Nếu bạn thay đổi Web.configtừ Contentđể Nonesau đó bạn có thể sử dụng Source="Web.config" Destination="$(TargetPath).config"(hoặc có lẽ đối với một số loại dự án, Destination="$(TargetDir)Web.config"). Tôi cũng đã chuyển chuyển đổi sang AfterBuild, vì nó không còn cần phải được thực hiện trước khi các tệp được sao chép.
Peter Taylor

Ok, thực sự điều đó không hoạt động bởi vì một số lý do tôi không thể cấu hình nó để chạy từ đó bin.
Peter Taylor

4

Câu hỏi ngay lập tức của bạn đã được trả lời - lời giải thích là chuyển đổi được áp dụng khi xuất bản, không phải khi xây dựng.

Tuy nhiên, tôi nghĩ rằng nó không đưa ra giải pháp làm thế nào để đạt được những gì bạn muốn làm.

Tôi đã vật lộn với vấn đề chính xác này trong vài ngày nay, đang tìm cách giữ cho web.config sạch sẽ và đặt tất cả các khóa thay đổi tùy theo môi trường trong các tệp chuyển đổi tương ứng. Kết luận của tôi là giải pháp dễ nhất và ổn định nhất là sử dụng các giá trị gỡ lỗi trong web.config gốc, theo cách đó chúng luôn hiện diện khi bạn chạy gỡ lỗi trong Visual Studio.

Sau đó, tạo các chuyển đổi cho các môi trường khác nhau mà bạn muốn xuất bản - thử nghiệm, tích hợp, sản xuất - bất cứ điều gì bạn có. Chức năng hiện được tích hợp sẵn để chuyển đổi tệp web.config khi xuất bản sẽ đủ cho việc này. Không cần SlowCheetah hoặc chỉnh sửa các sự kiện xây dựng cũng như tệp dự án. Nếu bạn chỉ có các dự án web.

Nếu bạn muốn, bạn cũng có thể có tệp web.debug.config trong giải pháp của mình, chỉ để giữ một tệp riêng biệt với tất cả các giá trị liên quan đến môi trường phát triển. Hãy chắc chắn nhận xét trong đó rằng các giá trị không được áp dụng khi chạy trong Visual Studio, trong trường hợp ai đó cố gắng sử dụng nó cho mục đích đó!


1

Sử dụng Octopus Deploy (phiên bản cộng đồng miễn phí) và để nó biến đổi web.configcho bạn. Các bước:

  1. Thiết lập Octopus để triển khai ứng dụng web của bạn
  2. Hãy chắc chắn rằng bạn Web.Release.configBuild Actionbộ tài sản để Contentgiống như chính của bạn web.configtập tin.

Đó là nó! Octopus sẽ làm phần còn lại mà không cần bất kỳ cấu hình đặc biệt nào. Một triển khai trang web IIS mặc định sẽ thực hiện điều này ngay lập tức:nhập mô tả hình ảnh ở đây


Số 2 là chìa khóa :)
Reza

0

Rõ ràng có một phần mở rộng cho Visual Studio 2015

https://visualstudiogallery.msdn.microsoft.com/05bb50e3-c971-4613-9379-acae2cfe6f9e

Gói này cho phép bạn chuyển đổi app.config của mình hoặc bất kỳ tệp XML nào khác dựa trên cấu hình bản dựng


SlowCheeta không phải là một cái mới. nó đã ở đó rất lâu. Bản phát hành 1.1 của họ là vào
9/8/2011

@HaBo Cảm ơn bạn đã chú ý, tôi đã xóa newthế giới dưới dạng câu.
Amir Astaneh

0

Gần đây, tôi đã gặp sự cố tương tự với tệp web.config cũ hơn dựa trên .NET Framework 2.0. Giải pháp đơn giản là xóa không gian tên của web.config ( xmlns attibute trong nút gốc cấu hình ):

TRƯỚC: <configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">

SAU: <configuration>

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.