简体   繁体   English

在 Visual Studio 解决方案中更改我所有项目的目标框架

[英]Change the Target Framework for all my projects in a Visual Studio Solution

I need to change the target framework for all projects.我需要更改所有项目的目标框架。 I have many solutions with hundreds of projects.我有数百个项目的许多解决方案。

Anything new here or do I have to change every single project?这里有什么新东西还是我必须改变每个项目?

刚刚发布了Target Framework Migrator ,Visual Studio Extension,用于一次更改多个 .Net 项目 Target Framework

You can do that using Scott Dorman's Visual Studio macro available on CodeProject:您可以使用 CodeProject 上提供的 Scott Dorman 的 Visual Studio 宏来做到这一点:

Visual Studio 2010 and Target Framework Version Visual Studio 2010 和目标框架版本

Below is the code, download it to your <UserProfile>\\Documents\\Visual Studio 2010\\Projects\\VSMacros80\\MyMacros folder, open the Visual Studio Macro IDE (Alt-F11) and add it as an existing item to the “MyMacros” project:下面是代码,将其下载到<UserProfile>\\Documents\\Visual Studio 2010\\Projects\\VSMacros80\\MyMacros文件夹,打开 Visual Studio Macro IDE (Alt-F11) 并将其作为现有项目添加到“MyMacros”项目:

'------------------------------------------------------------------------------
' Visual Studio 2008 Macros
'
' ProjectUtilities.vb
'
'------------------------------------------------------------------------------
' Copyright (C) 2007-2008 Scott Dorman (sj_dorman@hotmail.com)
'
' This library is free software; you can redistribute it and/or
' modify it under the terms of the Microsoft Public License (Ms-PL).
'
' This library is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
' Microsoft Public License (Ms-PL) for more details.
'------------------------------------------------------------------------------
Imports System
Imports EnvDTE
Imports EnvDTE80
Imports EnvDTE90
Imports System.Diagnostics

