Skip to content

Instantly share code, notes, and snippets.

@rynowak
Last active March 10, 2019 15:07
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Save rynowak/e82159b167a0f211523a0a395ae6939a to your computer and use it in GitHub Desktop.

LOL What?

Allows you to write methods that contain mixed HTML and C# in Razor Views (.cshtml) / Razor Components (.razor) files.

This is a primitive for composing Razor code that is very low overhead / low concept. Your code calls your code.

In Views (not components): Can be async, can use tag helpers. In Components (not views): Usage and semantics still need figuring out, but we want to build something like this.

Sample

<h1>Here is some info about people on the team</h1>

@foreach(var person in people)
{
    DisplayPerson(person);
}

@functions {
    void DisplayPerson(Person person)
    {
       @<div>
            <h3>
                @person.Name is @person.Age
            </h3>

            @if (DateTime.Now.DayOfYear == person.Birthday.DayOfYear)
            {
                <h4>Happy Birthday! @person.Name</h4>
            }
        </div>
    }

    Person[] people = new Person[]
    {
        new Person()
        {
            Name = "Ryan",
            Age = 33,
            Birthday = new DateTime(1985, 9, 9),
        },
        new Person()
        {
            Name = "Dan", // Not Dan Roth, some other guy. 
            Age = 53,
            Birthday = new DateTime(1965, 2, 3),
        },
    };

    public class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public DateTime BirthDay { get; set; }
    }
}

Your feedback

Is this W A V Y ? SPICY? Have you had cases where you wanted this? What would you add/change/remove?

@poke
Copy link

poke commented Mar 8, 2019

It felt that natural to me that you had to call it out explicitly here for me to notice.

When I looked at it on Twitter, I really only clicked the link to point out that the condition DateTime.Now.Date == person.BirthDay probably only works for a single birthday but not for the annual birthday.

@scottspiller
Copy link

Happy birthday! Text needs to be person.name not person.birthday

@rynowak
Copy link
Author

rynowak commented Mar 9, 2019

@iamtheoneaboveall @IDisposable @andre-artus - are you familiar with Razor or just C#? This is a syntax we already have, but normally you're using it in one big method. Razor predates the $"" feature and has different semantics (HTML encoding is included).

@rynowak
Copy link
Author

rynowak commented Mar 9, 2019

When I looked at it on Twitter, I really only clicked the link to point out that the condition DateTime.Now.Date == person.BirthDay probably only works for a single birthday but not for the annual birthday.

Heh! Yeah, this isn't an amazing example. I wanted to include some control flow.

The purpose is that you can refactor your logic into smaller methods if you think it needs it. It's possible to decompose Razor today, but the tools to use it are weakly typed and have high overhead relative to something like a method call.

@ladeak
Copy link

ladeak commented Mar 9, 2019

Interesting concept. I wonder if I would write cleaner code with this, or just make a bigger mess. Probably the second one, so I would try to use it either everywhere or nowhere.

@ateregulov
Copy link

I think it should be as

@void DisplayPerson(Person person)

Without excess word "function", without excess level of nesting.

@ardacetinkaya
Copy link

This is a big mess. Please don’t...

@mitiko
Copy link

mitiko commented Mar 9, 2019

I'd say the method should return something that's not void. Maybe that html content object that is used in components.

Just @ seems very undescriptive, maybe change it to return @<div> ... </div>.

@Yves57
Copy link

Yves57 commented Mar 9, 2019

In my opinion, the syntax above has too much '@' to be easy to use. In case of small components, I would like to have HTML more integrated in the C# syntax.

For me, a good compromise (i.e. remaing near the current Razor syntax) would be:

void DisplayPerson(Person person)
{
    <div>
        <h3>@person.Name is @person.Age</h3>
        if (DateTime.Now.DayOfYear == person.Birthday.DayOfYear)
        {
            <h4>Happy Birthday! @person.Name</h4>
        }
    </div>
}
  • If the first char of a line is '<', it is an HTML element. Otherwise, it is a C# expression.
  • All text following an HTML element on the same line is considered as HTML text.

Other questions:

  • In your example, the "function" is returns void. Is it possible to have async code?
  • What about HTML elements in lambda?
  • What is the function scope? Only this Razor file? Or is it possible to use more as a lightweight component in several files?
  • If it is a lightweight component, I would like to call it like in Typescript React <DisplayPerson person=@myVar />.

But I'm going probably too far :-)

@JesperTreetop
Copy link

JesperTreetop commented Mar 9, 2019

Just to underline what's new here, it's that with this new syntax, you could include Razor in @functions methods, whereas before if you tried, it would syntax error because it's meant to be pure C#?

I like the idea and it could help replace helpers, but this also muddies up the rules for what's HTML and what's C#. Most of the time, @ switches from HTML into C#, and not from C# into HTML. Writing HTML from inside C# is not a clean fit, especially without co-opting any return type or parameter the way @helper does. Not being able to capture the output in IHtmlContent is also problematic since most of the rest of the Razor public interface is based on top of it, although I understand that the idea is to be low-level and high-efficiency and it would be very "allocatey".

In the end, I can't help but like the way @helper solved this problem, by acknowledging that there's going to have to be some magic behind the scenes and so you can't set a return type, and using something like it would also give permission for the method signature to be malleable and different from exactly what's entered - ie in a low-level scenario, there could be an alternate method generated which output text to a writer passed in as an extra parameter instead of constructing an IHtmlContent to return. If every helper up and down the stack got that for free, I imagine there could be some savings.

Regarding the syntax: I remember that there's a feature like @<something></something> in classic Razor too, which comes with a magical item parameter which you couldn't change the name of. I don't remember the name of the feature and I have no idea if it made it to Core or not, and I think the syntax has a lot to do with that. Considering every other Razor syntax rule, it looks too close to a typo to feel natural, and it's basically impossible to Google.

@dodyg
Copy link

dodyg commented Mar 9, 2019

void DisplayPerson(Person person)
{
    <div></div>
}

Removing the @ is better

also it will be great if we can compose the functions

void DisplayPerson(Person person)
{
    <div>@ShowName(person)</div>
}

void Showname(Person person)
{
  <h3>@person.Name is @person.Age</h3>
}

@conficient
Copy link

Love it - makes it easier to compose ui

@adrianwright109
Copy link

I get the @ in front of person e.g. @person. and if e.g. @if (... but don't think the one at the start makes sense e.g. @<div>

@HerraHak
Copy link

HerraHak commented Mar 10, 2019

The @ in front of the div is a bit confusing but overall templating html using a method in the @functions that way is good.

@Bartmax
Copy link

Bartmax commented Mar 10, 2019

This:
poke:
It felt that natural to me that you had to call it out explicitly here for me to notice.

Exactly the same feeling.

I understand some can make a mess out of this but that's up to the developer. Totally want to have the option.

The example doesn't help understand why this could be usable

@SoftwareDreamer
Copy link

SoftwareDreamer commented Mar 10, 2019

To make a comparison as someone who went to the "dark side" of pure frontend development (but still doing a lot of C#, just more PAI and no Razor no more) I have to say there is a reason that vue.js is so successful and got traction: the .vue files just click with people. And the .vue files big thing: template markup, then script, then style tag, having everything in one place, making it a real component. Makes it much simpler to read the markup, too .

Sure, that is not the topic here, but just saying that having the option to just put markup in a Razor file at the top and markup-less C# code at the bottom with some binding-magic would solve sooth the "razor is a mess" fraction (I'm partially in), because.. well.. sorry.. having converted old Razor code to a modern frontend framework.. yeah, it's a mess. Or at least it's hard to read without a proper colorization, and often even with one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment