ASP.NET MVC 5 Web编程4 -- Razor视图引擎

Razor简介

Razor是ASP.NET新增的一个视图引擎,由微软全球最年轻的副总裁,有着"ASP.NET之父"称呼的Scott Guthrie主导的团队开发。

主导Razor开发的Scott Guthrie,毕业于美国杜克大学。现任微软云计算与企业级产品工程部执行副总裁。

Razor对传统aspx页面的写法和页面渲染能力提出了反思,所以它在代码书写和HTML生成方面都进行了优化。Rzaor的设计目标遵循以下几点:

a). 尽量减少代码

b). 上手快,只需要现有的编程语言和基本的HTML知识

c). 可以使用记事本编写

d). 便于单元测试

Rzaor视图引擎页面以.cshtml(或.vbhtml)文件后缀结尾,是ASP.NET MVC 5默认使用的页面展现形式。

Razor与.aspx视图引擎对比

为了有一个直观的认识,我们先来看一个简单的用户管理页面的实现:

假定上图的页面呈现效果就是我们的最终目标。先来看Razor实现的页面:

@{
    Layout = null;
}

@model IEnumerable<MVC5Demo.Models.UserInfoViewModel>

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="~/Content/bootstrap.min.css" rel="stylesheet" />
    <title></title>
</head>
<body>
    <div>
        @Html.ActionLink("新增", "Add", "UserInfo")
        <hr />
        <h3>用户信息列表</h3>
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <th>姓名</th>
                        <th>性别</th>
                        <th>年龄</th>
                        <th>部门</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var item in Model) {
                    <tr>
                        <td>@Html.DisplayFor(p => item.UserName)</td>
                        <td>@(item.Sex == 0 ? "女" : "男")</td>
                        <td>@Html.DisplayFor(p => item.Age)</td>
                        <td>@Html.DisplayFor(p => item.Dept)</td>
                        <td>@Html.ActionLink("编辑", "Edit", "UserInfo", new { id=item.UserID.ToString() },null) @Html.ActionLink("删除", "Delete", "UserInfo", new { id = item.UserID.ToString() }, new { onclick="return confirm(‘确认删除"+item.UserName+"的记录?‘);" })</td>
                    </tr>
                    }
                </tbody>
            </table>
        </div>

    </div>
</body>
</html>

同时贴出传统aspx页面的代码(注:样式代码部分省略):

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="MVC5Demo.WebForms.UserInfo.WebForm1" %>

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:LinkButton runat="server" Text="新增" PostBackUrl="~/add.aspx" />
    <div style="height: 267px">
        <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" >
            <Columns>
                <asp:BoundField DataField="UserName" HeaderText="姓名" />
                <asp:BoundField DataField="Sex" HeaderText="性别" />
                <asp:BoundField DataField="Age" HeaderText="年龄" />
                <asp:BoundField DataField="Dept" HeaderText="部门" />
                <asp:CommandField HeaderText="编辑" ShowEditButton="true" />
                <asp:CommandField HeaderText="删除" ShowDeleteButton="true" />
            </Columns>
        </asp:GridView>
    </div>
    </form>
</body>
</html>

站在Razor的角度,

与传统aspx页面实现的代码不同,主要是以下几点:

1. 没有使用"GridView" 服务器控件(或者说没有这样的控件可以使用);

2. 使用@符号代替<%= %>来访问服务器代码;

3. 使用MVC提供的HTML辅助函数来渲染页面(代替服务器控件形式);

4. 其他不同点(如页头)。

可以看到,Razor的页面处理更"精细",在页面展示上有点类似jsp(或者说回到了asp?),你需要具备基本的HTML知识(如画Table),因为"视图设计器","服务器控件"这些你曾经熟悉的东西,"不存在"了。

我们再来看看两种视图引擎生成的HTML源代码的差异。先来看Razor页面生成的HTML:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <link href="/Content/bootstrap.min.css" rel="stylesheet" />
    <title></title>