Public Module ProjectUtilities

    Private Class ProjectGuids
        Public Const vsWindowsCSharp As String = "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}"
        Public Const vsWindowsVBNET As String = "{F184B08F-C81C-45F6-A57F-5ABD9991F28F}"
        Public Const vsWindowsVisualCPP As String = "{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}"
        Public Const vsWebApplication As String = "{349C5851-65DF-11DA-9384-00065B846F21}"
        Public Const vsWebSite As String = "{E24C65DC-7377-472B-9ABA-BC803B73C61A}"
        Public Const vsDistributedSystem As String = "{F135691A-BF7E-435D-8960-F99683D2D49C}"
        Public Const vsWCF As String = "{3D9AD99F-2412-4246-B90B-4EAA41C64699}"
        Public Const vsWPF As String = "{60DC8134-EBA5-43B8-BCC9-BB4BC16C2548}"
        Public Const vsVisualDatabaseTools As String = "{C252FEB5-A946-4202-B1D4-9916A0590387}"
        Public Const vsDatabase As String = "{A9ACE9BB-CECE-4E62-9AA4-C7E7C5BD2124}"
        Public Const vsDatabaseOther As String = "{4F174C21-8C12-11D0-8340-0000F80270F8}"
        Public Const vsTest As String = "{3AC096D0-A1C2-E12C-1390-A8335801FDAB}"
        Public Const vsLegacy2003SmartDeviceCSharp As String = "{20D4826A-C6FA-45DB-90F4-C717570B9F32}"
        Public Const vsLegacy2003SmartDeviceVBNET As String = "{CB4CE8C6-1BDB-4DC7-A4D3-65A1999772F8}"
        Public Const vsSmartDeviceCSharp As String = "{4D628B5B-2FBC-4AA6-8C16-197242AEB884}"
        Public Const vsSmartDeviceVBNET As String = "{68B1623D-7FB9-47D8-8664-7ECEA3297D4F}"
        Public Const vsWorkflowCSharp As String = "{14822709-B5A1-4724-98CA-57A101D1B079}"
        Public Const vsWorkflowVBNET As String = "{D59BE175-2ED0-4C54-BE3D-CDAA9F3214C8}"
        Public Const vsDeploymentMergeModule As String = "{06A35CCD-C46D-44D5-987B-CF40FF872267}"
        Public Const vsDeploymentCab As String = "{3EA9E505-35AC-4774-B492-AD1749C4943A}"
        Public Const vsDeploymentSetup As String = "{978C614F-708E-4E1A-B201-565925725DBA}"
        Public Const vsDeploymentSmartDeviceCab As String = "{AB322303-2255-48EF-A496-5904EB18DA55}"
        Public Const vsVSTA As String = "{A860303F-1F3F-4691-B57E-529FC101A107}"
        Public Const vsVSTO As String = "{BAA0C2D2-18E2-41B9-852F-F413020CAA33}"
        Public Const vsSharePointWorkflow As String = "{F8810EC1-6754-47FC-A15F-DFABD2E3FA90}"
    End Class

    '' Defines the valid target framework values.
    Enum TargetFramework
        Fx40 = 262144
        Fx35 = 196613
        Fx30 = 196608
        Fx20 = 131072
    End Enum

    '' Change the target framework for all projects in the current solution.
    Sub ChangeTargetFrameworkForAllProjects()
        Dim project As EnvDTE.Project
        Dim clientProfile As Boolean = False

        Write("--------- CHANGING TARGET .NET FRAMEWORK VERSION -------------")
        Try
            If Not DTE.Solution.IsOpen Then
                Write("There is no solution open.")
            Else              
                Dim targetFrameworkInput As String = InputBox("Enter the target framework version (Fx40, Fx35, Fx30, Fx20):", "Target Framework", "Fx40")
                Dim targetFramework As TargetFramework = [Enum].Parse(GetType(TargetFramework), targetFrameworkInput)

                If targetFramework = ProjectUtilities.TargetFramework.Fx35 Or targetFramework = ProjectUtilities.TargetFramework.Fx40 Then
                    Dim result As MsgBoxResult = MsgBox("The .NET Framework version chosen supports a Client Profile. Would you like to use that profile?", MsgBoxStyle.Question Or MsgBoxStyle.YesNo, "Target Framework Profile")
                    If result = MsgBoxResult.Yes Then
                        clientProfile = True
                    End If
                End If

                For Each project In DTE.Solution.Projects
                    If project.Kind <> Constants.vsProjectKindSolutionItems And project.Kind <> Constants.vsProjectKindMisc Then
                        ChangeTargetFramework(project, targetFramework, clientProfile)
                    Else
                        For Each projectItem In project.ProjectItems
                            If Not (projectItem.SubProject Is Nothing) Then
                                ChangeTargetFramework(projectItem.SubProject, targetFramework, clientProfile)
                            End If
                        Next

                    End If
                Next
            End If
        Catch ex As System.Exception
            Write(ex.Message)
        End Try
    End Sub

    '' Change the target framework for a project.
    Function ChangeTargetFramework(ByVal project As EnvDTE.Project, ByVal targetFramework As TargetFramework, ByVal clientProfile As Boolean) As Boolean
        Dim changed As Boolean = True

        If project.Kind = Constants.vsProjectKindSolutionItems Or project.Kind = Constants.vsProjectKindMisc Then
            For Each projectItem In project.ProjectItems
                If Not (projectItem.SubProject Is Nothing) Then
                    ChangeTargetFramework(projectItem.SubProject, targetFramework, clientProfile)
                End If
            Next
        Else
            Try
                If IsLegalProjectType(project) Then
                    SetTargetFramework(project, targetFramework, clientProfile)
                Else
                    Write("Skipping project: " + project.Name + " (" + project.Kind + ")")
                End If
            Catch ex As Exception
                Write(ex.Message)
                changed = False
            End Try
        End If

        Return changed
    End Function

    '' Determines if the project is a project that actually supports changing the target framework.
    Function IsLegalProjectType(ByVal proejct As EnvDTE.Project) As Boolean
        Dim legalProjectType As Boolean = True

        Select Case proejct.Kind
            Case ProjectGuids.vsDatabase
                legalProjectType = False
            Case ProjectGuids.vsDatabaseOther
                legalProjectType = False
            Case ProjectGuids.vsDeploymentCab
                legalProjectType = False
            Case ProjectGuids.vsDeploymentMergeModule
                legalProjectType = False
            Case ProjectGuids.vsDeploymentSetup
                legalProjectType = False
            Case ProjectGuids.vsDeploymentSmartDeviceCab
                legalProjectType = False
            Case ProjectGuids.vsDistributedSystem
                legalProjectType = False
            Case ProjectGuids.vsLegacy2003SmartDeviceCSharp
                legalProjectType = False
            Case ProjectGuids.vsLegacy2003SmartDeviceVBNET
                legalProjectType = False
            Case ProjectGuids.vsSharePointWorkflow
                legalProjectType = False
            Case ProjectGuids.vsSmartDeviceCSharp
                legalProjectType = True
            Case ProjectGuids.vsSmartDeviceVBNET
                legalProjectType = True
            Case ProjectGuids.vsTest
                legalProjectType = False
            Case ProjectGuids.vsVisualDatabaseTools
                legalProjectType = False
            Case ProjectGuids.vsVSTA
                legalProjectType = True
            Case ProjectGuids.vsVSTO
                legalProjectType = True
            Case ProjectGuids.vsWCF
                legalProjectType = True
            Case ProjectGuids.vsWebApplication
                legalProjectType = True
            Case ProjectGuids.vsWebSite
                legalProjectType = True
            Case ProjectGuids.vsWindowsCSharp
                legalProjectType = True
            Case ProjectGuids.vsWindowsVBNET
                legalProjectType = True
            Case ProjectGuids.vsWindowsVisualCPP
                legalProjectType = True
            Case ProjectGuids.vsWorkflowCSharp
                legalProjectType = False
            Case ProjectGuids.vsWorkflowVBNET
                legalProjectType = False
            Case ProjectGuids.vsWPF
                legalProjectType = True
            Case Else
                legalProjectType = False
        End Select
        Return legalProjectType
    End Function

    '' Sets the target framework for the project to the specified framework.
    Sub SetTargetFramework(ByVal project As EnvDTE.Project, ByVal targetFramework As TargetFramework, ByVal clientProfile As Boolean)
        Dim currentTargetFramework As TargetFramework = CType(project.Properties.Item("TargetFramework").Value, TargetFramework)
        Dim targetMoniker As String = GetTargetFrameworkMoniker(targetFramework, clientProfile)
        Dim currentMoniker As String = project.Properties.Item("TargetFrameworkMoniker").Value

        If currentMoniker <> targetMoniker Then
            Write("Changing project: " + project.Name + " from " + currentMoniker + " to " + targetMoniker + ".")
            project.Properties.Item("TargetFrameworkMoniker").Value = targetMoniker
            project.Properties.Item("TargetFramework").Value = targetFramework
        Else
            Write("Skipping project: " + project.Name + ", already at the correct target framework.")
        End If
    End Sub

    Function GetTargetFrameworkMoniker(ByVal targetFramework As TargetFramework, ByVal clientProfile As Boolean) As String
        Dim moniker As String = ".NETFramework,Version=v"
        Select Case targetFramework
            Case ProjectUtilities.TargetFramework.Fx20
                moniker += "2.0"

            Case ProjectUtilities.TargetFramework.Fx30
                moniker += "3.0"

            Case ProjectUtilities.TargetFramework.Fx35
                moniker += "3.5"

            Case ProjectUtilities.TargetFramework.Fx40
                moniker += "4.0"

        End Select

        If clientProfile Then
            moniker += ",Profile=Client"
        End If

        Return moniker
    End Function

    '' Writes a message to the output window
    Sub Write(ByVal s As String)
        Dim out As OutputWindowPane = GetOutputWindowPane("Change Target Framework", True)
        out.OutputString(s)
        out.OutputString(vbCrLf)
    End Sub

    '' Gets an instance of the output window
    Function GetOutputWindowPane(ByVal Name As String, Optional ByVal show As Boolean = True) As OutputWindowPane
        Dim win As Window = DTE.Windows.Item(EnvDTE.Constants.vsWindowKindOutput)
        If show Then win.Visible = True
        Dim ow As OutputWindow = win.Object
        Dim owpane As OutputWindowPane
        Try
            owpane = ow.OutputWindowPanes.Item(Name)
        Catch e As System.Exception
            owpane = ow.OutputWindowPanes.Add(Name)
        End Try
        owpane.Activate()
        Return owpane
    End Function

