Поддержка нескольких версий зависимостей компиляции (vNext)

Я вношу вклад в библиотеку с открытым исходным кодом, которая в настоящее время поддерживает MVC 2 - MVC 5, и я хотел бы также поддерживать MVC 6 (и далее). Чтобы поддерживать каждую версию MVC, мы используем функцию Условие MSBuild, чтобы включить правильную версию MVC и ее зависимостей при выполнении сборки (в зависимости от значения DefineConstants). Это позволяет использовать один файл проекта для всех поддерживаемых версий MVC, создавая отдельную DLL для каждой версии MVC с использованием того же файла проекта и исходного кода.

<ItemGroup Condition=" $(DefineConstants.Contains('MVC2')) ">
    <Reference Include="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
</ItemGroup>
<ItemGroup Condition=" $(DefineConstants.Contains('MVC3')) ">
    <!-- Due to the windows update MS14-059, we need this hack to ensure we can build MVC3 both on machines that have the update and those that don't -->
    <Reference Condition=" Exists('$(windir)\Microsoft.NET\assembly\GAC_MSIL\System.Web.Mvc\v4.0_3.0.0.0__31bf3856ad364e35\System.Web.Mvc.dll') " Include="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
    <Reference Condition=" !Exists('$(windir)\Microsoft.NET\assembly\GAC_MSIL\System.Web.Mvc\v4.0_3.0.0.0__31bf3856ad364e35\System.Web.Mvc.dll') " Include="System.Web.Mvc, Version=3.0.0.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Mvc.3.0.20105.1\lib\net40\System.Web.Mvc.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Razor.1.0.20105.408\lib\net40\System.Web.Razor.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.WebPages.1.0.20105.408\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
    </Reference>
</ItemGroup>
<ItemGroup Condition=" $(DefineConstants.Contains('MVC4')) ">
    <Reference Include="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Mvc.4.0.20710.0\lib\net40\System.Web.Mvc.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Razor.4.0.20715.0\lib\net40\System.Web.Razor.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.WebPages.4.0.20710.0\lib\net40\System.Web.WebPages.Razor.dll</HintPath>
    </Reference>
</ItemGroup>
<ItemGroup Condition=" $(DefineConstants.Contains('MVC5')) ">
    <Reference Include="System.Web.Mvc, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Mvc.5.0.0\lib\net45\System.Web.Mvc.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.Razor.3.0.0\lib\net45\System.Web.Razor.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.dll</HintPath>
    </Reference>
    <Reference Include="System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
        <Private>True</Private>
        <HintPath>..\packages\Microsoft.AspNet.WebPages.3.0.0\lib\net45\System.Web.WebPages.Razor.dll</HintPath>
    </Reference>
</ItemGroup>

Я рассмотрел структуру проекта ASP.NET 5/MVC 6 и уже смирился с использованием файла project.json, а не файла .csproj для MVC 6. Однако я прочитал project.json, и, похоже, нет способа поддерживать несколько версий MVC с одним файлом project.json.

В идеале я хотел бы повернуть MSBuild и использовать Roslyn для каждой версии MVC (включая MVC 2 - MVC 5) в будущем. Но существует ли способ поддерживать несколько версий MVC без необходимости создавать файл проекта (и каталог проекта, поскольку все они должны быть названы project.json) для каждой версии MVC? Если нет, есть ли другой способ не дублировать всю конфигурацию project.json 5 раз?

Ответ 1

Я нашел (не очень хорошее) обходное решение проблемы. Я все еще хотел бы узнать, есть ли лучший способ.

Решение, с которым я столкнулся, состоит в том, чтобы использовать globbing для включения файлов для компиляции вне каталога проекта. Например, моя структура проекта выглядит следующим образом:

MyProject.sln
// This is where the legacy MVC2-5 support goes
MyProject/
    MyProject.csproj
// This is where the MVC6 support is compiled from
MyProject.MVC6/
    MyProject.MVC6.xproj
    project.json

Все .cs файлы включены в MyProject. И тогда мой файл project.json выглядит следующим образом:

{
  "version": "1.0.0-*",
  "description": "MyProject Description",

  "dependencies": {
    "Microsoft.AspNet.Mvc": "6.0.0-beta7",
    "Microsoft.AspNet.Mvc.TagHelpers": "6.0.0-beta7",
    "Microsoft.AspNet.Routing": "1.0.0-beta7"
  },

  "compile": "../MyProject/**/*.cs",

  "compilationOptions": {
    "define": ["MVC6", "NET46"]
  },

  "frameworks": {
    "dnxcore50": {
      "dependencies": {
        "Microsoft.CSharp": "4.0.1-beta-23225",
        "System.Collections": "4.0.11-beta-23225",
        "System.Linq": "4.0.1-beta-23225",
        "System.Runtime": "4.0.21-beta-23225",
        "System.Threading": "4.0.11-beta-23225"
      }
    }
  }
}

Однако есть еще одна проблема с этим решением - Visual Studio 2015 не отображает файлы из MyProject.MVC6, потому что они включены только для компиляции. Кроме того, невозможно включить файл .csproj, потому что это не позволяет компилировать весь проект.

Итак, я придумал другое обходное решение - включить файл project.json и файл MyProject.DNX.Debug.xproj внутри фактического проекта, и я включил его в решение MVC6 вместо файла .csproj.

MyProject.sln
// This is where the legacy MVC2-5 support goes
MyProject/
    MyProject.csproj
    MyProject.DNX.Debug.xproj
    project.json
// This is where the MVC6 support is compiled from
MyProject.MVC6/
    MyProject.MVC6.xproj
    project.json

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

MyProject.sln
// This is where the legacy MVC2-5 support goes
MyProject/
    MyProject.csproj
    MyProject.DNX.Debug.xproj 
    project.json // This project will be swapped between MVC6 and MVC7 based on compilationOptions
// This is where the MVC6 support is compiled from
MyProject.MVC6/
    MyProject.MVC6.xproj
    project.json
// This is where the MVC7 support is compiled from
MyProject.MVC7/
    MyProject.MVC7.xproj
    project.json

Это все еще очень далеко от идеала. Пожалуйста, дайте лучший ответ, если он есть.

Ответ 2

Вы можете создать один проект, который скомпилируется для нескольких сред выполнения, т.е..NET Core,.NET 4.5.1 и т.д.

  • Файл → Новый проект.
  • Веб → Библиотека классов (Пакет)
  • Отредактируйте файл project.json.
  • В элементе frameworks вы можете ввести несколько фреймворков. Здесь я нацелен на .NET Core и .NET 4.5.1:

    "frameworks": {
        "dnx451": {
            "frameworkAssemblies": {
                "System.Net.Http": "4.0.0.0",         // Example reference
            }
        },
        "dnxcore50": {
            "dependencies": {
                "System.Net.Http": "4.0.1-beta-23225" // Example reference
            }
        }
    }
    
  • Затем в вашем коде вы можете использовать предпроцессорные директивы для написания кода, специфичного для конкретной среды или среды выполнения.

    public void Foo()
    {
        #if DNX451
        // Code specific to .NET 4.5.1
        #endif
    }