ASP.NET/MVC的cshtml和Razor

維基教科書,自由的教學讀本

Razor是一種標記語法,把.NET嵌入到網頁中。Razor語法包括Razor標記、C#、HTML。文件以.cshtml為擴展名。

cshtml和aspx比較[編輯]

cshtml(使用C#的Razor語法)或vbhtml(使用VB的Razor語法)是MVC3開始新增的視圖文件,跟原先的aspx很相似,都是在伺服器端運行的動態網頁文件。

cshtml和aspx比較
項目 cshtml aspx
解釋引擎 Razor Rendering Engine WebForm Engine
在頁面中嵌入伺服器代碼塊 @{ test; } <% test; %>
在伺服器端解析表達式 @ShowHelloWorld() <%= ShowHelloWorld() %>

Razor語法[編輯]

Razor是伺服器端標記語言,有變量,循環,邏輯等,允許向網頁中嵌入基於伺服器的代碼。Razor網頁是帶有兩種內容的HTML頁面:HTML內容和Razor代碼。在伺服器端運行Razor代碼,生成靜態網頁,發往用戶的網頁瀏覽器。

Razor關鍵字[編輯]

Razor關鍵字有:

  • page
  • namespace
  • functions
  • inherits
  • model
  • section

加上括號可以轉義,如@( RazorKeyword )

C# Razor關鍵字[編輯]

C# Razor關鍵字有:case、do、default、for、foreach、if、else、lock、switch、try、catch、finally、using、while。使用雙重括號轉義,如@(@case)。第一個@讓Razor parser轉義,第2個@讓C# parser轉義。

@ 轉移字符[編輯]

@叫做轉移字符(transition character)。連續2個@字符為轉義,如razor的<p>@@Username</p>等價於html的<p>@Username</p>。

隱式Razor表達式[編輯]

隱式Razor表達式(Implicit Razor expressions),為@後跟C#表達式,如:

<p>@DateTime.Now</p>
<p>@DateTime.IsLeapYear(2016)</p>
<p>@await DoSomething("hello", "world")</p>

除了C# await關鍵字外不允許有空格、不能用泛型。角括號(<>)被解釋為HTML tag。

顯式Razor表達式[編輯]

顯式Razor表達式(Explicit Razor expression),為@後跟一對括號。

<p>Last week this time: @(DateTime.Now - TimeSpan.FromDays(7))</p>

<p>@(GenericMethod<int>())</p>正确的使用了泛型

@Html.Raw("<span>Hello World</span>")不编码直接作为html文本。

@("<span>Hello World</span>")编码为html文本&lt;span&gt;Hello World&lt;/span&gt;

@{
    var joe = new Person("Joe", 33);
}
<p>Age@(joe.Age)</p>如果不用显式Razor表达式,则<nowiki><p>Age@joe.Age</p></nowiki>将被解释为email地址。

Razor代碼塊[編輯]

Razor代碼塊為@後跟一對花括號{},例如:

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

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

將繪製html如下:

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

Razor代碼塊的默認語言是C#,但可以隱式轉換為HTML:

@{
    var inCSharp = true;
    <p>Now in HTML, was in C# @inCSharp</p>
}

使用<text>的顯式轉換為HTML:

@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <text>Name: @person.Name</text>
}

@:顯式行轉換為HTML:

@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    @:Name: @person.Name
}

控制結構[編輯]

@if (value % 2 == 0)
{
    <p>The value was even.</p>
}
else if (value >= 1337)
{
    <p>The value is large.</p>
}
else
{
    <p>The value is odd and small.</p>
}

@switch (value)
{
    case 1:
        <p>The value is 1!</p>
        break;
    case 1337:
        <p>Your number is 1337!</p>
        break;
    default:
        <p>Your number wasn't 1 or 1337.</p>
        break;
}

@{
    var people = new Person[]
    {
          new Person("Weston", 33),
          new Person("Johnathon", 41),
          ...
    };
}
@for (var i = 0; i < people.Length; i++)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}
@foreach (var person in people)
{
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>
}
@{ var i = 0; }
@while (i < people.Length)
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
}
@{ var i = 0; }
@do
{
    var person = people[i];
    <p>Name: @person.Name</p>
    <p>Age: @person.Age</p>

    i++;
} while (i < people.Length);

using複合[編輯]

@using (Html.BeginForm())
{
    <div>
        Email: <input type="email" id="Email" value="">
        <button>Register</button>
    </div>
}

@try, catch, finally[編輯]

@try
{
    throw new InvalidOperationException("You did something invalid.");
}
catch (Exception ex)
{
    <p>The exception message: @ex.Message</p>
}
finally
{
    <p>The finally statement.</p>
}

@lock[編輯]

用於保護臨界區:

@lock (SomeLock)
{
    // Do critical section work
}

註釋符號[編輯]

@*
    @{
        /* C# comment */
        // Another C# comment
    }
    <!-- HTML comment -->
*@

為一個view生成的Razor C#類[編輯]

Razor SDK把Razor文件編輯為原始碼文件並放在目錄中:

obj/<build_configuration>/<target_framework_moniker>/Razor

再向下就遵從Razor文件的目錄結構。

一個Razor文件:

@{
    var quote = "Getting old ain't for wimps! - Anonymous";
}

<div>Quote of the Day: @quote</div>

會被編譯為C#文件:

public class _Views_Something_cshtml : RazorPage<dynamic>
{
    public override async Task ExecuteAsync()
    {
        var output = "Getting old ain't for wimps! - Anonymous";

        WriteLiteral("/r/n<div>Quote of the Day: ");
        Write(output);
        WriteLiteral("</div>");
    }
}