End Module

A PowerShell script that I used to do mine.我曾经做过的一个 PowerShell 脚本。 Admittedly bruce force-ish.不可否认,布鲁斯力-ish。

Get-ChildItem . -Recurse -Filter *.*proj |ForEach {
    $content = Get-Content $_.FullName
    $content |ForEach {
        $_.Replace("<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>", "<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>")
    } |Set-Content $_.FullName
}

There's always the simple.总是有简单的。 A decent text editor such as notepad++ will include a find/replace in files function.一个不错的文本编辑器,例如记事本++,将在文件中包含查找/替换功能。 Just search for the current version string in your csproj/vbproj files:只需在您的 csproj/vbproj 文件中搜索当前版本字符串:

<TargetFrameworkVersion>v3.5</TargetFrameworkVersion>

and replace with the new version并替换为新版本

<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>

Good idea to check out first though...不过,先检查一下是个好主意......

来自 bash:

$find . -name "*.csproj" -exec sed -b -i "s,<TargetFrameworkVersion>[^<]*</TargetFrameworkVersion>,<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>," {} \;

I think by far the easiest way to do this is using a search and replace tool.我认为到目前为止最简单的方法是使用搜索和替换工具。 It is an advantage if it supports regex.如果它支持正则表达式,这是一个优势。

