HtmlHelper missing? - asp.net-mvc

I'm trying to create an Html Helper, by creating a static class as follows:
public static string Crumbs(this HtmlHelper helper, params string[] args) where T : class
{
// ... rest of code goes here.
}
And I'm invoking it like this:
<% Html.Crumbs(
Html.ActionLink("Home", "Index", "Home"),
Html.ActionLink("Lists", "Index", "User"),
Html.Encode(Model.List.Name)); %>
However, the view does not compile, as I get the following compilation error:
CS1061:
'System.Web.Mvc.HtmlHelper'
does not contain a definition for
'Crumbs' and no extension method
'Crumbs' accepting a first argument of
type
'System.Web.Mvc.HtmlHelper'
could be found (are you missing a
using directive or an assembly
reference?)
I don't get it. None of the documentation that I have mentions that you need to register the namespace of the static class anywhere. What am I doing wrong?

You need to import the namespace of your extension in you view or in web.config.
In web.config:
<pages>
<namespaces>
<add namespace="MyExtensions.Namespace"/>
In your view:
<%# Import Namespace="MyExtensions.Namespace" %>

You need to register the namespace in web.config
<system.web>
<pages>
<namespaces>
<add namespace="X.Y.Z"/>
</namespaces>
</pages>
</system.web>

Make sure you put your helper in namespace (any) that is referenced in web.config or the page itself (Import Namespace).

Related

Filename as last argument to MVC controller

I have an MVC controller with a single method which contains a few arguments, the last of which is a filename with an extension and it is this last argument which causes issues.
Say the format I wish to create is:
http://example.com/worker/90bef68f718a434bb588120e717fa29c/foo.txt
This URL will 404, however if I remove the period or add a trailing / then the handler is hit and executed normally.
Unfortunately the URL format I am trying to implement cannot accommodate either of these work arounds.
The route is defined as follows:
routes.MapRoute(
name: "Worker Handler",
url: "worker/{guid}/{fileName}",
defaults: new { controller = "Worker", action = "Index" }
);
Some reading suggested changing the url template to include {fileName} to {*fileName}, however that too did nothing to fix this.
I can suggest two solution.
First Use route like this ( FileName and FileExtention in separate argument)
routes.MapRoute(
name: "Worker Handler",
url: "worker/{guid}/{fileName}/{fileextention}",
defaults: new { controller = "Worker", action = "Index" }
);
Another solution is to add following thing in web.config.
<system.webServer>
<modules>
<remove name="UrlRoutingModule-4.0" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" preCondition="" />
</modules>
</system.webServer>
Get Help from http://www.britishdeveloper.co.uk/2010/06/dont-use-modules-runallmanagedmodulesfo.html
Route should be like this.
routes.MapRoute(
name: "Worker Handler",
url: "worker/{guid}/{fileName}",
defaults: new { controller = "Worker", action = "Index" }
);
Hope this help you.

Why is View requiring using statement

I have the following in a view I created, but the model.UserName is not recognized:
#model AcmeMVC.Models.SelectUserRolesViewModel
#{
ViewBag.Title = "User Roles";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Roles for user #Html.DisplayFor(model => model.UserName)</h2>
If I add: #using AcmeMVC.Models it will work.
But, I have this entry in the web.config in my Views folder:
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
.....
<add namespace="AcmeMVC" />
<add namespace="AcmeMVC.Models" />
.....
I thought this would make it so I didn't need the using statement, but I still do.
Does anyone have any clue on what I could be doing wrong here?
Modify this line
<h2>Roles for user #Html.DisplayFor(model => model.UserName)</h2>
So it is like this
<h2>Roles for user #Html.DisplayFor(m=>m.UserName)</h2>
The #model is directive to indicate you want to use strongly-typed model classes within your view. It is not a reference to an instance of the object. To access the model in your View you can use an expression (i.e. m=>m.Property)

MVC3 ASPX view object does not contain definition

I started this project using MVC2, but changed to the MVC3 dll.
I have an Asset entity. In the controller I have the Details ActionResult defined like this:
EDIT: (Put the correct controller code.)
public ActionResult Details(int id)
{
using (var db = new AssetsContainer())
{
return View(db.Assets.Find(id));
}
}
My Details.aspx page is defined this way:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<CITracker.Models.Asset>" %>
<%# Import Namespace="CITracker.Models" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Details
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Details</h2>
<fieldset>
<legend>Fields</legend>
<div class="display-label">Id</div>
<div class="display-field"><%: Model.Id %></div>
I get this error:
CS1061: 'object' does not contain a definition for 'Id' and no extension method 'Id' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)
Any ideas why this was working with MVC2 but fails with MVC3? I don't get develop time errors, but I do get runtime errors.
I am not sure, but looks like this is the problem. You are passing a List to the view
return View(db.Assets.ToList());
but your Inherits says
Inherits="System.Web.Mvc.ViewPage<CITracker.Models.Asset>" instead of
Inherits="System.Web.Mvc.ViewPage<IEnumerable<CITracker.Models.Asset>>"
And also since your model is now a IEnumerable, you can not do a simple Model.Id instead it should be Model[0].Id (or what ever ith elemnt you choose or you do a foreach)
This is an old question, but I ran into the same problem converting some MVC 2 code to MVC 3. A simple configuration problem to look for is making sure you have this app setting in your config:
<appSettings>
<add key="enableSimpleMembership" value="false" />
</appSettings>
See this thread for more info.

System.Web.mvc.HtmlHelper does not contain a definition for EnumDropDownListFor

