I would like to create some 'extension-based HTML helpers' in a separate (C#) project. Those html helpers are for example described at www.asp.net.
Because the methods are an extensions on the HtmlHelper
class and the HtmlHelper
class is inside the System.Web.Mvc Assembly, the project needs a reference to this assembly. But then then the project is dependent of a specific MVC version (3, 4, 5 etc).
I would like to write MVC helpers who are MVC version independent (but extension based). Is this possible?
I am aware of the <bindingRedirect />
config, but I would be nice if the client (the project who uses the MVC helpers) isn't forced to use this <bindingRedirect />
element.
You shouldn't worry about having to worry about the client having to add binding redirects. This used to be the problem a few years ago that Nuget solved.
So instead of sharing a dll, share a nuget package. You will probably need multiple versions as binding redirects don't work from MVC 3 to MVC 5 (because of medium trust changes removal in MVC 5). So you will end up with two nuget packages in total (search for AutoFac MVC on nuget.org to see what they did), or just support MVC 5 and above, it's been out for over a year already.
Place the nuget package in either nuget.org (or you can use a private nuget feed), and make sure your package has a dependency on MVC with the right versions as major and minor. You might need a few of them to match the MVC versions.
The nice thing about nuget is that for the versions that are compatible (say MVC 5, 5.1, 5.2, 5.2.2 etc.) with your code you will just need a single dll and Nuget will automatically add the binding redirects without the end user having to type them in.
How to create a nuget package
I am not sure if there is a better way to do "conditional dependencies", but the way I do it is to hand edit the .csproj file. For example, here is a sample from the MvcSiteMapProvider project:
<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>
And then of course, there are constants for MVC2, MVC3, MVC4, and MVC5 used throughout the code, as well to reuse the same codebase for each version. When the project is built, the build script passes the MVC version as a parameter and a separate DLL is created for each MVC version.
Direct link to the csproj file
NOTE: Although this works fine, Visual Studio shows the non-selected references in the list of references with a yellow icon, which can be somewhat disconcerting. I haven't found a way to make this work in a way that displays nicely in Visual Studio or that can actually be edited with Visual Studio's tools.
Full Disclosure: I am a major contributor to MvcSiteMapProvider.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With