Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 4 - Use Razor Views in Class Library

I am trying to have MVC 4 Razor View in a Class Library Project.

I added Web.Config files to my class library root folder and views folder but in my view @model is still not recongnized.

I also added the Microsoft.AspNet.Mvc package to the project to.

Does anyone knows how to solve this?

This is my Web.Config files:

1 - Views Folder

<?xml version="1.0"?>

<configuration>
  <configSections>
    <sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
      <section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
    </sectionGroup>
  </configSections>

  <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

  <appSettings>
    <add key="webpages:Enabled" value="false" />
  </appSettings>

  <system.web>
    <httpHandlers>
      <add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
    </httpHandlers>

    <!--
        Enabling request validation in view pages would cause validation to occur
        after the input has already been processed by the controller. By default
        MVC performs request validation before a controller processes the input.
        To change this behavior apply the ValidateInputAttribute to a
        controller or action.
    -->
    <pages
        validateRequest="false"
        pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
        userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
      <controls>
        <add assembly="System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
      </controls>
    </pages>
  </system.web>

  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />

    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
</configuration>

2 - Root folder

<?xml version="1.0" encoding="utf-8"?>
<!--
  For more information on how to configure your ASP.NET application, please visit
  http://go.microsoft.com/fwlink/?LinkId=169433
  -->
<configuration>
  <appSettings>
    <add key="webpages:Version" value="2.0.0.0" />
    <add key="webpages:Enabled" value="false" />
    <add key="PreserveLoginUrl" value="true" />
    <add key="ClientValidationEnabled" value="true" />
    <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  </appSettings>
  <system.web>
    <httpRuntime targetFramework="4.5" />
    <compilation debug="true" targetFramework="4.5" />
    <pages>
      <namespaces>
        <add namespace="System.Web.Helpers" />
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
        <add namespace="System.Web.WebPages" />
      </namespaces>
    </pages>
  </system.web>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <handlers>
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" />
      <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" />
      <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0" />
      <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="GET,HEAD,POST,DEBUG,PUT,DELETE,PATCH,OPTIONS" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
    </handlers>
  </system.webServer>
</configuration>

Does anyone knows what am I missing?

Thank You,

Miguel

like image 363
Miguel Moura Avatar asked Oct 22 '22 09:10

Miguel Moura


2 Answers

It turns out the easy solution is to create it as a web application, but that might not sit well with everyone.

First Attempt

I myself also had a class library I wanted to create some controls in, and yet I wanted to have a working Razor View, with full intellisence support. The trick to that is:

  1. Add References (for MVC)
  2. Add ProjectTypeGuids to .csproj (edit as text) after ProjectGUID: <ProjectTypeGuids>{349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}</ProjectTypeGuids>
  3. Add a .cshtml razor view file (it wont' work right until the next parts)
  4. Add a Web.Config file (see your View folder web.config)
  5. Change Project Properties Build output path to bin\ (not bin\Debug)
  6. Clean and Build Solution

Gets You almost there (comments mention the Bin folder issue): https://conficient.wordpress.com/2013/11/27/asp-net-razor-views-in-class-libraries/

Another Guide with Bin included: http://thetoeb.de/2014/01/05/enabling-mvc5-intellisense-in-a-classlibrary-project/

But the only point to any of that is if you're avoiding having a real ASP.Net MVC site. So, now you'll need something to run it... and there are options, but that's beyond this entry.


Almost There

If you just want your views to be compiled, and re-used as a project by many other real ASP.Net MVC projects, then instead you could just Use Razor Generator , but even still here, you might not want to create your project as a Class library, because such just isn't fun...

  1. Install VS Extension for Razor Generator
  2. Add new Class Library Project
  3. Add NuGet package to your library for RazorGenerator.Mvc
  4. Add NuGet package to your library for PrecompiledMvcViewEngineContrib
  5. Create a Views folder and a controller named folder under that in your library for the virual path you want these accessed as
  6. Move any views to that new \Views\ControllerName\ folder
  7. Set all these library views to Custom Tool RazorGenerator (right-click properties on view)
  8. Add reference to your library from your real ASP.Net MVC web application

From there I often have problem still. I'll be stuck in C# 2.0 unless I add Microsoft.CodeDom.Providers.DotNetCompilerPlatform nuget package. Which is for 4.5, so for 4.6.x one could modify the new codedom section in app.config to

  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701">
        <providerOption name="CompilerVersion" value="v4.0"/>
      </compiler>
      <compiler language="vb;vbs;visualbasic;vbscript" extension=".vb" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.VBCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:14 /nowarn:41008 /define:_MYTYPE=\&quot;Web\&quot; /optionInfer+"/>
    </compilers>
  </system.codedom>

Now you can use "var" as an implict type and other modern C# features.

Next I had an issue with System.Linq extension methods not being found despite having referenced it... and life just isn't quite right... if you want it all... But that is a start if that's a path you want to walk further down.


Simplest Option

But if you take the Advice of the Razor Generator crew, and actually install Razor Generator on top of a regular MVC Web Application (just create your "library" as one), then almost none of this work is necessary...

  1. Have a Main real MVC ASP.Net site
  2. Create a new MVC ASP.Net site to act as your "library", so you don't have to mess with things as much
  3. Install Nuget Package for RazorGenerator.MVC to "library"
  4. Install Nuget Package for PrecompiledMvcViewEngineContrib to "library"
  5. Move views to similiar structure in library and mark as Custom Tool RazorGenerator
  6. Reference your "library" from main site, and it'll all work with less hassle this way.

The beauty is that your referenced "library" has App Start code that will run at app start of your main app, and that will register the PreCompiledViewEngine, which knows about virual paths, and not just physical paths. Then your RazorGenerator Custom Tool views will define their virtual path, and when the view path is resolved, it can find them.


Nice Reference on the topic: https://www.c-sharpcorner.com/UploadFile/97fc7a/article-precompiled-razor-view-using-razorgenerator-mvc-and/

like image 74
Greg Avatar answered Oct 26 '22 21:10

Greg


Your project must be a Web Application for intellisense to work properly. Web Application is just a special class library.

like image 26
Max Toro Avatar answered Oct 26 '22 21:10

Max Toro