I have been following this tutorial http://blogs.msdn.com/b/stuartleeks/archive/2010/05/21/asp-net-mvc-creating-a-dropdownlist-helper-for-enums.aspx but I run into the error "System.Web.Mvc.HtmlHelper does not contain a definition for EnumDropDownListFor".
Model:
public enum Codes
{
IBC2012,
IBC2009,
IBC2006,
FL2010,
CBC2007
}
public class Code
{
public int ID { get; set; }
public int Active { get; set; }
public string Description { get; set; }
public string Edition { get; set; }
public Codes Code { get; set; }
}
Controller:
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
IEnumerable<TEnum> values = Enum.GetValues(typeof(TEnum)).Cast<TEnum>();
IEnumerable<SelectListItem> items =
values.Select(value => new SelectListItem
{
Text = value.ToString(),
Value = value.ToString(),
Selected = value.Equals(metadata.Model)
});
return htmlHelper.DropDownListFor(
expression,
items
);
}
HTML Helper:
#Html.EnumDropDownListFor(model => model.Code.Codes)
You forgot to bring the extension method in scope inside the view. This EnumDropDownListFor method is defined in some static class inside a namespace, right?
namespace AppName.SomeNamespace
{
public static class HtmlExtensions
{
public static MvcHtmlString EnumDropDownListFor<TModel, TEnum>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TEnum>> expression)
{
...
}
}
}
You need to add this namespace inside the view in which you want to use this helper:
#using AppName.SomeNamespace
#model MyViewModel
...
#Html.EnumDropDownListFor(model => model.Code.Codes)
And to avoid adding this using clause to all your Razor views you could also add it to the <namespaces> section of your ~/Views/web.config file:
<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="AppName.SomeNamespace" />
</namespaces>
</pages>
</system.web.webPages.razor>
As #ArhiChief hinted at in their answer, my problem was:
using System.Web.WebPages.Html;
Instead of:
using System.Web.Mvc;
Both of which have definitions for HtmlHelper so if you add the wrong one, you will get this error. Replacing it with the correct namespace will fix it.
Change your namespace to
namespace System.Web.Mvc
{
public static class HtmlExtensions
{
...
In my case I had my extensions namespace referenced, but was missing a using statement for System.Web.Mvc.Html.
(The DropDownList methods are defined in System.Web.Mvc.Html.SelectExtensions)
Maybe the problem is that your HtmlHelper doesn't contain defination for DropDownList because of HtmlHelper defined in several namespaces: System.Web.Mvc and System.Web.WebPages.Html. The System.Web.WebPages.Html namespace contains HtmlHelper.DropDownList.
Also, don't forget to post your html helper namespace into Views Web.config, so, Razor view engine will find it.
Pay particular attention in Darin's answer that you will be adding your namespace to the web.config in the Views folder. Not the web.config file in your root web folder. I didn't notice it at first, and for a while was baffled as to why it wouldn't work after adding my namespace to the root web.config file.
I think this also explains why it works for those who change their namespace to System.Web.Mvc in their HtmlExtensions class. System.Web.Mvc is already included in the namespaces in the ~/Views/web.config file.
As previously stated, the correct namespace needs to be in the web.config file under the views folder. The default namespace is automatically included in the web.config file under the views folder.
If your default namespace is
namespace AppName.SomeNamespace
The web.config file already contains the entry:
<add namespace="AppName.SomeNamespace" />
What has not been mentioned before is when you create a new folder in your MVC project the namespace gets extended. If you created a folder called Helpers, like I did then your namespace for these methods will be:
namespace AppName.SomeNamespace.Helpers
The extended namespace is not in the web in the web.config file under the views folder.
You have two options:
Change the namespace in the file with the html helper methods to the default namespace by removing the ".Helpers".
Add the extended namespace to the web config file
<add namespace="AppName.SomeNamespace.Helpers">
We use VB and were having the same issue. The only thing that worked for us was, in the _PartialView.vbhtml page:
#* Import the project's root namespace *#
#Imports MyRootNamespace
#* Import the Module that contains the HTML Extension Functions *#
#Imports MyHtmlHelperExtensions
#* To use the extension, We have to call the extension function directly
Passing the Html (HTML Helper Object) as the first parameter. *#
MyExtensionFunctionName(Html, "Hello World")
For reference, our HTML Extensions file looks like this:
Imports System.Web.WebPages.Html
Public Module MyHtmlHelperExtensions
'== Example
<Extension()>
Public Function MyExtensionFunctionName(ByVal html As HtmlHelper, ByVal textToDisplay As String) As IHtmlString
html.Raw(textToDisplay)
End Function
End Module

MVC3 with razor web.config authorization for default route

I am new to MVC and my question is this how can I setup my sites root to point to a specific Controller + Action and then in the Web.config file set the location + path of the root of the site, so eg: http://localhost:8080/ to be able to be accessed by all anonymous and logged in.
I have been playing with the location and path but just cant figure it out and in my Global.asax, I am not sure I have the right root to Home + Index as controller + Action.
Here is some code:
web.config (snippets)
<authentication mode="Forms">
<forms loginUrl="~/Account/LogOn" timeout="2880"/>
</authentication>
<authorization>
<deny users="?" />
<allow users="*" />
</authorization>
I am not sure what the <location path=""> of the root of the site should be.
Global.asax (snippets)
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
The default route in Global.asax for the site I would like it to go to the Home Controller and the Action Index, so when you type http://localhost:8080/
Thanks in advance.
You are already doing it in the third parameter of MapRoute.
new { controller = "Home", action = "Index", id = UrlParameter.Optional }
These specify your default controler and action, exactly as you want it.

Resources