252

How do I define a method in Razor?

Rookian
  • 19,841
  • 28
  • 110
  • 180
  • 2
    For those who wanted to see what are options: There are two ways to do it. One. using "@function" and another using "@helper". The difference between them is nicely explained here. https://www.mikesdotnetting.com/article/173/the-difference-between-helpers-and-functions-in-webmatrix – b1k Sep 20 '19 at 16:09

8 Answers8

354

Leaving alone any debates over when (if ever) it should be done, @functions is how you do it.

@functions {

    // Add code here.

}
PTD
  • 1,028
  • 1
  • 16
  • 23
David Ruttka
  • 14,269
  • 2
  • 44
  • 39
  • 17
    +1 thanks, FYI its called practicality. MVC isn't the only game in town. Some folks just like simple razor and URLRewrite as MVC is a lot to do for little benefit IMO – King Friday Oct 28 '12 at 18:00
  • 6
    `@functions` is a good place to organize *view specific* generation code. Case in point: those ugly client templates-from-strings .. – user2864740 Apr 22 '15 at 22:22
  • 1
    hi David, how can I define the function in one file and use it in another file? – Georgi Kovachev Dec 01 '16 at 20:06
  • Georgi, this is called "Razor HTML Helper". Basically, a class defined in your Code folder, with a set of static methods as suggested here: https://www.asp.net/mvc/overview/older-versions-1/views/creating-custom-html-helpers-cs – jeanie77 Jan 17 '17 at 10:02
  • Georgi, you may have come across this by now ... but for reusing @functions or @helper Razor options you can use a file such as Shared.cshtml in your App_Code folder. In there you can define @functions {} or @helper MyFunction() {} and use them in your other Razor templates like @Shared.MyFunction() where the name of the file is like the "namespace" – Jamie Altizer Dec 10 '17 at 01:26
219

You mean inline helper?

@helper SayHello(string name)
{
    <div>Hello @name</div>
}

@SayHello("John")
Darin Dimitrov
  • 1,023,142
  • 271
  • 3,287
  • 2,928
  • 5
    I want to define a method that returns not a MvcHtmlString, but a C# type. – Rookian Mar 01 '11 at 20:26
  • 5
    @Rookian, why would you ever need to write C# code in a view? I mean writing methods in a view is just wrong! You could perfectly fine write your C# code wherever in belongs and then invoke the method in a Razor view, and that's exactly what HTML helpers do. And they are not supposed to return always an MvcHtmlString. – Darin Dimitrov Mar 01 '11 at 20:27
  • because Phil Haack is doing this :) http://haacked.com/archive/2010/05/05/asp-net-mvc-tabular-display-template.aspx Is there antoher way of doing this with MVC 3 and Razor? – Rookian Mar 01 '11 at 20:28
  • 1
    @Rookian, maybe you could explain what you are trying to do in the first place. Whatever it is I am sure there is a better way to do it rather than writing C# code in a view :-) – Darin Dimitrov Mar 01 '11 at 20:30
  • I just want to pass any list (Ilist) in a view template and it should be rendered as a table. So this template should be reusable. – Rookian Mar 01 '11 at 20:37
  • 1
    This is awesome! Thank you Darin...just when I think I know everything about MVC, you come along and I learn something new :) – Serj Sagan Jun 10 '14 at 01:01
  • 1
    @Rookian I would suggest not being too idiomatic here; there are times you may want to involve complex but view-only logic that yields simple text/tostringable results -- e.g. as input to the build in conditional class(attribute) helpers. And if you want to later move that logic elsewhere its an easy refactor, easier in-fact than moving an inline helper to a shared location, which will have to be app_code, and won't have access to the Html helpers without a little wonkage: http://weblogs.asp.net/scottgu/asp-net-mvc-3-and-the-helper-syntax-within-razor – Adam Tolley Jun 26 '15 at 19:33
  • I wanted a recursive html code and this was the thing i wanted. – ConductedClever Jul 08 '15 at 09:03
  • 3
    Not supported anymore in ASP.NET Core it seems. Syntax error. – ygoe Jul 27 '16 at 07:43
  • 1
    Too bad it's gone now - coming from Classic ASP to this kind of code, it seems like a lot of work to fill in for the ubiquitous feature of being able to create a reusable function that uses raw html between the app code lines. – Vasily Hall Nov 07 '16 at 19:28
  • 5
    The ASP.NET Core equivalent is the Tag Helper: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/authoring – beercohol Jan 04 '17 at 18:02
