0

I am learning ASP.Net MVC 5 , and I am stuck at usage of extention method. So I created an extension method and now I want to use it in my Razor view. But it's throwing error InvalidOprationException Error.

Model

public class Student
{
    public int Id { get; set; }
    public string Name { get; set; }
    [Display(Name = "Amount Owed")]
    public decimal Amount { get; set; }
}

View

@model IEnumerable<WebApplication3.Models.Student>
@using WebApplication3.Extension
<table class="table" id="studentstable" style="border: 1px solid black; background-color: silver">
<tr>
    <th>
        @Html.DisplayNameFor(model => model.Name)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Amount)
    </th>
    <th>
        @Html.DisplayNameFor(model => model.Amount)
    </th>
</tr>

@foreach (var item in Model)
{
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Name)
        </td>
        <td>
            @item.Amount.ConvertToDollar() @* this works fine *@
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Amount.ConvertToDollar())  @*I want somwething like this so that I do not lose the HTML HELPERs*@
        </td>
    </tr>
}
</table>

Extension Method

namespace WebApplication3.Extension
{
    public static class Helper
    {
        public static string ConvertToDollar(this decimal amount)
        {
            return String.Format("{0:C}", amount);
        }
    }
}

Error Line:

@Html.DisplayFor(modelItem => item.Amount.ConvertToDollar()). I can use simply @item.Amount.ConvertToDollar() But I want to embed it in HTMLHELPER. Please guide me. Is this even possible?

Unbreakable
  • 7,776
  • 24
  • 90
  • 171
  • What do you mean _embed it in HTMLHELPER_? And this functionality is already built in to the frame work. You just add a `[DisplayFormat(DataFormatString = "{0:C}")]` attribute to your `Amount` property and use `@Html.DisplayFor(m => item.Amount)` You do not need to reinvent the wheel –  Aug 04 '17 at 22:35
  • @StephenMuecke: Thank you for the inputs. But I just explicitly wanted to use it so that, I can know how to use extension method. This was just an example. I did not mean to develop it logically. I just wanted to know how to use extension method. And be able to use it to show some stuff in UI using Razor code. – Unbreakable Aug 05 '17 at 00:24
  • Suppose we really have a scenario where we need to use extension method. Then how to apply it in razor code. I mean I can write something like `@model.blabla.extensionmethod()` but I want to utilize the strongly typed stuff too. – Unbreakable Aug 05 '17 at 00:25
  • I want to be able to use HTML helper and display the porperties by applying extension methods – Unbreakable Aug 05 '17 at 00:26
  • There are plenty of examples on the web of how to create `HtmlHelper` extension methods. But in this case it would make no sense at all to create one. And a good place to start is to study the source code. But without knowing just what you really want to do its impossible to help –  Aug 05 '17 at 00:30
  • @StephenMuecke: Ok no problem. Appreciate your inputs. :) – Unbreakable Aug 05 '17 at 00:30
  • @StephenMuecke: Once i come up with real world scenario, and I get stuck. I will update the question. :) – Unbreakable Aug 05 '17 at 00:31
  • As an example, refer [this answer](https://stackoverflow.com/questions/30372911/pass-model-tproperty-expression-to-partial/30374415#30374415) or [this one](https://stackoverflow.com/questions/40240845/how-to-change-or-add-attributes-to-html-fields-via-html-helper-methods/40250508#40250508) or [this one](https://stackoverflow.com/questions/27146524/how-to-render-singly-linked-list-in-mvc-view-page/27147744#27147744) –  Aug 05 '17 at 00:32
  • The more I am learning, I realize the less I know. Time to learn about custom Html helper now. :) – Unbreakable Aug 05 '17 at 00:36

1 Answers1

1

TLDR; You can not use an method at the end of the lambda that will be passed to @Html.DisplayFor(). You need to either convert your data earlier, use @Html.Display() or write display the data yourself.

Edited: The @Html.DisplayFor(modelItem => item.Amount.ConvertToDollar()) call throws the folowing error on my test project (i reconstructed a project similar to your for demonstration purposes)

InvalidOperationException: Templates can be used only with field access, property access, single-dimension array index, or single-parameter custom indexer expressions. This means that you can not use ConvertToDollar() in this call. You have to convert the value BEFORE returning it.