There must be quite a few out there - the first one I tested worked for me, though: http://www.ecobyte.com/replacetext/那里肯定有很多 - 不过我测试的第一个对我有用: http : //www.ecobyte.com/replacetext/

There is a note saying it has some issues on Win7, but I didn't experience that.有一个说明说它在Win7上有一些问题,但我没有遇到过。

Step by step instructions in that tool:该工具中的分步说明:

  1. Replace |替换 | Add Group |添加组 | Name it (eg "MyGroup")命名(例如“MyGroup”)
  2. Right-Click MyGroup |右键单击我的群组 | Add File(s)...添加文件...
  3. Choose your source (eg Use Folder, browse to root folder of the projects you want to change)选择您的来源(例如使用文件夹,浏览到您要更改的项目的根文件夹)
  4. Set the Include File Filter if necessary (eg *.csproj)如有必要,设置包含文件过滤器(例如 *.csproj)
  5. Right-Click the row below Original Text |右键单击原始文本下方的行 | Advanced Edit...高级编辑...
  6. Enter your regular expression in Search Text Box (eg <TargetFrameworkVersion>.*</TargetFrameworkVersion> )在搜索文本框中输入您的正则表达式(例如<TargetFrameworkVersion>.*</TargetFrameworkVersion>
  7. Select "Regular Expression Search" in the combobox below the Search Text在搜索文本下方的组合框中选择“正则表达式搜索”
  8. Enter Replacement Text (eg <TargetFrameworkVersion>4.0</TargetFrameworkVersion> )输入替换文本(例如<TargetFrameworkVersion>4.0</TargetFrameworkVersion>
  9. Choose Destination and Backup settings (will create a backup by default)选择目标和备份设置(默认情况下会创建一个备份)
  10. Start Replacing (Ctrl+R)开始替换 (Ctrl+R)

Now If for some reason you need to do this in code, I would probably be able to do that as well (it's how I found this question).现在,如果出于某种原因您需要在代码中执行此操作,我可能也可以执行此操作(这就是我发现此问题的方式)。 In that case, please request it in a comment.在这种情况下,请在评论中提出要求。


在此处输入图片说明

Conditional regexes are giving me a headache. 条件正则表达式让我头疼。 So here is a coded solution for search/replace (I'm avoiding EnvDTE as long as possible).所以这是一个用于搜索/替换的编码解决方案(我尽可能避免使用 EnvDTE)。

Order does not seem to matter for the project file entries:项目文件条目的顺序似乎无关紧要

Try something along those lines:沿着这些方向尝试一些事情:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;

namespace TextReplaceDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            try
            {
                ReplaceTargetFrameworkVersion("v4.0", "c:/projekt/2005", "*.csproj");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// Inserts the denoted targetFramework into all occurrences of TargetFrameworkVersion.
        /// If the TargetFrameworkVersion is not present in the file, the method searches for the 
        /// OutputType tag, which should be present, and inserts the TargetFrameworkVersion before that.
        /// </summary>
        /// <param name="targetFramework">New target framework (e.g. "v4.0")</param>
        /// <param name="rootDirectory">Root directory for the file search (e.g. "c:\Projects\2005")</param>
        /// <param name="fileSearchPattern">Pattern to find the project files (e.g. "*.csproj). 
        /// Will get all files for empty parameter.</param>
        public static void ReplaceTargetFrameworkVersion(string targetFramework, string rootDirectory, string fileSearchPattern)
        {
            if (string.IsNullOrEmpty(targetFramework)) throw new ArgumentNullException("targetFramework");
            if (string.IsNullOrEmpty(rootDirectory)) throw new ArgumentNullException("rootDirectory");
            if (string.IsNullOrEmpty(fileSearchPattern)) fileSearchPattern = "*.*";

            string regexPattern = "<TargetFrameworkVersion>.*</TargetFrameworkVersion>";
            string insertText = string.Format("<TargetFrameworkVersion>{0}</TargetFrameworkVersion>", targetFramework);
            string alternativeMarker = "<OutputType>";

            // get all files
            List<FileInfo> files = GetAllFiles(rootDirectory, fileSearchPattern);

            // iterate over found files
            foreach (var file in files)
            {
                string fileContent = File.ReadAllText(file.FullName);
                Match match = Regex.Match(fileContent, regexPattern);
                string newfileContent = null;
                if (match.Success)
                {
                    // replace <TargetFrameworkVersion>
                    newfileContent = fileContent.Replace(match.Value, insertText);
                }
                else if (fileContent.Contains(alternativeMarker))
                {
                    // create <TargetFrameworkVersion>
                    newfileContent = fileContent.Replace(alternativeMarker,
                        insertText + Environment.NewLine + "    " + alternativeMarker);
                }

                // overwrite file
                if (newfileContent != null)
                    File.WriteAllText(file.FullName, newfileContent);
            }
        }


        /// <summary>
        /// Recursive function to find all files in a directory by a searchPattern
        /// </summary>
        /// <param name="path">Path to the root directory</param>
        /// <param name="searchPattern">Pattern for the file search, e.g. "*.txt"</param>
        public static List<FileInfo> GetAllFiles(string path, string searchPattern)
        {
            List<FileInfo> files = new List<FileInfo>();

            DirectoryInfo dir = new DirectoryInfo(path);

            if (dir.Exists)
            {
                // get all files in directory
                files.AddRange(dir.GetFiles(searchPattern));

                // get all files of subdirectories
                foreach (var subDir in dir.GetDirectories())
                {
                    files.AddRange(GetAllFiles(subDir.FullName, searchPattern));
                }
            }
            return files;
        }
    }
}

You can use a macro to do this, or remember that the VS project files are text files, which means a simple global search and replace can achieve the same, and is a more general technique for making the same change to lots of project files.您可以使用宏来执行此操作,或者记住 VS 项目文件是文本文件,这意味着简单的全局搜索和替换可以实现相同的效果,并且是对大量项目文件进行相同更改的更通用技术。

First back up an existing project file, then make the change you want (eg, change the target framework).首先备份现有的项目文件,然后进行所需的更改(例如,更改目标框架)。 Use WinDiff or WinMerge to compare the new project file with the back up.使用 WinDiff 或WinMerge将新项目文件与备份文件进行比较。 This will tell you the change you need to make.这将告诉您需要进行的更改。 Then use the Visual Studio IDE's Find and Replace in Files function to make the change to all your project files.然后使用 Visual Studio IDE 的“在文件中查找和替换”功能对所有项目文件进行更改。

An alternative with no external tools (and the ability to change other settings, eg ToolsVersion):没有外部工具的替代方案(以及更改其他设置的能力,例如 ToolsVersion):

  1. Using Visual Studio, create a new c# console project 'ManageCSProjFiles' (or whatever name you like) in a temporary directory.使用 Visual Studio,在临时目录中创建一个新的 c# 控制台项目“ManageCSProjFiles”(或您喜欢的任何名称)。 Be sure to check 'Place solution and project in same directory'请务必选中“将解决方案和项目放在同一目录中”
  2. Remove Program.cs and Properties/AssemblyInfo.cs from the project.从项目中删除 Program.cs 和 Properties/AssemblyInfo.cs。 There is no need to ever compile the project.无需编译项目。
  3. Save the project and close Visual Studio.保存项目并关闭 Visual Studio。
  4. Using a text editor open ManageCSProjFiles.csproj.使用文本编辑器打开 ManageCSProjFiles.csproj。 Add the following lines at the bottom, before the last line:在底部添加以下几行,在最后一行之前:
  <ItemGroup>
    <None Include="**\*.csproj" />
  </ItemGroup>
  1. Copy ManageCSProjFiles.sln and ManageCSProjFiles.csproj to the topmost directory of your solution tree.将 ManageCSProjFiles.sln 和 ManageCSProjFiles.csproj 复制到解决方案树的最顶层目录。
  2. If you load the ManageCSProjFiles solution in Visual Studio, it will now show all your .csproj files and you can change them with the search/replace tools in Visual Studio.如果您在 Visual Studio 中加载 ManageCSProjFiles 解决方案,它现在将显示您的所有 .csproj 文件,您可以使用 Visual Studio 中的搜索/替换工具更改它们。

This can easily be extended for other project types.这可以很容易地扩展到其他项目类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM