Подтвердить что ты не робот

Проверка проектов Visual Studio на согласованность

У вас есть большое решение Visual Studio с десятками файлов проекта. Как бы вы подтвердили, что все проекты следуют определенным правилам в их настройках свойств и применяют эти правила, если новый проект будет добавлен. Например, проверьте, что все проекты имеют:

TargetFrameworkVersion = "v4.5"
Platform = "AnyCPU"
WarningLevel = 4
TreatWarningsAsErrors = true
OutputPath = $(SolutionDir)bin
SignAssembly = true
AssemblyName = $(ProjectFolderName)

Я знаю два метода, которые я добавлю в ответ ниже, но мне было интересно, как люди идут на этот тип теста проекта. Мне особенно интересно узнать о доступных решениях, таких как библиотеки, или создать для этого задачи, а не придумывать что-то новое или писать с нуля.

4b9b3361

Ответ 1

*. Файлы sln - это простой текст и легко разбираются, а файлы *. * proj - это xml.

Вы можете добавить фиктивный проект с шагом предварительной сборки, который анализирует sln для извлечения всех файлов проекта, проверки их параметров, печати отчета и сбоя сборки при необходимости.

Кроме того, вы должны проверить этот пост, чтобы гарантировать, что шаг предварительной сборки всегда выполняется. По сути, вы указываете пустой вывод на этапе пользовательской сборки, чтобы принудительно восстановить.

Ответ 2

В следующем списке указаны типы файлов ключей, которые автоматически добавляются в VSS, когда решение добавляется в исходный элемент управления с помощью интегрированной среды разработки Visual Studio.NET(IDE):

Файлы решений (.sln). Ключевыми элементами, содержащимися в этих файлах, являются список составных проектов, информация о зависимостях, детали конфигурации сборки и сведения о поставщике управления источником. Файлы проекта (.csproj или *.vbproj). Ключевыми элементами, содержащимися в этих файлах, являются параметры сборки сборки, ссылочные сборки (по имени и пути) и инвентарь файла. Файлы конфигурации приложения. Это файлы конфигурации на основе Extensible Markup Language (XML), используемые для управления различными аспектами поведения вашего проекта во время выполнения.

Используйте единую модель решения, когда возможно

Также смотрите: https://msdn.microsoft.com/en-us/library/ee817677.aspx,          https://msdn.microsoft.com/en-us/library/ee817675.aspx

