Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Supporting Multiple Versions of a Compilation Dependency (vNext)

I contribute to an open source library that currently supports MVC 2 - MVC 5, and I would like to support MVC 6 (and beyond) as well. To support each version of MVC, we take advantage of the Condition feature of MSBuild to include the correct version of MVC and its dependencies when doing a build (depending on the value of DefineConstants). This makes it possible to use a single project file for all supported versions of MVC, by creating an individual DLL for each MVC version using the same project file and source code.

<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>

I have looked at the project structure of ASP.NET 5/MVC 6 and have already resigned to use a project.json file rather than a .csproj file for MVC 6. However, I read the project.json documentation and there doesn't appear to be a way to support multiple versions of MVC with a single project.json file.

Ideally, I would like to ditch MSBuild and use Roslyn for every MVC version (including MVC 2 - MVC 5) going forward. But is there a way to support multiple MVC versions without having to create a project file (and project directory since all of them would have to be named project.json) for every MVC version? If not, is there another way to not have to duplicate all of the project.json configuration 5 times?

like image 918
NightOwl888 Avatar asked Aug 23 '15 07:08

NightOwl888


1 Answers

I found a (not so good) workaround to the issue. I still would like to know if there is a better way.

The solution I came up with is to use globbing to include files to compile outside of the project directory. For example, my project structure looks like this:

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

All of the .cs files are included in MyProject. And then my project.json file looks like this:

{
  "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"
      }
    }
  }
}

However, there is another issue with this solution - Visual Studio 2015 does not show any of the files in MyProject.MVC6 because they are only included for compilation. Also, it is not possible to include the .csproj file because this causes the whole project not to compile.

So, I came up with another workaround - to include a project.json file and MyProject.DNX.Debug.xproj file inside of the actual project and I include this one into the MVC6 solution instead of the .csproj file.

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

These files serve only to provide a way to debug them in MVC6, the idea is that when MVC7 comes out I will be able to create another project folder and then swap this configuration as needed for which version to debug.

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

This is still very far from ideal. Please provide a better answer if there is one.

like image 154
NightOwl888 Avatar answered Oct 30 '22 03:10

NightOwl888