Globally add "<#Assembly>" and "<#Import Namespace>" to Asp.net MVC views - asp.net-mvc

Instead of writing
<# Import Namespace="Microsoft.SharePoint" %>
on every view I create I know I can easily just edit my web.config file and add this:
...
<pages>
<namespaces>
<add namespace="Microsoft.SharePoint" />
</namespaces>
</pages>
But this doesn't seem to work in design time. Visual Studio 2010 is not able to see SPContext unless I add these two lines on top of my view as well:
<%# Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%# Import Namespace="Microsoft.SharePoint" %>
So how do I add assemblies globally as well as import namespaces so VS will be able to resolve classes/objects?

You also need to add the assembly to the <assemblies> section of the <compilation> section under <system.web>:
<compilation debug="false" targetFramework="4.0">
<assemblies>
<add
assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" />
</assemblies>
</compilation>
Your targetFramework and debug attribute values may vary according to the framework version you're targetting and whether you're debugging or not.

It should work if you add the assembly in the Web.config, too.

Related

MVC3 Contrib not working in razor pages, but is fine in controllers

I've got MVC3Contrib installed.. strange thing is, the examples show that I could use them to render links in razor pages, something like this:
#( Html.ActionLink<HomeController>(c => c.Index(), "Go home") )
This somehow never works for me.. Although, in my controllers, I can do
return new RedirectToRoute<MyController>(c => c.Index());
just fine.. The error I get is The non generic link ActionLink cannot be used with type arguments
It is as if the contrib isn't installed.. Infact, I don't even see the mvc future action link option in the intellisense
I just can't figure out why it is behaving so, Do I need to do anything extra here?
If you need any other info, please ask, I don't know what else I should be giving out here..
EDIT
Oh btw, I'm using MVC Areas, if that matters, I have about 3 areas and then the main controllers etc..
Make sure that the Microsoft.Web.Mvc namespace is in scope which is where thos extension methods are defined:
or add it to the <namespaces> section of your ~/Views/web.config file in order to bring this namespace in all views:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.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" />
<add namespace="Microsoft.Web.Mvc" />
</namespaces>
</pages>
</system.web.webPages.razor>
I suppose that in your controller code you have added using MvcContrib.ActionResults; which is why you are able to see the RedirectToRouteResult<T> class available.

mvc3 razor page don't find Namespace

I read a lot of similar questions out there, but I can't solve my particular problem...
In my MVC3 project I use an external library. I can use this library everywhere, but not in my razor views.
So, reading some similar question on SO, I found out that I should register this library into the <system.web><compilation><assemblies> section.
Trying to do this, I ended up with a portion of my web.config like this
<compilation debug="true" targetFramework="4.0">
<assemblies>
... <!-- default assembly registration, like System.Web.something -->
<add assembly="MailBee.Net.dll, Version=7.1.4.348, Culture=neutral, PublicKeyToken=cd85b70fb26f9fc1" />
</assemblies>
</compilation>
But still don't work... or to be more precise, this broke up all the project at runtime. If I launch the project, it crashes telling me Impossibile to load assembly 'MailBee.Net.dll, Version=7.1.4.348, Culture=neutral, PublicKeyToken=cd85b70fb26f9fc1' or one of its dependency
The dll for sure is in the /bin folder of the web application and, deleting the declaration in the web.config file, I cau use it in all the project but in the views page.
Any idea?
There are a few possible problems:
MailBee.Net.dll has a dependancey/requirement on another dll that is not in your solution.
MailBee.Net.dll is not the same x86/x64 version as your project/hosting solution (visual studio/iis express)
Additionally, in your web.config file located in the Views directory you should add something like the following:
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory,
System.Web.Mvc,
Version=3.0.0.0,
Culture=neutral,
PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage" />
<namespaces>
<add namespace="<NamespaceYouNeedInYourViews>" />
</namespaces>
</pages>
</system.web.webPages.razor>
I got it!
It's not a problem of dependencies, nor a problem of declaring the assembly or the namespace somewhere... it's just that that library, for some reason, is not copied into the bin folder when building the project!
Or better, the reason is that the property "Copy local" on the referenced library is set to false, but I have no idea why: every other third party library I tried with haven't this behaviour...

ASP.NET Views: Avoiding using <%# Assembly... in every .aspx