</head>
<body>
    <div>
        <a href="/UserInfo/Add">新增</a>
        <hr />
        <h3>用户信息列表</h3>
        <div class="table-responsive">
            <table class="table table-striped table-bordered">
                <thead>
                    <tr>
                        <th>姓名</th>
                        <th>性别</th>
                        <th>年龄</th>
                        <th>部门</th>
                        <th>操作</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>lili</td>
                        <td>女</td>
                        <td>22</td>
                        <td>Human Resource</td>
                        <td><a href="/UserInfo/Edit/e92cfb5c-e81a-4cfc-9d85-1bc77f9fab75">编辑</a> <a href="/UserInfo/Delete/e92cfb5c-e81a-4cfc-9d85-1bc77f9fab75" onclick="return confirm('确认删除lili的记录?');">删除</a></td>
                    </tr>
                    <tr>
                        <td>zhangsan</td>
                        <td>女</td>
                        <td>0</td>
                        <td>Resource</td>
                        <td><a href="/UserInfo/Edit/e4b9c9f2-afd4-45f4-bb3d-1ca2c91642b3">编辑</a> <a href="/UserInfo/Delete/e4b9c9f2-afd4-45f4-bb3d-1ca2c91642b3" onclick="return confirm('确认删除zhangsan的记录?');">删除</a></td>
                    </tr>
                    <tr>
                        <td>hangwei</td>
                        <td>男</td>
                        <td>26</td>
                        <td>Technology</td>
                        <td><a href="/UserInfo/Edit/3fdc971a-20c0-4016-b09b-703db265e972">编辑</a> <a href="/UserInfo/Delete/3fdc971a-20c0-4016-b09b-703db265e972" onclick="return confirm('确认删除hangwei的记录?');">删除</a></td>
                    </tr>
                    <tr>
                        <td>xiaoya</td>
                        <td>女</td>
                        <td>20</td>
                        <td>Human Resource</td>
                        <td><a href="/UserInfo/Edit/64bb557a-0eae-4554-8258-99412f4a0c78">编辑</a> <a href="/UserInfo/Delete/64bb557a-0eae-4554-8258-99412f4a0c78" onclick="return confirm('确认删除xiaoya的记录?');">删除</a></td>
                    </tr>
                    <tr>
                        <td>lulu</td>
                        <td>女</td>
                        <td>19</td>
                        <td>public relation</td>
                        <td><a href="/UserInfo/Edit/d2da9745-8423-468d-b16c-a5f1e220228b">编辑</a> <a href="/UserInfo/Delete/d2da9745-8423-468d-b16c-a5f1e220228b" onclick="return confirm('确认删除lulu的记录?');">删除</a></td>
                    </tr>
                </tbody>
            </table>
        </div>

    </div>

<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
    {"appName":"InternetExplorer","requestId":"e66859a98d6d44589621dafbc30ed07b"}
</script>
<script type="text/javascript" src="http://localhost:38131/ed029686c8c448a4ad16768559cf6138/browserLink" async="async"></script>
<!-- End Browser Link -->

</body>
</html>

总的来说,非常"干净"。跟Razor书写的代码几乎一样。再来看aspx页面生成的HTML:

<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>

</title></head>
<body>
    <form method="post" action="WebForm1.aspx" id="form1">
