HTML helper class method not working - asp.net-mvc

I’m stuck in a reference book by Steven Sanderson/Adum Freeman Pro ASP .Net MVC 3. I’ve made it up to page 185 where a HTML helper is to be used to return the numberer of pages in links. I found help on this site addressing my issue with this reference book, and walked through every step still having the same issues (link) MVC extension method error
When I run the code in a browser I get this error:
Compiler Error Message: CS1973: 'System.Web.Mvc.HtmlHelper'
has no applicable method named 'PageLinks' but appears to have an
extension method by that name. Extension methods cannot be dynamically
dispatched. Consider casting the dynamic arguments or calling the
extension method without the extension method syntax
The code builds fine but if I open any other class to edit this line of code to my helper method gets the same error as above.
#Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x}))
Helper Class:
namespace SportsStore.WebUI.HtmlHelpers
{
public static class PagingHelpers
{
public static MvcHtmlString PageLinks(this HtmlHelper html,
PagingInfo pagingInfo,
Func<int, string> pageURL)
{
StringBuilder results = new StringBuilder();
for (int i = 1; i <= pagingInfo.TotalPages; i++)
{
TagBuilder tag = new TagBuilder("a");
tag.MergeAttribute("href", pageURL(i));
tag.InnerHtml = i.ToString();
if (i == pagingInfo.CurrentPage)
tag.AddCssClass("selected");
results.Append(tag.ToString());
}
return MvcHtmlString.Create(results.ToString());
}
}
}
My View:
#{
ViewBag.Title = "Products";
}
#foreach (var p in Model.Products) {
<div class="item">
<h3>#p.Name</h3>
#p.Description
<h4>#p.Price.ToString("c")</h4>
</div>
}
<div class="pager">
#Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new {page = x}))
</div>
Web.config
<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="SportsStore.WebUI.HtmlHelpers"/>
</namespaces>
</pages>
</system.web.webPages.razor>

You are passing a dynamic value to an extension method. (Hover over Model.PagingInfo and intellisense should tell you that the type is dynamic. This means it does not know what the type is until runtime) So, try changing your code so that it casts the dynamic type like this:
#Html.PageLinks((PagingInfo)Model.PagingInfo, x => Url.Action("List", new {page = x}))
You could fix this in two other ways:
As the error suggests, do not call it using the extension method:
PageLinks(Html, Model.PagingInfo, x => Url.Action("List", new {page = x}))
OR you could make the view know what the model is going to be so that it does not use a dynamic, by setting this at the top of your view
#model PagingInfo

Add #using project_name.HtmlHelpers
e.g.
#using ChristianSchool.HtmlHelpers
#Html.PageLinks(Model.PagingInfo, x => Url.Action("List", new { page = x, category = Model.CurrentCategory }))

you must add this lines in web.cofig under Views Folder not main one
<add namespace="YourProjectName.HtmlHelpers"/>

Related

Enum object not found with razor

The object 'YogaSpaceAccommodation' that I'm using as my type in GetEnumDescription seems to be brown and not found. Or something here isn't correct in terms of syntax.
<div id="AccomodationTypeSelector">
<select class="form-control" id="SpaceAccommodation" name="YogaSpaceAccommodation">
<option id="default">0</option>
#{
var accomodationValues = Enum.GetValues(typeof(YogaSpaceAccommodation));
foreach (var value in accomodationValues)
{
var index = (int)#value; var description = #EnumHelper.GetEnumDescription
<YogaSpaceAccommodation>(#index.ToString());
}
}
</select>
</div>
EnumDescription looks like this
public static string GetEnumDescription<T>(string value)
{
Type type = typeof(T);
var name = Enum.GetNames(type).Where(f => f.Equals(value, StringComparison.CurrentCultureIgnoreCase)).Select(d => d).FirstOrDefault();
if (name == null)
{
return string.Empty;
}
var field = type.GetField(name);
var customAttribute = field.GetCustomAttributes(typeof(DescriptionAttribute), false);
return customAttribute.Length > 0 ? ((DescriptionAttribute)customAttribute[0]).Description : name;
}
Find out which namespace your enum is in and add a using declaration at the top of the View. Say your namespace is MyApp.Data.Enums you would add:
#using MyApp.Data.Enums
to the top of the view by the #model declaration. You can also add the namespace through the web.config located in your views folder:
<system.web.webPages.razor>
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="MyApp.Data.Enums" />
</namespaces>
</pages>
</system.web.webPages.razor>
Note that when you make these changes you usually have to close and reopen the views for intellisense to catch up. You may need the namespace of the helper functions you are using.

