文章目录
代码
View
传递数据到Views
控制器和视图在同一进程中运行。要传递数据,可以使用ViewDataDictionary。ViewData,Key为String,Value为Object。ViewBag是一种动态类型,可以指定任何属性名称以将数据传递给View。
public IActionResult PassingData()
{
ViewBag.MyData = "Hello from the controller";
return View();
}
<h2>@ViewBag.MyData</h2>
Razor 语法
在ASP.NET Core MVC 中,可以在View上使用Razor语法写C#代码。
<div>@ViewBag.MyData</div>
@{
string name = "Angela";
}
<div>@name</div>
@foreach(var item in list)
{
<li>The item name is @item.</li>
}
在某些情况下,无法自动检测C#代码的结尾。可以使用括号解决此问题,如下所示
<div>@(name), Stephanie</div>
创建强类型视图
Controller传递数据给View的另一种方法是传递Model,使用Model可以创建强类型视图。
Controller
public IActionResult PassingAModel() => View(GetSampleData());
private IEnumerable<Menu> GetSampleData() =>
new List<Menu>
{
new Menu
{
Id = 1,
Text = "宫保鸡丁",
Price = 6.9,
Category = "Main"
},
new Menu
{
Id = 2,
Text = "水煮牛肉",
Price = 6.9,
Category = "Main"
},
new Menu
{
Id = 3,
Text = "辣炒蛤蜊",
Price = 6.9,
Category = "Main"
}
};
View
@using MVCSampleApp.Models
@model IEnumerable<Menu>
<div>
<ul>
@foreach (var item in Model)
{
<li>@item.Text</li>
}
</ul>
</div>
布局
使用VS创建_ViewStart.cshtml——定义所有View是否需要布局页。(在Views目录下创建)
@{
Layout = "_Layout";
}
如果所有View不需要layout,可以将Layout设为null
@{
Layout = null;
}
默认布局页
@RenderBody()呈现网页内容
默认布局页
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
经过修改的
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initialscale=1.0" />
<title>@ViewBag.Title</title>
<environment include="Development">
<link rel="stylesheet"
href="~/lib/bootstrap/dist/css/bootstrap.css" />
<link rel="stylesheet" href="~/css/site.css" />
</environment>
<environment exclude="Development">
<link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.7/css/bootstrap.min.css"
asp-fallbackhref=" ~/lib/bootstrap/dist/css/bootstrap.min.css"
asp-fallback-test-class="sr-only" asp-fallback-testproperty="position" asp-fallback-test-value="absolute" />
<link rel="stylesheet" href="~/css/site.min.css" aspappend-version="true" />
</environment>
<title>@ViewBag.Title - My ASP.NET Application</title>
</head>
<body>
<div class="container body-content">
<header>
<h1>ASP .NET MVC例子</h1>
</header>
<nav>
<ul>
<li><a asp-controller="ViewsDemo" asp-action="LayoutSample">LayoutSample</a></li>
<li><a asp-controller="ViewsDemo" asp-action="LayoutUsingSections">Layout Using Sections</a></li>
</ul>
</nav>
<div>
@RenderBody()
</div>
<hr />
<footer>
<p>
<div>Sample Code for Professional C#</div> @DateTime.Now.Year - My ASP.NET Application
</p>
</footer>
</div>
</body>
</html>
添加LayoutSample页面
@{
ViewData["Title"] = "LayoutSample";
}
<h2>LayoutSample</h2>
结果
Sections
使用Sections,在View的某个位置上添加内容。
以下代码段使用名为PageNavigation的Section。 默认情况下需要此section,如果section未定义,则加载视图将失败。 当required参数设置为false时,section变为可选
<!–– ... ––>
<div>
@RenderSection("PageNavigation", required: false)
</div>
<div>
@RenderBody()
</div>
<!–– ... ––>
添加LayoutUsingSections页面
@{
ViewBag.Title = "Layout Using Sections";
}
<h2>使用Sections的Layout</h2>
<div>这是主要内容</div>
@section PageNavigation
{
<div>拥有Navigation的View</div>
<ul>
<li>Nav1</li>
<li>Nav2</li>
</ul>
}
结果
Sections不仅仅在Html中的Body放置内容,还可以应用于head中的一些标签——例如metadata
使用Partial View定义内容
Layout为Web应用程序中的多个页面提供了总体定义,而Partial View是定义视图中的内容。 局部视图没有布局。而且,Partial View和普通View很像,Partial View和普通View有相同的基类,它们都有Model。
现在,从模型开始,该模型包含由EventsAndMenusContext类定义的independent collections,events和menus 的属性。
public class EventsAndMenusContext
{
private IEnumerable<Event> GetEvents() =>
new List<Event>
{
new Event (1, "Formula 1 G.P. Australia, Melbourne", new DateTime(2018, 3, 25)),
new Event(2, "Formula 1 G.P. Bahrain, Sakhir", new DateTime(2018, 4, 8)),
new Event(3, "Formula 1 G.P. China, Shanghai", new DateTime(2018, 4, 15)),
new Event(4, "Formula 1 G.P. Aserbaidschan, Baku", new DateTime(2018, 4, 29))
};
private IEnumerable<Menu> GetMenus() =>
new List<Menu>
{
new Menu
{
Id=1,
Text="Baby Back Barbecue Ribs",
Price=16.9,
Category="Main"
},
new Menu
{
Id=2,
Text="Chicken and Brown Rice Piaf",
Price=12.9,
Category="Main"
},
new Menu
{
Id=3,
Text="Chicken Miso Soup with Shiitake Mushrooms",
Price=6.9,
Category="Soup"
}
};
private IEnumerable<Event> _events = null;
public IEnumerable<Event> Events
{
get => _events ?? (_events = GetEvents());
}
private IEnumerable<Menu> _menus = null;
public IEnumerable<Menu> Menus
{
get => _menus ?? (_menus = GetMenus());
}
}
为了让控制器构造函数注入类型,需要在startup类中使用依赖注入注册EventsAndMenusContext类。
在服务端代码使用部分视图
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
...
//为了让控制器构造函数注入类型,需要在startup类中使用依赖注入注册EventsAndMenusContext类。
services.AddScoped<EventsAndMenusContext>();
}
Controller
public IActionResult UseAPartialView1() => View(_context);
View
@using MVCSampleApp.Models
@model EventsAndMenusContext
@{
ViewBag.Title = "Use a Partial View";
ViewBag.EventsTitle = "Live Events";
}
<h2>使用部分视图</h2>
<div>主视图</div>
<div>
@await Html.PartialAsync("ShowEvents", Model.Events)
</div>
结果
可以使用同步方法Html.Partial替代Html.PartialAsync。
在View中呈现partial view的另一种方法是使用HTML Helper方法Html.RenderPartialAsync,该方法被定义为返回Task。 此方法直接将部分视图内容写入响应流。
partial view也支持ViewBag
@using MVCSampleApp.Models
@model IEnumerable<Event>
<h2>@ViewBag.EventsTitle</h2>
<table>
@foreach (var item in Model)
{
<tr>
<td>@item.Day.ToShortDateString()</td>
<td>@item.Text</td>
</tr>
}
</table>
返回部分视图
部分视图可以通过控制器返回
Controller
public ActionResult UseAPartialView2() => View();
public ActionResult ShowEvents()
{
ViewBag.EventsTitle = "Live Events";
return PartialView(_context.Events);
}
View
利用fetch代替Ajax从服务器下载部分视图
@using MVCSampleApp.Models
@model EventsAndMenusContext
@{
ViewBag.Title = "Use a Partial View";
}
<script src="~/lib/jquery/dist/jquery.js"></script>
<script>
(function () {
window.onload = function () {
var buttonEvents = document.getElementById("getEvents");
buttonEvents.onclick = function () {
if (window.fetch == null) {
output.innerHTML = "<div>window.fetch not supported. Use another browser</div>";
return;
}
//利用fetch代替Ajax从服务器下载部分视图
var result = fetch("/ViewsDemo/ShowEvents");
result.then(function (response){
return response.text();
}).then(function (text){
var output = document.getElementById("output");
output.innerHTML = text;});
};
};
})();
</script>
<h2>使用部分视图</h2>
<div>主页面</div>
<button id="getEvents">加载部分视图按钮</button>
<div id="output">
</div>
结果
View Component
ASP.NET Core MVC 提供了部分视图的替代方法:View Component。View Component与Partial View非常相似; 主要区别在于View Component没有Controller。 这使得View Component可以轻松地和多个控制器一起使用。View Component真正有用的地方是菜单的动态导航,登录面板或博客中的侧边栏内容。这些场景对独立的单个控制器非常友好。
与Controller和View一样,View Component有两个部分。对于View Component,ViewComponent(或具有ViewComponent属性的POCO类)派生的类会接管Controller的功能。用户界面的定义与View类似,但调用view component的方法不同。
public class EventListViewComponent : ViewComponent
{
//需要在Startup中注册的EventsAndMenusContext类型。
private readonly EventsAndMenusContext _context;
public EventListViewComponent(EventsAndMenusContext context)
{
_context = context;
}
/// <summary>
/// InvokeAsync方法定义为从显示ViewComponent的View中调用。
/// 此方法可以包含任何数量和类型的参数,因为IViewComponentHelper接口定义的方法使用params关键字定义了灵活数量的参数。
/// 也可以使用同步实现此方法,返回的是IViewComponentResult。
/// 最好使用异步,例如访问数据库。
/// view component需要存储在ViewComponents目录中。 该目录本身可以放在项目中的任何位置
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public Task<IViewComponentResult> InvokeAsync(DateTime from, DateTime to) =>
Task.FromResult<IViewComponentResult>(View(EventsByDateRange(from, to)));
private IEnumerable<Event> EventsByDateRange(DateTime from, DateTime to) =>
_context.Events.Where(e => e.Day >= from && e.Day <= to);
}
View
View Component的View可以使用MVC View Page模板创建。目录要求:Components / [viewcomponent]文件夹中——例如,Components / EventList。
用于特定视图还是用于公共?
要使view component可用于所有控件,需要创建Views/Shared/Components文件夹。
当您仅使用来自一个特定controller的view component时,可以将其放入视图控制器(view Controller)文件夹中。但是,与此视图的不同之处在于它需要命名为default.cshtml。也可以创建其他视图名称; 需要使用InvokeAsync方法返回的View方法的参数指定这些视图。
Views/Shared/Components/EventList/default.cshtml
@using MVCSampleApp.Models;
@model IEnumerable<Event>
<h3>Formula 1 Calendar</h3>
<ul>
@foreach (var ev in Model)
{
<li>
<div>@ev.Day.ToString("D")</div><div>@ev.Text</div>
</li>
}
</ul>
VIew:UseViewComponent1
@{
ViewBag.Title = "View Components Sample";
}
<h2>@ViewBag.Title</h2>
<p>
@*Component是View的动态创建属性(dynamically created property),它返回实现IViewComponentHelper的对象。
IViewComponentHelper允许调用同步或异步方法
需要使用Dictionary <string,object>传递参数,其中键与参数名称匹配*@
@await Component.InvokeAsync("EventList", new
Dictionary<string, object>()
{
["from"] = new DateTime(2018, 4, 1),
["to"] = new DateTime(2018, 4, 20)
})
</p>
VIew:UseViewComponent2
从ASP.NET Core 1.1开始,就可以使用Tag Helpers调用view component。 Tag Helpers使用类似HTML的代码编写,简化了视图的代码。如果想使用Tag Helpers,需要使用view component所在的程序集的名称添加@addTagHelper指令,才能使用vc标记引用视图组件。在vc标记的冒号之后,跟随视图组件的名称。使用Pascal命名约定定义类时,Tag Helper通过切换为小写字母(而不是大写字母),添加下划线来更改名称; ,因此EventList成为event-list
@addTagHelper *, MVCSampleApp
@{
ViewBag.Title = "View Components Sample";
}
<h2>@ViewBag.Title</h2>
<vc:event-list from="@new DateTime(2018, 4, 1)" to="@new DateTime(2018, 4, 20)" />
结果(http://localhost:2253/viewsdemo/UseViewComponent1)
在View里使用依赖注入
如果View里直接需要一个service,可以使用关键词inject注入。并且最好使用AddScoped方法注册服务。如前所述,以这种方式注册服务意味着它只对一个HTTP请求实例化一次。 使用AddScoped,在控制器和视图中注入相同的服务,它仅为请求实例化一次。
@using MVCSampleApp.Services
@inject ISampleService sampleService
<p>
@string.Join(" * ", sampleService.GetSampleStrings())
</p>
对多个View导入命名空间
使用_ViewImports.cshml文件对每个view进行添加using,不必对每个view进行单独添加。
@using MVCSampleApp.Models
@using MVCSampleApp.Services