<div class="aspNetHidden">
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="dGzszrXmAWyS03LAAgn9Mu1+oe52zJZWXOwK8eBrCoGaaS/NrVfZYEyrJvwBzrLQUvloUdjMnLIMY6ou+eUPBQzAbrXsu1pxuWUlqErhvIGpI/ZFKrtfWqhpA1Eh5Dwn8ITIgsK9q4FP+qZ7dHk7EdtIwrvR4JHcwaBwS1jc17WIRdeeMDIfC3/Bo4fED1739IKFjjnc6Wo+8LjZ/gvo/NY3Z6aKjdPrOd7Kaiali/xL8TvA6q51KDyb0xn+FIOs4gKtotrzhfrB6mjRlgSU9VRv/V8vghdES0qtH7zRBNgUK+APeUNrdWvbS/bdNbtOqmmyAAUhj+UxB98lP1Uq2/6GwNKdUhcqfPyB1tFVGKtASLQnSRyvhMHReAn6SlMFGbr/Iks8DG2ZGHpe9+9walyoEwkYSO3HwbJx8ZwYilUuAPnaXm9PhtrBmfKS+JWln9qPTz5Ene1+cfRMo/JrOv9PHE7geq5apg5XbqEONnHMRp5gf6foGSUozbmkjEPrqtVal8cmVMyLYFXmegRS0QNhyUxf9MW4O392d0FnpCqWomY6iX7f1Zufd8rfAA6/shzOd4tKmHr+aDnXjeEjVuPn4MAQj7F2SAKonTwn7MbHpStwqggpax6ouj9Rv1F2Apew7oe6RTcf4jD1PGneseg32CVZlgtDO/jU38wW8Ot56dqayPEq6WNXUPbyJ/jUbT4bKWcN7TllXjdBfIiqo5puP4ZFkK1Jeeeah7oScwU=" />
</div>

<script type="text/javascript">
//<![CDATA[
var theForm = document.forms[‘form1‘];
if (!theForm) {
    theForm = document.form1;
}
function __doPostBack(eventTarget, eventArgument) {
    if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
        theForm.__EVENTTARGET.value = eventTarget;
        theForm.__EVENTARGUMENT.value = eventArgument;
        theForm.submit();
    }
}
//]]>
</script>

<script src="/WebResource.axd?d=pynGkmcFUV13He1Qd6_TZPjjg_3PjzXOZ2RR84591qrPEBSFqiIUM7TmWtTTY9Q7RVnJXgsOCIupr1tET1vQvA2&amp;t=635586541120000000" type="text/javascript"></script>

        <a href="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions(&quot;ctl03&quot;, &quot;&quot;, false, &quot;&quot;, &quot;../add.aspx&quot;, false, true))">新增</a>
    <div style="height: 267px">
        <div>
    <table cellspacing="0" rules="all" border="1" id="GridView1" style="border-collapse:collapse;">
        <tr>
            <th scope="col">姓名</th><th scope="col">性别</th><th scope="col">年龄</th><th scope="col">部门</th><th scope="col">编辑</th><th scope="col">删除</th>
        </tr><tr>
            <td>lili</td><td>0</td><td>22</td><td>Human Resource</td><td><a href="javascript:__doPostBack('GridView1','Edit$0')">编辑</a></td><td><a href="javascript:__doPostBack('GridView1','Delete$0')">删除</a></td>
        </tr><tr>
            <td>zhangsan</td><td>0</td><td>0</td><td>Resource</td><td><a href="javascript:__doPostBack('GridView1','Edit$1')">编辑</a></td><td><a href="javascript:__doPostBack('GridView1','Delete$1')">删除</a></td>
        </tr><tr>
            <td>hangwei</td><td>1</td><td>26</td><td>Technology</td><td><a href="javascript:__doPostBack('GridView1','Edit$2')">编辑</a></td><td><a href="javascript:__doPostBack('GridView1','Delete$2')">删除</a></td>
        </tr><tr>
            <td>xiaoya</td><td>0</td><td>20</td><td>Human Resource</td><td><a href="javascript:__doPostBack('GridView1','Edit$3')">编辑</a></td><td><a href="javascript:__doPostBack('GridView1','Delete$3')">删除</a></td>
        </tr><tr>
            <td>lulu</td><td>0</td><td>19</td><td>public relation</td><td><a href="javascript:__doPostBack('GridView1','Edit$4')">编辑</a></td><td><a href="javascript:__doPostBack('GridView1','Delete$4')">删除</a></td>
        </tr>
    </table>
</div>
    </div>