Virtually every .aspx page I have in my web site needs to have this at its top to function correctly:
<%# Assembly Name="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" %>
Is there anyway I can avoid having to declare this in the .aspx view for every page? Isn't there some way I can declare this globally for all .aspx views? Maybe something in the web.config?
Add it to assemblies
<assemblies>
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</assemblies>
The #Assembly directive correspond to assemblies tag in web.config not namespace tag. Check MSDN reference
You can declare it in web.config in the assemblies section, like this:
<system.web>
<compilation>
<assemblies>
<add assembly="System.Web.Mvc, Version=3.0.0.0 ... "/>
</assemblies>
</compilation>
</system.web>
However, according to the MSDN docs:
Assemblies that reside in your Web application's \Bin directory are automatically linked to ASP.NET files within that application. Such assemblies do not require the # Assembly directive. You can disable this functionality by removing the following line from the section of your application's Web.config file:
<add assembly="*"/>
As others have pointed out, you can declare this in the web.config pages section.
Another alternative (if its available to you) is to use the new Razor View engine. It not only removes this type of code, but also provides cleaner, overall syntax. Of course, I realize this may not be a viable solution as you may be limited by your current technology/customer needs/etc.
An example of what you may see at the top of a Razor page is shown here:
#model Some.StronglyTyped.Model
#using Other.Libraries.To.Import
#{
ViewBag.Title = "Specific Page Title";
}
Put it in the Web.config as a global namespace. It will be available to all your pages there.
<system.web>
<pages>
<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>

Why don't my Html Helpers have intellisense?

I can't get intellisense for my own html helpers. My CustomHtmlHelpers.cs looks like this:
using System.Web.Mvc;
using System.Text;
using System.Web;
namespace laget.Web.Helpers
{
public static class CustomHtmlHelpers
{
//MY HELPERS
}
}
and in my Web.config:
<pages>
<namespaces>
<add namespace="laget.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"/>
<add namespace="System.Web.Helpers" />
</namespaces>
</pages>
If I put <#using laget.Web.Helpers> in my view, I get the intellisense issue fixed.
Should it not be enough with the code in Web.config?
Sometimes it doesn't seem to work right away. Try closing the .cshtml file, and re-opening it. Then if that doesn't work, try restarting Visual Studio. Also make sure you actually compiled your project, intellisense won't work with non-compiled helpers.
I'm pretty sure that you're not editing the correct Web.config file.
You need to add your namespace to the one in your Views directory.
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.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" />
<add namespace="laget.Web.Helpers" />
</namespaces>
</pages>
</system.web.webPages.razor>
You actually don't need to restart Visual Studio in most cases. All you need to do is close the .cshtml file and reopen it!
It needs it on the local page. I'm pretty sure this has to do with Namespace resolution. It isn't exactly sure what you are referring to without the local using statement.
I ran into this today as well. Sometimes just closing the Razor view's window in Visual Studio and re-opening it will do the trick without having to do a full Visual Studio restart.
I tried to solve an issue like this one yesterday. I had e pre-compiled dll (project name ie: MyHtmlHelpers) containing helpers and lot of other classes.
I had the assembly referenced in the web project and the all "standard"-helpers showed up in intellisense but, even though I added the namespace to both web.config in the root and in the views-folder nothing worked. When running the project helpers works, but not in intellisense.
I added a new class and wrote a new html helper inside the web project, added the namespace to web.config. And that worked.
After some hours add tried my last card, adding the MyHtmlHelpers-project to the same solution as my webproject. That did the trick. I diden't change anything in the configs just added the project to the same solution and changed the reference to point at the project insted of the compiled dll.
Isen't that strange? A VS-bug?
I found that i was adding the reference to the wrong web.config. It's not the main config but the web.config in the views directory...
So now I will show you the steps
1.Create or open an existing class library project (if you open an existing one be sure to remove the MVC5 nuget package)
2.Add the MVC (5.0) nuget package (
right click project in solution explorer -> Manage NuGet Packages -> search for MVC and install “Microsoft ASP.NET MVC”)
3.Close any and all open .cshtml files
4.Right click project -> Properties -> Build -> change Output path to your project “bin/”
5.Add the following minimal Web.config to the root of your class library project
( the web config file is solely needed for intellisense. Configuration (via Web.config)
should be done in the WebApplication hosting your ClassLibrary assembly)
6.Clean and Build the solution.
7.Open cshtml file and try now :)
I found that if it still doesn't work, you may need to go to the properties of the custom class and change the build action from "content" to "compile". That resolved it for me.
I try all of this solutions, one more thing which i didnt find is that in root web.config i must change webpages:Version from 2.0.0.0 to 3.0.0.0.
Open and close all .cshtml files and it's worked.
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />

MEF and Razor Views inside Class Library

