25

Basically I need something like old asp.net

@helper MakeNote(string content) {
    <p><strong>Note</strong>&nbsp;&nbsp; @content    </p>
}

or JSX

MakeNote(note) {
   return (<div>Note {note}</div>);
}

A partial view is not an option. I am happy with either a function returning an IHtmlString, or a function writing to the underlying writer.

It also needs to support Razor Syntax (not just string concatenation) inside the function.

3
  • 1
    You can create a tag helper to return your custom HTML markup. BTW, your OR JSX part makes this question very broad (at least for me) Commented Aug 30, 2018 at 20:05
  • 2
    This is just example of what I need from another language, I do not see how does it make question broad. Commented Aug 30, 2018 at 20:18
  • 1
    I just gave 2 examples of what I need and tag helper is nowhere close. Commented Aug 30, 2018 at 20:18

5 Answers 5

36

Since ASP.NET Core 3.0, we can declare Local Functions containing markup to serve as templating methods, inside Razor Code Blocks:

@{
    void RenderName(string name)
    {
        <p>Name: <strong>@name</strong></p>
    }

    RenderName("Mahatma Gandhi");
    RenderName("Martin Luther King, Jr.");
}

Which renders the following HTML Code:

<p>Name: <strong>Mahatma Gandhi</strong></p>
<p>Name: <strong>Martin Luther King, Jr.</strong></p>

Documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-3.0#razor-code-blocks


(just for sake of completion) In ASP.NET Core 2.0 we can use Templated Razor delegates, which combined with the <text></text> razor tag (Explicit Delimited Transition), allow us to make something similar to an old day's ASP.NET MVC @helper tag:

@{
    Func<string, object> RenderName = @<text>
        <p>
            Name: <strong>@item</strong>
        </p>;
    </text>;
}

<div>
    @RenderName("Victor")
</div>

Which renders the following HTML Code:

<div>
    <p>
        Name: <strong>Victor</strong>
    </p>
</div>

Documentation: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-2.0#templated-razor-delegates
Documentation <text></text>: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/razor?view=aspnetcore-2.0#razor-code-blocks

Sign up to request clarification or add additional context in comments.

1 Comment

If your function return void than in html markup call function inside braces. Like this: @{ RenderName("Victor"); }
22

You might be looking for @functions that use Html.Raw.

Here is an example that shows two function styles. The first uses a traditional block body, the second uses an expression-body.

Both of them have the $@ prefix on the string.

  • The $ enables {interpoloation} in the string.
  • The @ makes a verbatim string, which can span multiple lines.

The third way is somewhat of a hack that lets us parse Razor inside the function. It's as close as we seem to be able to get to the original @helper syntax.

SomeRazorFile.cshtml

@using Microsoft.AspNetCore.Html

@functions 
{
    IHtmlContent MakeNote(string content) 
    {
        return Html.Raw($@"
            <p>
                <strong>Note</strong> {content}
            </p>
        ");
    }

    // an alternative that uses method shorthand
    IHtmlContent MakeNoteToo(string content) => Html.Raw($@"
        <p>
            <strong>Note</strong> {content}
        </p>
    ");
}

@{
    // an alternative that parses razor
    Func<string, IHtmlContent> MakeNoteThree = 
        @<p>
            <strong>Note</strong> {@item}
        </p>;
}

<div>
    @MakeNote("Foo")
    @MakeNoteToo("Bar")
    @MakeNoteThree("Baz")
</div>

Edit: Added an example that parses Razor. See https://github.com/aspnet/Razor/issues/715 for details.

7 Comments

It kind-of works, but I want to use Razor inside that function, not string concatenation.
@user2029276 Good to know. I added an example that uses Razor inside the function. Let me know how that works for you.
I saw it already on github, but I think it is kind of hack, rather than official solution. Syntax is kinda weird, and argument isn't named. Can You add more arguments?
Yes. You can add more arguments. The method of doing that is more of a hack though; it involves passing a tuple to the func.
For a workaround to the limitation of the parameters, you can use Tuples. i.e. Func<(string name, int value), IHtmlContent> CreateInput = @<input name="@item.name" value="@item.value" />
|
7

I would like to provide an overview answer to simplify this post.

The closest approach to the question is @Vitox's answer, but lacks how to call the method in place:

@{
    void MakeNote(string content)
    {
        <p><strong>Note</strong>&nbsp;&nbsp; @content    </p>
    }
}

This is good for helpers with a lot of C# code and is called like this:

<div>
  <p>Today is a great day for programming.</p>
  @{MakeNote("Have a nice day!");}
</div>

In case you don't like the @{Method(params);} construct, I suggest @Shaun Luttin's answer:

Func<string, IHtmlContent> MakeNote = 
    @<p><strong>Note</strong>&nbsp;&nbsp; @item    </p>;
}

This is good for HTML oriented helpers and is called like this:

<div>
  <p>Today is a great day for programming.</p>
  @MakeNote("Have a nice day!")
</div>

I don't know why Shaun wrote {@item} in his code, but I did notice that sometimes VS 2022 requires cleaning up the project to compile such code.

Here is an extended example with this second approach:

Func<ValueTuple<int, string>, IHtmlContent> SomeMethod =
@<p>
    @{int x = item.Item1 + 2;}
    <strong>Note</strong> @(item.Item2 + x)
</p>;

When calling like this @SomeMethod((5, "Have a good day!")) the following output is displayed:

<p>
    <strong>Note</strong> Have a good day!7
</p>

Comments

0

I'm having to convert old Helpers to something as close as possible in .net 5 and I've had good luck with this so far. Not saying it's best, but it works.

Old Helper now as a function...

public static string Helper1(string name) {
   string html = null;
   html += "<p>Hi, my name is <strong>@name</strong></p>";
   html += "<p>It's nice to meet you!</p>";
   return html;
}

Include the reference and call on any Page...

<div>
   @Html.Raw(Helper1("Josh"))
</div>

Comments

0

If the method uses TagHelpers the signature must be async.

error MVC1006: The method contains a TagHelper and therefore must be async and return a Task. For instance, usage of ~/ typically results in a TagHelper and requires an async Task returning parent method.

However adding async causes CS1998 that I must disable due to TreatWarningsAsErrors enabled:

@{
    #pragma warning disable CS1998 // The async method lacks 'await'
    async Task Helper(string action) {
        <a asp-action=@action>@action</a>
    }
}

And calling it must also be awaited:

@{ await Helper("MyAction"); }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.