<div class="aspNetHidden">

    <input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="B24E7CB3" />
    <input type="hidden" name="__PREVIOUSPAGE" id="__PREVIOUSPAGE" value="cLskMNrn93I_KrBWtzNjrdnU4nEVf6xwwXS72kJcSzZSQTv9se1ft7fisMnkWVQ7Z1_Y9_pWYR72hqYsEfzaCrwR6i_KuWzhFn_wlzM3p741" />
    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="9sDy55QrEe0ZfiQhGKNvPEncESgVyis86+m/35or5jtV71SyrczxxZtNqnclLUIYCY9SxVMVhFTtH6/dC1a0JcJVCXr3M2w7+s4NlG+yZzYeecp4VCuGddyDMFStphryD6ncUMbxyJg5pLmFN56lo48qLRH9fBpud2tV4CyA4R1XsSIq6tmqduRgR43l/GP82S6BAn8w8pjMhqiw93soSt1S0Rt+QbNzDL/3mcJBpwn+yFK5gF0DuOly6Bb3OAv5HFp90N/rFDjogMMY+eHhOx97R/7BKXyqfyhKG3wg0H2ek4zQlKVhzC7KwX56hq1rD5SrQpg+u0qTdaxkZsOKuw==" />
</div></form>

<!-- Visual Studio Browser Link -->
<script type="application/json" id="__browserLink_initializationData">
    {"appName":"InternetExplorer","requestId":"20a0a7414285497caad40f738f0947ce"}
</script>
<script type="text/javascript" src="http://localhost:38131/ed029686c8c448a4ad16768559cf6138/browserLink" async="async"></script>
<!-- End Browser Link -->

</body>
</html>

直观的,多了些"ViewState"。以上对比是不是就能说明MVC从性能和书写方面比WebForms好呢?

关于这点,首先注意Razor介绍里,Razor是一个独立的渲染引擎。至今为止没有专业的团队从性能的角度去测试它和WebForms的区别并给出实际结果的(估计结果相差不大)。其次,我个人比较赞同老赵的观点(为WebForms说几句话),高性能Web应用程序大多与具体所用的实现技术无关。MVC和WebForms各有各的好处和适合的应用场景,一味的压低WebForms抬高MVC,有种跟风和墙头草嫌疑。

Razor语法

1). @标示符

@符号表示Razor代码块的开始,无需像WebForms那样,加‘%>‘表示结束。Razor会自动从@符号的右边开始,判断哪些是后台代码,哪些是前台HTML。

2). 普通输出

如在.cshtml文件中,输入下面的代码:

@DateTime.Now;

前台会显示什么呢?如下图:

前台显示 时间+";"(注意这个分号),在单语句@符号后,进行代码书写,是不需要加分号的,加分号会被当做HTML文本来输出到前台。

     如果进行代码和文本混合编写,可以这样:

时间 @DateTime.Now 星期: @DateTime.Now.DayOfWeek

文本和Razor代码,中间加空格,这样视图引擎就可以判定@后是代码部分。

关于文本和代码混合,还有一种简单的方式:

@("today is :" + DateTime.Now.Year + "year.")

使用@(),来进行多符号语句输出。

3). 在语句块中输出

语句块,使用@{}来表示一段代码。

        @{
            @DateTime.Now.Month;
            <br />
            <label>块中变量输出:</label>
            int x = 8;
            @x;
        }

在语句块中,需要注意的是:

a. 使用@符号进行输出,并且由于块中遵循C#代码机制,建议加分号(‘;‘),这个分号不会输出到前台页面;

b. 直接使用HTML标签,会自动被识别为前台代码。这点真的很方便,想想在一个C#代码的编译环境,直接写HTML标签输出...;

c. 不能直接输出字符,如直接在代码块中书写"Test" ,Test 等,都是不被允许的,请谨记代码块中遵循的是C#(或VB)环境;

d. 其它书写方式同后台代码。

4). HTML辅助函数