I have a composite ASP .NET MVC 3 Razor application using MEF. Everything goes fine if I am to deploy plugins as DLL files and views (CSHTML) under the regular Views folder from the application. But this is not very clean and it won't be a real plugin if I don't place views as embedded resources within the DLL files (along with both controllers and models).
I've followed many articles (most of them are outdated). In fact there is one quite good one here on Stack Overflow: Controllers and Views inside a Class Library
I've also checked docs for VirtualPathProvider and I've been able to build a custom one that finds the file within the assembly and loads it perfectly (or at least gets the stream to it). For this I've followed the VirtualPathProvider documentation on MSDN.
There is also an implementation for VirtualFile but not yet for VirtualDirectory.
Here is the problem. I'm working with Razor views. I do know that they need config specs from the web.config file for Razor to build them. But if I embed them within the DLL this config is simply lost.
I wonder if that's why I keep getting the error:
The view at '~/Plugins/CRM.Web.Views.CRM.Index.cshtml' must derive
from WebViewPage, or WebViewPage.
Maybe I just need to add some code to make it work? Any ideas?
My preferred way to embed Razor Views in a Class Library is to copy them into the MVC website's Views/Areas folders with a post build event. Custom view locations can be specified if you override the ViewEngine or VirtualPathProvider.
The tricky part for me was getting intellisense to work in these View Class libraries. First, you must add a Web.Config to your View assembly. Note that you don't have to actually include it in your assembly. It only has to be in the assembly root directory (or views folder). Here is an example. Regard the important Assemblies/Compilation section.
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.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=3.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>
<compilation targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<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=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=3.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>
Next, you need to modify your class library's vbproj file so that all OutputPath elements point to 'bin\' instead of 'Debug\bin\' or 'Release\bin\'. This is the main difference I found between class libraries and ASP.Net web project types that can cause intellisense bugs.
If you still recieve your must inherits error, consider using #Inherits System.Web.Mvc.WebViewPage in your views. If you are not copying your views into your website project, you may be loading them from Embedded Resources using a custom ViewEngine / VirtualPathProvider. If that is the case, you definately need the Inherits so Razor knows what your view base class is unfortunately.
Good luck.
You might take a look at the following blog post.
Hossam,
The post you're talking about is what Darin has already suggested. The main down side to that approach is using the custom MvcRazorClassGenerator compiler to convert the CSHTML view files in to class files. To do so you have to set every CSHTML view in your project to Content and set the Custom Tool to MvcRazorClassGenerator.
I can't speak for LordALMMa but I did download the compiler source and gave it a shot and it doesn't exactly work the way I was hoping.
My other approach was to include the CSHTML files as Embeded Resources in the external DLL, read in the raw contents of the file and execute the view as a string (See the RazorEngine on CodeProject for an example: http://razorengine.codeplex.com/)
I didn't want to fully depend on the RazorEngine in an enterprise application because I don't know how well it is compatiable with all of the Razor syntax so I gave up on that for now.
I'm coming from a prototype I built in ASP.NET MVC 2.0 that is a multi-tennant application. On a server farm we have one instance of an application running where all clients share the same code base. In my MVC 2.0 prototype I was able to determine what "client" the request was being made for, check for a custom controller that over-rides the base (for customizations of the core code) and also check for custom views (for customizations of the core view). What this does is allow us to deploy a "plugin" per say for each client. The software detects if the client has a custom controller that matches the request as well as a custom action that matches and if it does, it uses the customized controller/action instead.
When I started migrating my prototype to MVC 3 I ran in to the same problem as LordALMMa, the error "The view at '...Index.cshtml' must derive from WebViewPage, or WebViewPage". I'll look in to placing "#inherits System.Web.Mvc.WebViewPage" on my CSHTML views and see if that gets me any closer to getting it to work.
Since I have a working MVC 2.0 prototype using MVC 3 Razor is not a top priority and I don't waste a ton of time on it. I'm sure I can port the MVC 2.0 to MVC 3.0 using the WebForms engine if we need to leverage the 4.0 Framework.
Hey I suspect you have good reasons for wanting views inside DLLs. However also consider that it is an unusual way of packaging everything into one entity.
If you are developing a plugin, these days people opt for packaging in the NUGET format, which also solves your kind of problem among other things. It has a .nupkg structure which is also one way of distributing plugins as packages and libraries.
Another solution which communities generally follow is (if they do not want something as elaborate as nuget) they code up the plugin DLLs such that, it does not use view engines like razor, instead outputs HTML all by itself using the old primitive way of Response.Write and thus become independent of cshtml files. If you still want to use cshtml - see this blog entry for precompiling those into classes.

Resources