這種生成的類,可以有Razor directives來修飾:

  • @attribute
  • @code:向Razor components (.razor)增加 C# members (fields, properties, and methods) 。是 @functions的別名
  • @functions:向生成的類增加C# members (fields, properties, and methods)
  • @implements:生成的類實現一個接口
  • @inherits:當前view繼承了一個類
  • @inject:從服務容器向view注入一個服務
  • @layout:一個可路由的Razor components且有一個@page指令,指定一個layout
  • @model:指定傳給一個MVC views或Razor Pages (.cshtml)的模型的類型。生成的類是從RazorPage<ModelClass>派生的。通過生成類的Model屬性可以訪問model傳給view的數據。如果沒有給出@model指令,那麼默認為dynamic
  • @namespace:生成類所在的命名空間。 Sets the root derived namespaces of a pages, views, or components classes from the closest imports file in the directory tree, _ViewImports.cshtml (views or pages) or _Imports.razor (Razor components)。如果每個頁面都導入了Pages/_ViewImports.cshtml,且Pages/_ViewImports.cshtml包含@namespace Hello.World,那麼每個頁面都以Hello.World作為根命名空間。如Pages/Index.cshtml的命名空間為Hello.World;Pages/MorePages/Page.cshtml的命名空間為Hello.World.MorePages。如果多個導入文件都有命名空間,那麼在目錄樹上最接近 page, view, component的導入文件的命名空間作為根命名空間。
  • @page:對於.cshtml文件,指出這是Razor Page;或者指出Razor component應直接處理請求。
  • @preservewhitespace:對於Razor components (.razor),設為false (缺省值)時頭尾部空白符被刪除。
  • @section:對於MVC views或Razor Pages (.cshtml),與layouts一起可在HTML頁面不同位置繪圖。
  • @using:即C# using指令
@functions {
    public string GetHello()
    {
        return "Hello";
    }
}
<div>From method: @GetHello()</div>

@using System.IO
@{
    var dir = Directory.GetCurrentDirectory();
}
<p>@dir</p>

Razor模板[編輯]

@符號後跟一對html標記可作為一個模板化的Razor委託。其參數的類型為dynamic。例如:

public class Pet
{
    public string Name { get; set; }
}

    var pets = new List<Pet>
    {
        new Pet { Name = "Rin Tin Tin" },
        new Pet { Name = "Mr. Bigglesworth" },
        new Pet { Name = "K-9" }
    };

用於

@{
    Func<dynamic, object> petTemplate = @<p>You have a pet named <strong>@item.Name</strong>.</p>;

@foreach (var pet in pets)
{
    @petTemplate(pet)
}
}

結果為:

<p>You have a pet named <strong>Rin Tin Tin</strong>.</p>
<p>You have a pet named <strong>Mr. Bigglesworth</strong>.</p>
<p>You have a pet named <strong>K-9</strong>.</p>

內聯寫法:

@using Microsoft.AspNetCore.Html

@functions {
    public static IHtmlContent Repeat(IEnumerable<dynamic> items, int times,
        Func<dynamic, IHtmlContent> template)
    {
        var html = new HtmlContentBuilder();

        foreach (var item in items)
        {
            for (var i = 0; i < times; i++)
            {
                html.AppendHtml(template(item));
            }
        }

        return html;
    }
}

<ul>
    @Repeat(pets, 3, @<li>@item.Name</li>)
</ul>

結果為:

<ul>
    <li>Rin Tin Tin</li>
    <li>Rin Tin Tin</li>
    <li>Rin Tin Tin</li>
    <li>Mr. Bigglesworth</li>
    <li>Mr. Bigglesworth</li>
    <li>Mr. Bigglesworth</li>
    <li>K-9</li>
    <li>K-9</li>
    <li>K-9</li>
</ul>

Razor語法規則雜項[編輯]

  • 代碼語句以分號結尾
  • 字符串由引號包圍
  • 變量用關鍵字var聲明
  • C#代碼對大小寫敏感

Razor類型轉換[編輯]

可以用As系列擴展方法和Is系列擴展方法:

  • AsInt(), IsInt()
  • AsBool(),IsBool()
  • AsFloat(),IsFloat()
  • AsDecimal(),IsDecimal()
  • AsDateTime(),IsDateTime()
  • ToString()

示例[編輯]

    <!-- 单行代码块 -->
    @{ var myMessage =	"Hello World"; }
     
    <!-- 行内表达式或变量 -->
    <p>The value of myMessage is: @myMessage</p> 
     
    <!-- 多行语句代码块 -->
    @{
    var greeting = "Welcome to our site!";
    var weekDay = DateTime.Now.DayOfWeek;
    var greetingMessage = greeting + " Here in Huston it is: " + weekDay;
    }
    <p>The greeting is: @greetingMessage</p>


讀取用戶在動態網頁上的輸入[編輯]

由Request[] 函數讀取輸入,並由 IsPost條件進行測試:

    @{
    var totalMessage = "";
    if(IsPost)
        {
        var num1 = Request["text1"];
        var num2 = Request["text2"];
        var total = num1.AsInt() + num2.AsInt();
        totalMessage = "Total = " + total;
        }
    }
    <html>
    <body style="background-color: beige; font-family: Verdana, Arial;">
    <form action="" method="post">
    <p><label for="text1">First Number:</label><br>
    <input type="text" name="text1" /></p>
    <p><label for="text2">Second Number:</label><br>
    <input type="text" name="text2" /></p>
    <p><input type="submit" value=" Add " /></p>
    </form>
    <p>@totalMessage</p>
    </body>
    </html>