Mathieu
Mathieu

Reputation: 154

Having trouble creating my own HTML Helper

I'm trying to create my own Html. helper in razor inspired on this answer. I have a problem with the parameter "this HtmlHelper html"

    public static MvcHtmlString ActionImage(this HtmlHelper html, string action, object routeValues, string imagePath, string alt)
{
    var url = new UrlHelper(html.ViewContext.RequestContext);

    // build the <img> tag
    var imgBuilder = new TagBuilder("img");
    imgBuilder.MergeAttribute("src", url.Content(imagePath));
    imgBuilder.MergeAttribute("alt", alt);
    string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

    // build the <a> tag
    var anchorBuilder = new TagBuilder("a");
    anchorBuilder.MergeAttribute("href", url.Action(action, routeValues));
    anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
    string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

    return MvcHtmlString.Create(anchorHtml);
}

I saw in all the Html helpers the methods also used this parameter. However. i keep getting the error there is no overload for that method i created.

Im fairly sure im placin the method that Lucas provided somewhere wrong. I made a new static class and added the namespace to the web config ( answer provided by umar ).

Could someone help me why im getting this?

thanks in advance

------ Edit Here is my full class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;

namespace SSA_Project.Models.htmlHelper {
    public static class htmlHelperExtension {
        public static MvcHtmlString ActionImage(this HtmlHelper html, string action, object routeValues, string imagePath, string alt) {
            var url = new UrlHelper(html.ViewContext.RequestContext);

            // build the <img> tag
            var imgBuilder = new TagBuilder("img");
            imgBuilder.MergeAttribute("src", url.Content(imagePath));
            imgBuilder.MergeAttribute("alt", alt);
            string imgHtml = imgBuilder.ToString(TagRenderMode.SelfClosing);

            // build the <a> tag
            var anchorBuilder = new TagBuilder("a");
            anchorBuilder.MergeAttribute("href", url.Action(action, routeValues));
            anchorBuilder.InnerHtml = imgHtml; // include the <img> tag inside
            string anchorHtml = anchorBuilder.ToString(TagRenderMode.Normal);

            return MvcHtmlString.Create(anchorHtml);
        }
    }
}

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="SSA_Project.Models.htmlHelper" />
      </namespaces>
    </pages>

And im trying to call it with @Html.ActionImage(..)

I just found out there is also a webconfig file @ the map "views" so i deleted the namespace mentioned before and added it there. code below

 <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.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="SSA_Project.Models.htmlHelper" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>

This is thee area im working in. ( selected one is which im working in ) Area

Whole webconfig file that you can see in the screenshot above.

<?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.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="SSA_Project.Models.htmlHelper" />
      </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>

Upvotes: 2

Views: 575

Answers (1)

Richard
Richard

Reputation: 30628

The changes that you mention you've added to web.config need to be added to the web.config in the Views folder. Please ensure that they're in here rather than just in the web.config in the root of your project.

You can also add a @using statement to the individual view to use it, e.g.

@using SSA_Project.Models.htmlHelper

@Html.ActionImage(....)

If you're using an Area, then the web.config must be in Areas/AreaName/Views. You can also add web.config files to individual folders within the Views folders - the closest existing config file will be used. For example...

|-Areas
|   \-Admin
|     \-Views
|         |-Home
|         |   \-Index.cshtml
|         \-Web.config <-- Will be used by Areas\Admin\Views\Home\Index.cshtml
|-Views
|   |-Account
|   |  |-Login.cshtml
|   |  \-Web.Config     <-- Will be used by Views\Account\Login.cshtml
|   |-Home
|   |  \-Index.cshtml
|   \-Web.config         <-- Will be used by Views\Home\Index.cshtml
\-Web.Config

I've created a project using the code from your question, and this works fine for me. I did the following:

  • Create new MVC project
  • Add folder "htmlHelper" to Models folder
  • Create "htmlHelperExtension.cs" with contents from your question
  • Add <add namespace="WebApplication5.Models.htmlHelper"/> to namespaces section of Views/Web.config
  • Add @Html.ActionImage("Index", "Home", "~/Content/images/blah.png", "aaaa") to Views\Shared_Layout.cshtml

This works for me!

Upvotes: 2

Related Questions