Sử dụng msbuild để thực thi cấu hình xuất bản hệ thống tệp


86

Tôi có dự án ac # .Net 4.0 được tạo bằng VS2010 và hiện đang được truy cập bằng VS2012.

Tôi đang cố gắng chỉ xuất bản các tệp cần thiết từ trang web này đến vị trí đích (C: \ build \ MyProject [Files])

Cấu trúc tệp của tôi: ./ProjectRoot/MyProject.csproj ./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Tôi đang chạy phần sau qua MSBuild:

C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ MSBuild.exe ./ProjectRoot/MyProject.csproj / p: DeployOnBuild = true /p:PublishProfile=./ProjectRoot/Properties/PublishProfiles/FileSystemDebug.pubxml

Đây là xml trong FileSystemDebug.pubxml

<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <WebPublishMethod>FileSystem</WebPublishMethod>
    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
    <LastUsedPlatform>Any CPU</LastUsedPlatform>
    <SiteUrlToLaunchAfterPublish />
    <ExcludeApp_Data>False</ExcludeApp_Data>
    <publishUrl>C:\builds\MyProject\</publishUrl>
    <DeleteExistingFiles>True</DeleteExistingFiles>
  </PropertyGroup>
</Project>

Hành vi kết quả là:

  • tệp zip được tạo tại đây: ./ProjectRoot/obj/Debug/Package/MyProject.zip
  • Không có gì được triển khai cho <publishUrl>C:\builds\MyProject\</publishUrl>WTF
  • tệp zip được tạo là một bữa sáng lợn và đầy đủ các tệp không cần thiết cho ứng dụng.

Khi tôi chạy hồ sơ xuất bản này thông qua studio trực quan, một thư mục được tạo tại * C: \ build \ MyProject * và chứa các tạo tác chính xác mà tôi muốn.

Làm cách nào để nhận được kết quả đơn giản này từ msbuild?

Câu trả lời:


51

FYI: Tôi đã gặp vấn đề tương tự với Visual Studio 2015. Sau nhiều giờ cố gắng, giờ tôi có thể làm được msbuild myproject.csproj /p:DeployOnBuild=true /p:PublishProfile=myprofile.

Tôi đã phải chỉnh sửa tệp .csproj của mình để nó hoạt động. Nó chứa một dòng như thế này:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v10.0\WebApplications\Microsoft.WebApplication.targets" 
  Condition="false" />

Tôi đã thay đổi dòng này như sau:

<Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v14.0\WebApplications\Microsoft.WebApplication.targets" />

(Tôi đã thay đổi 10.0 thành 14.0, không chắc liệu điều này có cần thiết hay không. Nhưng tôi chắc chắn phải xóa phần điều kiện.)


1
Nhập có điều kiện với Condition="false"tồn tại để tương thích ngược. VS2010 yêu cầu nhập này tồn tại, ngay cả khi nó bị bỏ qua vì điều kiện sai. Nếu bạn nhìn lại thì bạn sẽ thấy rằng csproj chứa một bản nhập khác để phân $(VSToolsPath)\WebApplications\Microsoft.WebApplication.targetsgiải thành tệp đích cho phiên bản Visual Studio hiện tại.
Steven Liekens

3
Lưu ý việc sử dụng chiến lược của $(MSBuildToolsVersion)trong đường dẫn đến tài khoản cho các phiên bản VS thích hợp: <Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(MSBuildToolsVersion)\WebApplications\Microsoft.WebApplication.targets" Condition="false" />. Điều này làm việc cho tôi trên VS2015 Update 1.
Al Dass

42

Tìm thấy câu trả lời ở đây: http://www.digitallycished.net/Blog/59/locally-publishing-a-vs2010-asp.net-web-application-using-msbuild

Visual Studio 2010 có các tính năng xuất bản Dự án ứng dụng web mới tuyệt vời cho phép bạn dễ dàng xuất bản dự án ứng dụng web của mình chỉ bằng một cú nhấp chuột. Phía sau hậu trường, quá trình chuyển đổi và xây dựng gói Web.config được thực hiện bởi một tập lệnh MSBuild lớn được nhập vào tệp dự án của bạn (tìm thấy tại: C: \ Program Files (x86) \ MSBuild \ Microsoft \ VisualStudio \ v10.0 \ Web \ Microsoft .Web.Publishing.targets). Thật không may, tập lệnh cực kỳ phức tạp, lộn xộn và không có tài liệu (sau đó một số nhận xét sai chính tả và chủ yếu là vô ích trong tệp). Một sơ đồ lớn của tệp đó và một số tài liệu về cách kết nối vào nó sẽ rất hay, nhưng có vẻ như vẫn còn thiếu (hoặc ít nhất là tôi không thể tìm thấy nó).

Thật không may, điều này có nghĩa là thực hiện xuất bản thông qua dòng lệnh mờ hơn nhiều so với mức cần thiết. Tôi rất ngạc nhiên về việc thiếu tài liệu trong lĩnh vực này, vì ngày nay nhiều cửa hàng sử dụng máy chủ tích hợp liên tục và một số thậm chí còn triển khai tự động (mà các tính năng xuất bản của VS2010 có thể giúp ích rất nhiều), vì vậy tôi đã nghĩ rằng việc bật điều này ( dễ dàng!) sẽ là một yêu cầu khá chính cho tính năng này.

Dù sao đi nữa, sau khi đào qua tệp Microsoft.Web.Publishing.targets hàng giờ và đập đầu vào tường thử nghiệm và lỗi, tôi đã tìm ra cách Visual Studio thực hiện phép thuật của nó chỉ bằng một cú nhấp chuột “Xuất bản lên Hệ thống tệp” và các tính năng “Gói triển khai xây dựng”. Tôi sẽ tìm hiểu một chút về kịch bản MSBuild, vì vậy nếu bạn chưa quen với MSBuild, tôi khuyên bạn nên xem trang MSDN của khóa học về lỗi này.

Xuất bản lên hệ thống tệp

Hộp thoại Xuất bản lên Hệ thống Tệp VS2010 Xuất bản lên Hệ thống Tệp khiến tôi mất một lúc để giải thích vì tôi mong đợi một số hoạt động sử dụng hợp lý của MSBuild sẽ xảy ra. Thay vào đó, VS2010 làm một điều gì đó khá kỳ lạ: nó kêu gọi MSBuild thực hiện kiểu triển khai một nửa để chuẩn bị các tệp của ứng dụng web trong thư mục obj của dự án của bạn, sau đó nó dường như thực hiện một bản sao thủ công của các tệp đó (tức là bên ngoài MSBuild) vào thư mục xuất bản mục tiêu của bạn. Đây thực sự là một hành vi kỳ lạ vì MSBuild được thiết kế để sao chép các tệp xung quanh (và những thứ liên quan đến xây dựng khác), vì vậy sẽ có ý nghĩa nếu toàn bộ quá trình chỉ là một mục tiêu MSBuild mà VS2010 đã gọi, không phải là mục tiêu sau đó là bản sao thủ công.

Điều này có nghĩa là thực hiện điều này thông qua MSBuild trên dòng lệnh không đơn giản như việc gọi tệp dự án của bạn với một mục tiêu cụ thể và thiết lập một số thuộc tính. Bạn sẽ cần phải làm những gì VS2010 phải làm: tự tạo một mục tiêu để thực hiện nửa triển khai sau đó sao chép kết quả vào thư mục đích. Để chỉnh sửa tệp dự án của bạn, nhấp chuột phải vào dự án trong VS2010 và nhấp vào Dỡ dự án, sau đó nhấp chuột phải một lần nữa và nhấp vào Chỉnh sửa. Cuộn xuống cho đến khi bạn tìm thấy phần tử Nhập nhập mục tiêu ứng dụng web (Microsoft.WebApplication.targets; chính tệp này nhập tệp Microsoft.Web.Publishing.targets được đề cập trước đó). Bên dưới dòng này, chúng tôi sẽ thêm mục tiêu mới, được gọi là PublishToFileSystem:

<Target Name="PublishToFileSystem"
        DependsOnTargets="PipelinePreDeployCopyAllFilesToOneFolder">
    <Error Condition="'$(PublishDestination)'==''"
           Text="The PublishDestination property must be set to the intended publishing destination." />
    <MakeDir Condition="!Exists($(PublishDestination))"
             Directories="$(PublishDestination)" />

    <ItemGroup>
        <PublishFiles Include="$(_PackageTempDir)\**\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(PublishFiles)"
          DestinationFiles="@(PublishFiles->'$(PublishDestination)\%(RecursiveDir)%(Filename)%(Extension)')"
          SkipUnchangedFiles="True" />
</Target>

Mục tiêu này phụ thuộc vào mục tiêu PipelinePreDeployCopyAllFilesToOneFolder, là mục tiêu mà VS2010 gọi trước khi thực hiện sao chép thủ công. Một số tìm hiểu trong Microsoft.Web.Publishing.targets cho thấy rằng việc gọi đích này khiến các tệp dự án được đặt vào thư mục được chỉ định bởi thuộc tính _PackageTempDir.

Tác vụ đầu tiên chúng tôi gọi trong mục tiêu của mình là tác vụ Lỗi, trên đó chúng tôi đã đặt một điều kiện đảm bảo rằng tác vụ chỉ xảy ra nếu thuộc tính PublishDestination chưa được đặt. Điều này sẽ bắt bạn và lỗi bản dựng trong trường hợp bạn quên chỉ định thuộc tính PublishDestination. Sau đó, chúng tôi gọi tác vụ MakeDir để tạo thư mục PublishDestination đó nếu nó chưa tồn tại.

Sau đó, chúng tôi xác định một Mục được gọi là PublishFiles đại diện cho tất cả các tệp được tìm thấy trong thư mục _PackageTempDir. Sau đó, tác vụ Sao chép được gọi là tác vụ sao chép tất cả các tệp đó vào thư mục Đích xuất bản. Thuộc tính DestinationFiles trên phần tử Copy hơi phức tạp; nó thực hiện chuyển đổi các mục và chuyển đổi các đường dẫn của chúng thành các đường dẫn mới bắt nguồn từ thư mục PublishDestination (kiểm tra Siêu dữ liệu Mục Nổi tiếng để xem ý nghĩa của% () s).

Để gọi mục tiêu này từ dòng lệnh, bây giờ chúng ta có thể chỉ cần thực hiện lệnh này (rõ ràng là thay đổi tên tệp dự án và thuộc tính cho phù hợp với bạn):

msbuild Website.csproj "/p:Platform=AnyCPU;Configuration=Release;PublishDestination=F:\Temp\Publish" /t:PublishToFileSystem

3
Tôi không thể hiểu được đoạn mã cho mục tiêu mới (nó hiển thị 01 02 03 ...). Bạn có thể vui lòng chỉnh sửa?
fan711

2
Tôi đồng ý với fan711. Mặc dù vậy, giải pháp được phân biệt đối xử trên liên kết - sau đó sao chép nó để làm gì?
Антон Курьян

4
@ АнтонКурьян: Các liên kết có xu hướng chết sau một thời gian, đó là lý do tại sao các câu hỏi và câu trả lời trên stackoverflow.com phải luôn tự động mà không dựa vào các nguồn lực bên ngoài.
Oliver

Kết quả có vẻ như hồ sơ xuất bản hoàn toàn không được MSBuild sử dụng, và thay vào đó nó đang thực hiện một gói (có thể là mặc định?). Giải pháp bên dưới của bạn thực hiện điều gì để sao chép những gì cấu hình được đặt để làm, mà Microsoft.Web.Publishing.targets xử lý bằng cách chọn đúng loại từ thư mục triển khai của nó (đối với FileSystem). Vì vậy, có vẻ như bạn đang phát minh lại bánh xe ở đây, thay vì giải quyết vấn đề đó. Nhưng không thể nói chắc chắn nếu không có nhật ký MSBuild của bạn. Tôi nhận mỏ làm việc, chi tiết trong câu trả lời của tôi
GregS

1
Giải pháp của GregS không phù hợp với tôi. Xây dựng tốt, nhưng không có tệp nào được sao chép vào thư mục xuất bản
gấp rút

19

Vẫn gặp sự cố sau khi thử tất cả các câu trả lời ở trên (tôi sử dụng Visual Studio 2013). Không có gì được sao chép vào thư mục xuất bản.

Vấn đề là nếu tôi chạy MSBuild với một dự án riêng lẻ thay vì một giải pháp, tôi phải đặt một tham số bổ sung chỉ định phiên bản Visual Studio:

/p:VisualStudioVersion=12.0

12.0dành cho VS2013, thay thế bằng phiên bản bạn sử dụng. Sau khi tôi thêm thông số này, nó chỉ hoạt động.

Dòng lệnh hoàn chỉnh trông như thế này:

MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0

Tôi đã tìm thấy nó ở đây:

http://www.asp.net/mvc/overview/deployment/visual-studio-web-deployment/command-line-deployment

Họ nói:

Nếu bạn chỉ định một dự án riêng lẻ thay vì một giải pháp, bạn phải thêm một tham số chỉ định phiên bản Visual Studio.


12

Đối với tôi, có vẻ như hồ sơ xuất bản của bạn không được sử dụng và đang thực hiện một số đóng gói mặc định. Các mục tiêu của Microsoft Web Publish thực hiện tất cả những gì bạn đang làm ở trên, nó chọn các mục tiêu chính xác dựa trên cấu hình.

Tôi không gặp vấn đề gì từ bước TeamCity MSBuild, nhưng tôi đã chỉ định một đường dẫn rõ ràng đến hồ sơ, bạn chỉ cần gọi nó bằng tên mà không có .pubxml (ví dụ: FileSystemDebug). Nó sẽ được tìm thấy miễn là trong thư mục tiêu chuẩn, là của bạn.