以往的方式,我们是在代码中向前台输出HTML文本,这可以实现,但,不是很理想。像我本人,以前还使用了像jsrender这样的页面渲染方式。现在,借助于Razor的HTML辅助函数,可以轻松实现代码输出HTML。

使用@helper 语法,自定义辅助函数(代码片段可以放在任意位置)。

    @helper pList(List<string> lst)
    {//HTML辅助函数
        <ul>
            @foreach (string p in lst)
            {
                <li>@p</li>
            }
        </ul>
    }

然后使用

        HTML辅助函数:
        @{
            List<string> lsts = new List<string> { "a", "b", "c", "d", "e" };
            @pList(lsts);
        }

由于定义了名为pList的函数,使用时直接调用即可。

5). 其它

a)一些书写习惯,作用上是等价的,如条件判断、循环分支:

        @if (1 == 1) {
        }
        @foreach (string p in lsts){
        }
        @{
            if (1 == 1) { }
            foreach (string p in lsts) { }
        }

b)代码注释,使用@*  ...  *@

        @*
            代码注释符:
            http://www.cnblogs.com/hangwei
        *@

c)输出@符号,使用 @@

d)字符串转换

       字符串转换:
        @{
            string str = "10000";
            @str.AsInt();//在块中遵循后台代码形式
        }

6). 布局(模板)的使用

a)layout布局页的使用

首先你需要在MVC工程下的Views/Shared目录下,新建一个视图文件(此目录默认用来存放layout(模板)文件)。这里我们新建一个TestLayout.cshtml,代码如下:

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>
    1.TestLayout是模板页 @DateTime.Now.ToString("HH:mm:ss.fff")
    </div>
    <div id="content"><!--内容页的内容会出现在此div中-->
        @RenderBody()
    </div>
</body>
</html>

定义好布局页的内容 ,子页的部分,用@RenderBody()表示。再新建一个子页套用此布局页,代码如下:

@{
    Layout = "~/Views/Shared/TestLayout.cshtml";
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title></title>
</head>
<body>
    <div>
    2.Index页面 @DateTime.Now.ToString("HH:mm:ss.fff")
    </div>
</body>
</html>

在页面的开始部分,使用Layout指定模板页的地址即可。我们再来看前台显示效果:

需要注意的是:MVC跟WebForms不同,子页是先于布局页被显示(渲染)出来的。

b)布局页的灵活使用(RenderSection)

有时我们需要页面的区域内容不是由布局页定,而是动态的,由子页自己决定内容的呈现。这时就使用到了RenderSection。比如我们在布局页TestLayout.cshtml加入以下代码:

    <div id="menu">
        <!--让子页决定如何呈现menu-->
        @RenderSection("menu", false) @*注意此方法跟MVC前版可能不同,false表示可选(非必须)*@
    </div>

再在子页中加入以下代码:

    @section menu{
        <ul id="subMenu">
            <li>Item1</li>
            <li>Item2</li>
        </ul>
    }

前台显示效果:

总结

本文主要对Razor的创立,Razor和WebForms视图引擎的对比做了简单介绍;同时详细介绍了Razor的语法。在下一章中,将介绍MVC5页面之间的传值,敬请期待~

希望本文对你有帮助。

时间: 2024-10-28 23:34:50

ASP.NET MVC 5 Web编程4 -- Razor视图引擎的相关文章

ASP.NET MVC 5 Web编程5 -- 页面传值的方式

本篇文章将讲述MVC的页面传值方式,具体包括:后端向前端传值(Controller向View传值):前端向后端传值(View向Controller传值):Action与Action之间的传值. 回顾 我们回顾下在ASP.NET WebForms中,页面之间最常用的传值方式,有以下几种: a). QueryString(也叫URL传值) b). Session c). Cookie d). Application e). Server.Transfer 这里不再讲述这几种传值方式的用法和利弊,在本

ASP.NET MVC 5 Web编程2 -- URL映射(路由原理)