И ДЛЯ НЕПРЕРЫВНОЙ ИНТЕГРАЦИИ:  существует множество инструментов, таких как MSBuild, Jenkins, Apache Continuum, Cruise Control (CC) и Hudson (плагин может быть расширен до С#)

Ответ 3

Это то, что у меня есть:

Один из способов сделать это - создать цель MSBuild с условиями ошибки:

<Error Condition="'$(TreatWarningsAsErrors)'!='true'" Text="Invalid project setting" />

Мне нравится этот подход, потому что он интегрирован с MSBuild и дает вам ранние ошибки, однако вам нужно изменить каждый проект, чтобы импортировать его в них, или заставить всех членов вашей команды использовать специальную командную строку с переменными среды, которые будут вводить пользовательские шаги предварительной сборки в ваши проекты во время сборки, что является болью.

Второй подход, который я знаю, - использовать некоторую библиотеку, например VSUnitTest, которая предоставляет API, чтобы проецировать свойства, с которыми вы можете протестировать. VSUnitTest в настоящее время не является открытым исходным кодом и не включен в список из службы NuGet.

Ответ 4

Вы можете написать некоторый код, чтобы открыть решение в виде текстового файла, чтобы идентифицировать все связанные с ним файлы csproj, в свою очередь, открывая каждый из них в виде XML файлов, а затем записывая модульные тесты, чтобы убедиться, что определенные узлы проекта соответствуют тому, что вы ожидаете.

Это быстрое и грязное решение, но работает для CI и дает вам гибкость, чтобы игнорировать узлы, которые вам не нужны. Это на самом деле кажется полезным. У меня есть решение с 35 проектами, которые я тоже хотел бы отсканировать.

Ответ 5

Попробуйте что-то совершенно другое: вы можете убедиться, что они согласованы по построению, генерируя их из шаблона или используя инструмент создания сборки, такой как CMake. Это может быть проще, чем пытаться сделать их последовательными после факта.

Ответ 6

В нашей работе мы используем powershell script, который проверяет настройки проекта и модифицирует их, если они неверны. Например, мы удаляем конфигурацию Debug таким образом, отключите оптимизацию С++ и поддержку SSE2. Мы запускаем его вручную, но определенно можно запустить его автоматически, например. как pre\post build step.

Ниже примера:

`function Prepare-Solution {  
param (  
    [string]$SolutionFolder
)  
$files = gci -Recurse -Path $SolutionFolder -file *.vcxproj | select -    ExpandProperty fullname  
$files | %{  
    $file = $_  
    [xml]$xml = get-content $file  

    #Deleting Debug configurations...
    $xml.Project.ItemGroup.ProjectConfiguration | ?{$_.Configuration -eq "Debug"} | %{$_.ParentNode.RemoveChild($_)} | Out-Null
    $xml.SelectNodes("//*[contains(@Condition,'Debug')]") |%{$_.ParentNode.RemoveChild($_)} | Out-Null

    if($xml.Project.ItemDefinitionGroup.ClCompile) {  
        $xml.Project.ItemDefinitionGroup.ClCompile | %{  
            #Disable SSE2
            if (-not($_.EnableEnhancedInstructionSet)){
                $_.AppendChild($xml.CreateElement("EnableEnhancedInstructionSet", $xml.DocumentElement.NamespaceURI)) | Out-Null  
            }   

            if($_.ParentNode.Condition.Contains("Win32")){  
                $_.EnableEnhancedInstructionSet = "StreamingSIMDExtensions"
            }
            elseif($_.ParentNode.Condition.Contains("x64")) {
                $_.EnableEnhancedInstructionSet = "NotSet"
            } else {
                Write-Host "Neither x86 nor x64 config. Very strange!!"
            }

            #Disable Optimization
            if (-not($_.Optimization)){  
                $_.AppendChild($xml.CreateElement("Optimization", $xml.DocumentElement.NamespaceURI)) | Out-Null  
            }   
            $_.Optimization = "Disabled" 
        } 
    } 
    $xml.Save($file);  
} }`

Ответ 7

Файл является сборкой тогда и только тогда, когда он управляется и содержит запись сборки в своих метаданных. Дополнительные сведения о сборках и метаданных см. В разделе "Манифест Ассамблеи".

Как вручную определить, является ли файл сборкой

  • Запустите Ildasm.exe (IL Disassembler).
  • Загрузите файл, который вы хотите проверить.
  • Если ILDASM сообщает, что файл не является переносимым исполняемым (PE) файлом, то это не сборка.
    Дополнительные сведения см. в разделе" Как просмотреть содержимое сборки".

Как программно определить, является ли файл сборкой

  • Вызвать метод GetAssemblyName, передав полный путь к файлу и имя файла, который вы тестируете.
  • Если выбрано исключение BadImageFormatException, файл не является сборкой.

В этом примере проверяется DLL, чтобы увидеть, является ли это сборкой.

class TestAssembly
{
static void Main()
   {

    try
    {
        System.Reflection.AssemblyName testAssembly = System.Reflection.AssemblyName.GetAssemblyName(@"C:\Windows\Microsoft.NET\Framework\v3.5\System.Net.dll");

        System.Console.WriteLine("Yes, the file is an assembly.");
    }

    catch (System.IO.FileNotFoundException)
    {
        System.Console.WriteLine("The file cannot be found.");
    }

    catch (System.BadImageFormatException)
    {
        System.Console.WriteLine("The file is not an assembly.");
    }

    catch (System.IO.FileLoadException)
    {
        System.Console.WriteLine("The assembly has already been loaded.");
    }
   }
}
  // Output (with .NET Framework 3.5 installed):
 // Yes, the file is an assembly.

Framework - самая высокая установленная версия, SP - это пакет обновления для этой версии.

  RegistryKey installed_versions =   Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP");
  string[] version_names = installed_versions.GetSubKeyNames();
  //version names start with 'v', eg, 'v3.5' which needs to be trimmed off    before conversion
  double Framework = Convert.ToDouble(version_names[version_names.Length - 1].Remove(0, 1), CultureInfo.InvariantCulture);
  int SP =  Convert.ToInt32(installed_versions.OpenSubKey(version_names[version_names.Length     - 1]).GetValue("SP", 0));

 For .Net 4.5


 using System;
 using Microsoft.Win32;


 ...


 private static void Get45or451FromRegistry()
{
using (RegistryKey ndpKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine,    RegistryView.Registry32).OpenSubKey("SOFTWARE\\Microsoft\\NET Framework  Setup\\NDP\\v4\\Full\\")) {
    int releaseKey = Convert.ToInt32(ndpKey.GetValue("Release"));
    if (true) {
        Console.WriteLine("Version: " + CheckFor45DotVersion(releaseKey));
     }
   }
 }


 ...


// Checking the version using >= will enable forward compatibility,  
// however you should always compile your code on newer versions of 
// the framework to ensure your app works the same. 
private static string CheckFor45DotVersion(int releaseKey)
{
if (releaseKey >= 393273) {
   return "4.6 RC or later";
}
if ((releaseKey >= 379893)) {
    return "4.5.2 or later";
}
if ((releaseKey >= 378675)) {
    return "4.5.1 or later";
}
if ((releaseKey >= 378389)) {
    return "4.5 or later";
}
// This line should never execute. A non-null release key should mean 
// that 4.5 or later is installed. 
return "No 4.5 or later version detected";
}

Ответ 8

Вы можете выполнить поиск и заменить метод Regex рукописным С#, Script, powershell или аналогичным. Но он имеет следующие проблемы:

  • Трудно прочитать (прочитайте ваше довольно регулярное выражение за три или более месяца)
  • Трудно улучшить (новое регулярное выражение для новой функции поиска/замены/проверки)
  • Легко сломать (новый выпуск/формат проекта сборки ms или тега не прогноза может не работать)
  • Труднее проверить (вы должны убедиться, что не произошло непреднамеренного соответствия)
  • Трудно поддерживать (из-за выше)

и следующие преимущества:

  • Не делать никакой дополнительной проверки, которая (может) позволяет ему работать над любым видом проекта (моно или визуально).
  • Не волнует \r:)

Лучше всего было бы использовать Microsoft.Build.Evaluation и создайте инструмент С#, который выполняет все ваши проверки/проверки/исправления и т.д.

Я сделал инструмент командной строки, в котором используется список исходных файлов (используется Mono), а также источники обновлений csproj, а другой - консоль содержимого csproj. Это было легко сделать, довольно просто и легко проверить.

Однако он может завершиться неудачно (как я это испытал) в проектах, модифицированных с помощью инструмента "non" Ms (например, Mono Studio) или из-за отсутствия \r.... В любом случае, вы всегда можете обработать его с помощью исключения catch и хорошего сообщения.

Здесь пример с использованием Microsoft.Build.dll(не используйте Microsof.Build.Engine, поскольку он устарел):

using System;
using Microsoft.Build.Evaluation;

internal class Program
{
    private static void Main(string[] args)
    {
        var project = new Project("PathToYourProject.csproj");
        Console.WriteLine(project.GetProperty("TargetFrameworkVersion", true, string.Empty));
        Console.WriteLine(project.GetProperty("Platform", true, string.Empty));
        Console.WriteLine(project.GetProperty("WarningLevel", true, string.Empty));
        Console.WriteLine(project.GetProperty("TreatWarningsAsErrors", true, "false"));
        Console.WriteLine(project.GetProperty("OutputPath", false, string.Empty));
        Console.WriteLine(project.GetProperty("SignAssembly", true, "false"));
        Console.WriteLine(project.GetProperty("AssemblyName", false, string.Empty));
        Console.ReadLine();
    }
}

public static class ProjectExtensions
{
    public static string GetProperty(this Project project, string propertyName, bool afterEvaluation, string defaultValue)
    {
        var property = project.GetProperty(propertyName);
        if (property != null)
        {
            if (afterEvaluation)
                return property.EvaluatedValue;
            return property.UnevaluatedValue;
        }
        return defaultValue;
    }
}

Ответ 9

Для подобных целей мы используем пользовательские фрагменты MSBuild с общими свойствами, которые мы хотим разделить между проектами (например, файл build.common.props):

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

  <PropertyGroup>
    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
    <PlatformToolset>v90</PlatformToolset>
    <OutputPath>$(SolutionDir)..\bin\$(PlatformPath)\$(Configuration)\</OutputPath>

   <!-- whatever you need here -->
  </PropertyGroup>

</Project>

И тогда мы просто включаем этот фрагмент в реальные проекты VS, мы хотим применить эти свойства к:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <CommonProps>$(SolutionDir)..\Build\build.common.props</CommonProps>
  </PropertyGroup>

  <Import Project="$(CommonProps)" />

  <!-- the rest of the project -->

</Project>

Мы обрабатываем много вещей, используя этот подход:

  • общие свойства, как вы упомянули
  • статический анализ (FxCop, StyleCop)
  • цифровой знак сборок
  • и др.

Единственный недостаток, заключающийся в том, что вам нужно включать эти фрагменты MSBuild в каждый файл проекта, но как только вы это сделаете, у вас есть все преимущества модульной системы сборки, которую легко управлять и обновлять.