As far as i know you can not call an extension method at the end of a lambda before passing it to @Html.DisplayFor. You will have to use either an Attribute to decorate your class or a property a bit like

    [Display(Name = "Amount Owed")]
    public string AmountAsMoney => $"${this.Amount}";

I'm sorry, I don't think what you are trying to do is possible :-(

As requested, I found this example of real useful usage for an extension method in c#. As for personal example, i can not provide any code but so far i have only used extension methods in order to add functionality to a class defined in an other library that I didn't feel like inheriting, or that was sealed. (this goes againsst OOP principles but, still, we CAN do it.)

Mathieu VIALES
  • 4,526
  • 3
  • 31
  • 48
  • Ok, I will ask my doubt again. First forget that I want to convert amount to dollar. I know that it can be handled by the framework itself. But I was just learning about Extension method. And I explicitly wanted to use it. We only write extension method for the functionality which is most commonly used in the application and that functionality is not provided by framework. Also, to remove code duplication. With this in mind. suppose we do not have the functionality for the conversion of dollar symbol on amount. So, I wrote a sample extension method which will append amount with dollar symbol – Unbreakable Aug 07 '17 at 14:45
  • So far so good. But my question is how to call extension method from htmlhelper. Supose I want to convert amount into dollar at 1000 places – Unbreakable Aug 07 '17 at 14:45
  • Why do I need to write some thing like this ` @item.Amount.ConvertToDollar()` – Unbreakable Aug 07 '17 at 14:46
  • I wanted to use inbuild htmlhelper and call the extension method. something like `@Html.DisplayFor(modelItem => item.Amount.ConvertToDollar())` – Unbreakable Aug 07 '17 at 14:46
  • So bascially, I am trying to learn about extension method and how to call them in Razor code. – Unbreakable Aug 07 '17 at 14:46
  • Do you understand my doubt. I don think I can explain more clearly. :( – Unbreakable Aug 07 '17 at 14:47
  • If you can tell me how to use @Html.displayfor and call extention method on model property,. I can live in peace. – Unbreakable Aug 07 '17 at 14:48
  • And Please note that I do not want to create my own custom helper just to be able to call extension method in razor code. – Unbreakable Aug 07 '17 at 14:49
  • Check my edit and let me know if it answer the question better :-) – Mathieu VIALES Aug 07 '17 at 15:09
  • so whenever I need to call extension method and render something in Razor code , I need to get rid of the Html Helper provided by the framework. Cool, thanks, I can get some peace. Also if you can share some link (practical usage where I should use extension method), real world usage that would be great. Thanks a ton! :) – Unbreakable Aug 07 '17 at 15:28
  • The HtmlHelper `@Html.DisplayFor()` in this case is the part that you keep. What you need to change is the call to `ConvertToDollar()`. Your lambda expression can not end with a call to a method (in this context, at least). If you are still not sure how to do what you want (aka pass a string "$182.3" to your @Html.DisplayFor() let me know, i will provide a full working example of how i might have implemented it. – Mathieu VIALES Aug 07 '17 at 15:32
  • Pardon my ignorance. But how can I keep the `displayfor` helper and still call the extension method with it. From what I understood from your answer is I CANNOT USE `displayfor` in conjunction with the extension method. that's what you explained right? – Unbreakable Aug 07 '17 at 15:43
  • So either I use `@Html.displayfor` and then use framework's amount to dollar SYMBOL conversion. Or I need to use a bare html `@item.Amount.ConvertToDollar()` to get the job done – Unbreakable Aug 07 '17 at 15:44
  • We all ignored all of this one day :-) Don't apologize for not knowing something. Now about the Html helper, you perfectly understood me. I do not know any way to use an extension method at the end of the lambda contained in a @Html.DisplayFor(). If you really want to use the extension method AND and Html helper, just make an other property in your ViewModel the returns `Amount.ConvertToDollar()`. This will use both techniques. But no, you can not have the converToDollar call be done right inside the Helper, unfortunately. – Mathieu VIALES Aug 07 '17 at 15:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/151286/discussion-between-unbreakable-and-wndrr). – Unbreakable Aug 07 '17 at 15:53