I just downloaded the MVC 3.0 RC and I'm excited to start using it, especially the Razor view engine. However, due to a few stick in the mud type people here, we are stuck using VB.NET instead of C#.
When I started trying it out, I noticed some quirks. If you are creating a Razor view using CSHTML, you can write code like this:
@foreach(string genreName in Model.Genres)
{
<li>@genreName</li>
}
Razor will automatically detect that the <li>
text is an HTML tag and will switch out of "code mode". With a VB.NET VBHTML file, this doesn't seem to be working. It's making me put the @:
keyword in front of each line like this:
@For Each genreName As String In Model.Genres
@:<li>@genreName</li>
Next
If I don't have it there, I get a runtime error. Also, the <text></text>
tags don't seem to work.
Anybody know what's going on here or whether there's a workaround?
The namespace for Razor Engine is System. The Razor file extension is "cshtml" for the C# language. By default, Razor View Engine encodes html tags or scripts before it's being rendered to view that avoids Cross-Site Scripting attacks.
cshtml files are razorpages or MVC views, they does not contain any C#-written client-side code. If you wan to do so, you must use JavaScript. However, a . razor file, also know as a Razor component, can have C# written in it and run on client's browser.
A Razor Page is almost the same as ASP.NET MVC's view component. It has basically the syntax and functionality same as MVC. The basic difference between Razor pages and MVC is that the model and controller code is also added within the Razor Page itself. You do not need to add code separately.
I would say the reason it's required in Vb.net is vb allows xml elements inline whereas c# does not.
Dim xmlMarkup = <someElement>Values</span>
Because of this the natural parser for vb must behave differently than c# so you have to tell the parser to escape back to html by using the @
. You can use @
and @:
.
As previously mentioned in comments, but not explicitly shown; prepending the text tag with @ solves the issue:
@For Each genreName As String In Model.Genres
@<text>
<li>@genreName</li>
</text>
Next
I just tried this in ASP.NET MVC 3 RC in a VBHTML view and it seems to work fine:
<ul>
@For Each i As Integer In Enumerable.Range(0, 5)
@:<li>@i</li>
Next
</ul>
It renders this markup:
<ul>
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
</ul>
This doesn't use the same code as the OP but I was converting some C# code from an MVC book into VB.NET and got stuck with mixing inline HTML and VB code. This is the original C#:
@using (Html.BeginForm()) {
@Html.ValidationSummary()
<p>Your name: @Html.TextBoxFor(x => x.Name, new { @class = "form-control" }) </p>
<p>Your email: @Html.TextBoxFor(x => x.Email, new { @class = "form-control" }) </p>
<p>Your phone: @Html.TextBoxFor(x => x.Phone, new { @class = "form-control" }) </p>
<p>Will you attend?
@Html.DropDownListFor(x => x.WillAttend, new[] {
new SelectListItem() {Text = "Yes, I'll be there",
Value = bool.TrueString},
new SelectListItem() {Text = "No, I can't come",
Value = bool.FalseString}
}, "Choose an option", new { @class = "form-control" })
</p>
}
and these are the different ways of representing it in VB:
@Using Html.BeginForm()
@:<p>Your name: @Html.TextBoxFor(Function(x) x.Name)</p>
@:<p>Your email: @Html.TextBoxFor(Function(x) x.Email)</p>
@:<p>Your phone: @Html.TextBoxFor(Function(x) x.Phone)</p>
@:<p>Will you attend?
@Html.DropDownListFor(Function(x) x.WillAttend, New SelectListItem() {New SelectListItem() With {.Text = "Yes", .Value = Boolean.TrueString}, New SelectListItem() With {.Text = "No", .Value = Boolean.FalseString}})
@:</p>
End Using
@Using Html.BeginForm()
@<text>
<p>Your name: @Html.TextBoxFor(Function(x) x.Name)</p>
<p>Your email: @Html.TextBoxFor(Function(x) x.Email)</p>
<p>Your phone: @Html.TextBoxFor(Function(x) x.Phone)</p>
<p>Will you attend?
@Html.DropDownListFor(Function(x) x.WillAttend, New SelectListItem() {New SelectListItem() With {.Text = "Yes", .Value = Boolean.TrueString}, New SelectListItem() With {.Text = "No", .Value = Boolean.FalseString}})
</p>
</text>
End Using
@code
Using Html.BeginForm()
@:<p>Your name: @Html.TextBoxFor(Function(x) x.Name)</p>
@:<p>Your email: @Html.TextBoxFor(Function(x) x.Email)</p>
@:<p>Your phone: @Html.TextBoxFor(Function(x) x.Phone)</p>
@:<p>Will you attend?
@Html.DropDownListFor(Function(x) x.WillAttend, New SelectListItem() {New SelectListItem() With {.Text = "Yes", .Value = Boolean.TrueString}, New SelectListItem() With {.Text = "No", .Value = Boolean.FalseString}})
@:</p>
End Using
End Code
@code
Using Html.BeginForm()
@<text>
<p>Your name: @Html.TextBoxFor(Function(x) x.Name)</p>
<p>Your email: @Html.TextBoxFor(Function(x) x.Email)</p>
<p>Your phone: @Html.TextBoxFor(Function(x) x.Phone)</p>
<p>Will you attend?
@Html.DropDownListFor(Function(x) x.WillAttend, New SelectListItem() {New SelectListItem() With {.Text = "Yes", .Value = Boolean.TrueString}, New SelectListItem() With {.Text = "No", .Value = Boolean.FalseString}})
</p>
</text>
End Using
End Code
What should be obvious from this is that when you need to include inline HTML within a code block you need to either prefix each line with a @:
or enclose the HTML with an @<text></text>
block. It's also obvious that this applies when you are using @Code
... End Code
instead of starting a block of code with @
.
p.s. Note that the @<text></text>
tags are not output to the page so they won't interfere with anything
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With