How to enable custom html helper extension method to all views?

I have an issue on custom html helper method. I have added two custom html helper method. First method is MyTextBox and second one is MySelectBox Method which is extention to the HtmlHelper class.The following code is working fine.
C# :
namespace MyHtmlHelper
{
public static class HtmlHelperClass
{
public static MvcHtmlString MyTextBox(string fieldName)
{
return new MvcHtmlString("<input type=\"text\" name=\"" + fieldName + "\"></input>");
}
}
}
namespace MyHtmlHelper
{
public static class HtmlHelperExtension
{
public static MvcHtmlString MySelectBox(this HtmlHelper helper, string text)
{
return new MvcHtmlString("<select ><option>" + text + "</option></select>");
}
}
}
view:
#using MyHtmlHelper
<div>
#MyHtmlHelper.HtmlHelperClass.MyTextBox("test")
#Html.MySelectBox("Test")
</div>
I want this html helper method for all views in my application.so i removed MyHtmlHelper namespace from view and added in web.cong as follows
Web.config :
<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.Optimization" />
<add namespace="System.Web.Routing" />
<add namespace="System.Web.WebPages" />
<add namespace="MyHtmlHelper"/>
</namespaces>
</pages>
My Problem is : MyTextBox helper method working fine but html extension method (MySelectBox) is not working.Anyone please help me ,what mistake i have done or how to resolve this issue?
There is a another webconfig in the view folder. You have to use this.

Inline javascript in my Razor file - Can I have this "included" from an external file

I have javascript blocks that are small. I would like to have these same blocks appear inline in my code but don't want to repeat them in each file. Is there a way that I can "include" code into the Razor file that doesn't involve
<script src="#Url.Content("~/Scripts/small_script_block1.js")" type="text/javascript"></script>
Thanks
Another possibility that will take me a few more minutes to write up:
Create an extension method for HtmlHelper. In your cshtml file it would look like this:
#Html.InlineScriptBlock("~/scripts/small_script_block1.js")
If you want I can send you the implementation but that idea might be all you need. If not, add a comment and I'll write it up.
EDIT CODE Below (not pretty and no warranty implied or given :)
public static class HtmlHelperExtensions
{
public static MvcHtmlString InlineScriptBlock<TModel>(this HtmlHelper<TModel> htmlHelper, string path)
{
var builder = new TagBuilder("script");
builder.Attributes.Add("type", "text/javascript");
var physicalPath = htmlHelper.ViewContext.RequestContext.HttpContext.Server.MapPath(path);
if (File.Exists(physicalPath))
{
builder.InnerHtml = File.ReadAllText(physicalPath);
}
return MvcHtmlString.Create(builder.ToString());
}
}
Keep in mind that if you drop this into your project you will need to make the namespace visible to the views. Unlike ASP.NET WebForms where you could provide markup at the top, Razor requires you to do this in the Web.config file in the Views folder.
<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="Your.Namespace.Here.Extensions" />
</namespaces>
</pages>
You can use the #RenderSection syntax.
<head>
#RenderSection( "JavaScript", optional : true)
</head>
somewhere in the body, add ..
#section JavaScript
{
<script src="/Scripts/script.js" type="text/javascript"></script>
}
EDIT:
Or if you prefer inline, then as follows:
#section JavaScript
{
<script type="text/javascript">
function doSomething() {
}
</script>
}
#RenderPage("_IncludeYourScriptsHere.cshtml")
Create a partial view and paste in your tag.
If any one searching for asp.net core. Here is the full conversion code to use in asp.net core
in razor file, use
#using Project.Utility
#Html.InlineScriptBlock("scripts/small_script_block1.js")
In utility extension
public static string GetString(IHtmlContent content)
{
var writer = new System.IO.StringWriter();
content.WriteTo(writer, HtmlEncoder.Default);
return writer.ToString();
}
public static HtmlString InlineStyleBlock(this IHtmlHelper helper, string path)
{
var builder = new TagBuilder("style");
builder.Attributes.Add("type", "text/css");
var physicalPath = "wwwroot/" + path;
if (File.Exists(physicalPath))
{
builder.InnerHtml.AppendHtml(File.ReadAllText(physicalPath));
}
return new HtmlString(GetString(builder));
}
public static HtmlString InlineScriptBlock(this IHtmlHelper helper, string path)
{
var builder = new TagBuilder("script");
builder.Attributes.Add("type", "text/javascript");
var physicalPath = "wwwroot/" + path;
if (File.Exists(physicalPath))
{
builder.InnerHtml.AppendHtml(File.ReadAllText(physicalPath));
}
return new HtmlString(GetString(builder));
}
this should embed or inline css/js in razor page/ html body. Works for dot net core

Problem with HtmlHelper and MVC not seeing my new method

I tried to create this HtmlHelper method:
namespace Power.WebUx.Helpers
{
public static class HtmlHelperExtensions
{
public static MvcHtmlString SelectedIfMatch(this HtmlHelper helper, string actual, string expected)
{
if (expected == actual)
{
return new MvcHtmlString("<option selected=\"selected\" value=\"" + actual + "\"" + actual + "</option>");
}
else
{
return new MvcHtmlString("<option value=\"" + actual + "\"" + actual + "</option>");
}
}
I added the Power.WebUx.Helpers line to my web.config:
<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" />
<add namespace="Power.WebUx.Helpers" />
</namespaces>
</pages>
However when I try to use the extension I get an error message saying that System.Web.Mvc.HtmlHelper does not contain a definition for SelectedIfMatch
Does the code I am trying to run look right or am I missing something?
Hope someone can see something obvious.
thanks
Jon Wylie
Import the namespace into your view to use any extension methods in that namespace
<%# Import Namespace =
"Power.WebUx.Helpers" %>
Make sure you're modifying the top level web.config file(instead of the one in the views folder), then close and open the files where you're trying to use the helper

Generate urls that use MapRoute defaults

I have these routes defined:
routes.MapRoute("CategoryList_CountryLanguage", "Categories/{id}/{urlCategoryName}/{country}/{language}",
new {
controller = "Categories",
action = "Details",
});
routes.MapRoute("CategoryList", "Categories/{id}/{urlCategoryName}",
new {
controller = "Categories",
action = "Details",
country = "US",
language = "EN"
});
and I'm generating links using:
#Html.ActionLink("desc", "Details", "Categories", new { id = item.Id, urlCategoryName = item.UrlFriendlyName}, null)
and the generated urls are in the form:
/Categories/id/friendly-name
I want to generate:
/Categories/id/friendly-name/US/EN
without having to specify the country and language in the ActionLink call, can't I use defaults like that?
The easy workaround is to specify those parameters in the ActionLink calls, but I would like to avoid that if possible. My hope is that the first route expects the values specified in the url, while the second has the defaults when not included in the url and would use that to create new urls, no luck so far, is this possible?
You can create a helper class called UrlHelpers.cs that looks like this:
public static class URLHelpers {
public static string CategoryList(this UrlHelper helper, int id, string urlFirendlyName) {
return CategoryList(helper, id, urlFirendlyName, "US", "EN");
}
public static string CategoryList(this UrlHelper helper, int id, string urlFirendlyName, string country, string language)
{
return helper.Action("Details", "Categories", new { id, urlCategoryName = urlFriendlyName, country, language });
}
}
Then in your view you would call it like this:
Some Text
Just a note: You will want to add the namespace of your helper to your web.config in the pages > namespaces section. So if you add a Helpers folder to the root of your MVC app and place the UrlHelper.cs class in it you would add:
<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"/>
<add namespace="MyProject.Helpers"/>
</namespaces>
</pages>

Resources