52

It's very simple to define a function inside razor.

@functions {

    public static HtmlString OrderedList(IEnumerable<string> items)
    { }
}

So you can call a the function anywhere. Like

@Functions.OrderedList(new[] { "Blue", "Red", "Green" })

However, this same work can be done through helper too. As an example

@helper OrderedList(IEnumerable<string> items){
    <ol>
        @foreach(var item in items){
            <li>@item</li>
        }
    </ol>
}

So what is the difference?? According to this previous post both @helpers and @functions do share one thing in common - they make code reuse a possibility within Web Pages. They also share another thing in common - they look the same at first glance, which is what might cause a bit of confusion about their roles. However, they are not the same. In essence, a helper is a reusable snippet of Razor sytnax exposed as a method, and is intended for rendering HTML to the browser, whereas a function is static utility method that can be called from anywhere within your Web Pages application. The return type for a helper is always HelperResult, whereas the return type for a function is whatever you want it to be.

Ananda G
  • 2,389
  • 23
  • 39
  • 4
    Calling function by omitting `@Functions` prefix as `@OrderedList(...)` works for me in .netcore. – Muflix Aug 21 '18 at 11:51
14

You could also do it with a Func like this

@{
    var getStyle = new Func<int, int, string>((width, margin) => string.Format("width: {0}px; margin: {1}px;", width, margin));
}

<div style="@getStyle(50, 2)"></div>
Bokoskokos
  • 512
  • 4
  • 13
10

Razor is just a templating engine.

You should create a regular class.

If you want to make a method inside of a Razor page, put them in an @functions block.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
3

You can also just use the @{ } block to create functions:

@{
    async Task<string> MyAsyncString(string input)
    {
        return Task.FromResult(input);
    }
}

Then later in your razor page:

   <div>@(await MyAsyncString("weee").ConfigureAwait(false))</div>
Daniel
  • 8,655
  • 5
  • 60
  • 87
2

Here is how the list helper is written in ASP.NET Core 3

You can now include HTML markup in the body of a method declared in a code block as a local method as previously, or in an @functions block. The method should return void, or Task if it requires asynchronous processing :

@{
    void Template(string[] listItems, string style)
    {
        <ul>
            @foreach (var listItem in listItems)
            {
            <li class="@style">@listItem</li>
            }
        </ul>
    }
}
M.Ali El-Sayed
  • 1,608
  • 20
  • 23
1

MyModelVm.cs

public class MyModelVm
{
    public HttpStatusCode StatusCode { get; set; }
}

Index.cshtml

@model MyNamespace.MyModelVm
@functions
{
    string GetErrorMessage()
    {
        var isNotFound = Model.StatusCode == HttpStatusCode.NotFound;
        string errorMessage;
        if (isNotFound)
        {
            errorMessage = Resources.NotFoundMessage;
        }
        else
        {
            errorMessage = Resources.GeneralErrorMessage
        }

        return errorMessage;
    }
}

<div>
    @GetErrorMessage()
</div>

You could also use the code block below. It is much cleaner and has more functionality. You can also insert variables above and functions below. Instead of using 2 seperate code blocks.

@{
    string exampleVariable = "just an example variable";
    string anotherExampleVariable = "just another example variable";

    string GetErrorMessage()
    {
        var isNotFound = Model.StatusCode == HttpStatusCode.NotFound;
        string errorMessage;
        if (isNotFound)
        {
            errorMessage = Resources.NotFoundMessage;
        }
        else
        {
            errorMessage = Resources.GeneralErrorMessage
        }

        return errorMessage;
    }
}
Valdemar Vreeman
  • 177
  • 2
  • 16
Joel Wiklund
  • 1,697
  • 2
  • 18
  • 24