Thí dụ:

C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe ./ProjectRoot/MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=FileSystemDebug

Lưu ý rằng điều này được thực hiện bằng cách sử dụng phiên bản Visual Studio 2012 của mục tiêu Microsoft Web Publish, thường được đặt tại "C: \ Program Files (x86) \ MSBuild \ Microsoft \ VisualStudio \ v11.0 \ Web". Kiểm tra thư mục triển khai để biết các mục tiêu loại triển khai cụ thể được sử dụng


MS đã thực hiện rất nhiều cải tiến kể từ khi điều này được đăng cách đây vài năm, cảm ơn bạn đã cập nhật chương trình?
P. Roe

3

FYI: Vấn đề tương tự khi chạy trên máy chủ xây dựng (Jenkins với msbuild 15 được cài đặt, được điều khiển từ VS 2017 trên dự án web .NET Core 2.1).

Trong trường hợp của tôi, việc sử dụng đích "xuất bản" với msbuild đã bỏ qua hồ sơ.

Vì vậy, lệnh msbuild của tôi bắt đầu bằng:

msbuild /t:restore;build;publish

Điều này đã kích hoạt chính xác quá trình xuất bản, nhưng không có sự kết hợp hoặc biến thể nào của "/ p: PublishProfile = FolderProfile" từng hoạt động để chọn cấu hình tôi muốn sử dụng ("FolderProfile").

Khi tôi ngừng sử dụng mục tiêu xuất bản:

msbuild /t:restore;build /p:DeployOnBuild=true /p:PublishProfile=FolderProfile

Tôi (ngu ngốc) nghĩ rằng nó sẽ không có gì khác biệt, nhưng ngay sau khi tôi sử dụng công tắc DeployOnBuild, nó đã chọn đúng hồ sơ.


3

Trên thực tế, tôi đã hợp nhất tất cả các câu trả lời của bạn thành giải pháp của riêng tôi, cách giải quyết vấn đề trên:

  1. Tôi tạo tệp pubxml theo nhu cầu của mình
  2. Sau đó, tôi sao chép tất cả các tham số từ tệp pubxml sang danh sách tham số của riêng tôi "/ p: foo = bar" cho msbuild.exe
  3. Tôi vứt bỏ tệp pubxml

Kết quả là như vậy:

msbuild /t:restore /t:build /p:WebPublishMethod=FileSystem /p:publishUrl=C:\builds\MyProject\ /p:DeleteExistingFiles=True /p:LastUsedPlatform="Any CPU" /p:Configuration=Release


1

Trước tiên, hãy kiểm tra phiên bản Visual studio của PC nhà phát triển có thể xuất bản giải pháp (dự án). như được hiển thị cho VS 2013

 /p:VisualStudioVersion=12.0

thêm dòng lệnh trên để chỉ định loại phiên bản studio trực quan nào nên xây dựng dự án. Như các câu trả lời trước, điều này có thể xảy ra khi chúng tôi chỉ cố gắng xuất bản một dự án, không phải toàn bộ giải pháp.

Vì vậy, mã hoàn chỉnh sẽ giống như thế này

"C: \ Windows \ Microsoft.NET \ Framework \ v4.0.30319 \ msbuild.exe" "C: \ Program Files (x86) \ Jenkins \ workspace \ Jenkinssecondsample \ MVCSampleJenkins \ MVCSampleJenkins.csproj" / T: Build; Package / p : Configuration = DEBUG / p: OutputPath = "obj \ DEBUG" / p: DeployIisAppPath = "Trang web mặc định / jenkinsdemoapp" /p:VisualStudioVersion=12.0


1
Xin lỗi shammakalubo bạn đã hiểu sai câu hỏi rất nhiều.
P. Roe

1
@shammakalubo Câu trả lời là đúng, nhưng nó không được nêu hoàn toàn. Tham số này cần được thêm vào lệnh mà OP đề cập, sau đó sẽ trở thành: MSBuild C:\PathToMyProject\MyProject.csproj /p:DeployOnBuild=true /p:PublishProfile=MyPublishProfile /p:VisualStudioVersion=12.0Tham số này là những gì tôi đã thiếu và đã khắc phục sự cố của tôi. Bạn chỉ cần đề cập đến câu trả lời hoàn toàn!
Syed Waqas

@WaqasShah Cảm ơn, Như bạn đã đề cập, tôi đã chỉnh sửa câu trả lời của mình và xuất bản mã hoàn chỉnh trông như thế nào.
Shammie
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.