本章将讲述ASP.NET MVC5 的路由原理,即URL映射机制. 简单点就是解释:为什么MVC在浏览器输入地址就能访问到类(或类中的方法)?这是怎么做到的?我自己可以通过.NET写出一个自己的MVC框架吗? 答案是:可以. 模拟URL映射 先来看一个Demo,在传统的.NET WebForms项目中,实现URL的拦截. 打开VS2013,新建一个“ASP.NET Web窗体应用程序”项目,并取名为Demo4URLRouting. 为了方便测试,注释掉Default.aspx页面的内容和模板引用

ASP.NET MVC 5 Web编程1 -- 入门

开篇引言 说起ASP.NET MVC,我想作为WebForms开发者第一点要问的是:为什么要使用它?我的理解是:MVC是更细节化的框架,“细节可控”意味着你的系统更精致.具体体现在应用上.MVC的出现,可能正是迎合Web开发越来越精致的需求.就我了解的一个大型投资管理电商平台,所用的架构就是ASP.NET MVC.MVC将来在系统应用的趋势,很可能就是大型电子商务平台.当然,WebForms并不是被“抛弃”,在快速开发,控件复用上,WebForms依然走在前面.有时候,根据需要,我们可以在同一项

ASP.NET MVC 5 Web编程3 -- Controller的应用及扩展

http://www.midifan.com/moduleuser-index-420934.htmhttp://www.midifan.com/moduleuser-index-420949.htmhttp://www.midifan.com/moduleuser-index-421026.htmhttp://www.midifan.com/moduleuser-index-420782.htmhttp://www.midifan.com/moduleuser-index-421061.htm

Razor 视图引擎的一些属性和方法

参考网址:http://www.cnblogs.com/hangwei/p/4391058.html ASP.NET MVC 5 Web编程4 -- Razor视图引擎 2015-04-30 09:00 by hangwei, 1575 阅读, 1 评论, 收藏, 编辑 Razor简介 Razor是ASP.NET新增的一个视图引擎,由微软全球最年轻的副总裁,有着"ASP.NET之父"称呼的Scott Guthrie主导的团队开发. 主导Razor开发的Scott Guthrie,毕业于

ASP.NET Razor 视图引擎编程参考

ASP.NET Razor 视图引擎编程参考 转载请注明出处:http://surfsky.cnblogs.com Rasor 视图引擎    http://msdn.microsoft.com/zh-cn/library/ff849693.aspx    http://www.microsoft.com/downloads/en/details.aspx?FamilyID=b7937c34-3b53-47b7-ae17-5a72fa700472&displaylang=en    http:/

asp.net mvc vs web form

译者介绍 小小.NET学童,滴答…滴答…的雨…… 正文如下======================================================= 原文示例(VS2012): 1.  Download Simple WebForm demo - 6.7 KB 2.  Download Simple MVC Demo demo - 1.5 MB 介绍 我做为一名ASP.NET开发人员已经有很长时间了,并且我非常乐意使用ASP.NET Web Forms开发web应用程序. 在

ASP.Net MVC开发基础学习笔记(3):Razor视图引擎、控制器与路由机制学习

首页 头条 文章 频道                         设计频道 Web前端 Python开发 Java技术 Android应用 iOS应用 资源 小组 相亲 频道 首页 头条 文章 小组 相亲 资源 设计 前端 Python Java 安卓 iOS 登录 注册 首页 最新文章 经典回顾 开发 Web前端 Python Android iOS Java C/C++ PHP .NET Ruby Go 设计 UI设计 网页设计 交互设计 用户体验 设计教程 设计职场 极客 IT技术

Razor 视图引擎 &ndash; ASP.NET MVC 4 系列

       Razor 视图引擎是 ASP.NET MVC 3 开始扩展的内容,并且也是默认视图引擎.        Razor 通过理解标记的结构来实现代码和标记之间尽可能顺畅的转换.下面的例子演示了一个包含少量视图逻辑的简单 Razor 视图: @{ // this is a block of code. For demonstration purposes, // we'll create a "model" inline. var items = new string[] {