前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ASP.NET Core Views系列二

ASP.NET Core Views系列二

作者头像
郑子铭
发布2023-08-30 10:21:08
1920
发布2023-08-30 10:21:08
举报
文章被收录于专栏:DotNet NB && CloudNative

8 Partial 视图

部分视图是普通的视图文件(.cshtml),可以嵌入到另外的视图文件里,这意味这相同的视图文件能被使用在多个地方并且减少代码重复,如果在我们应用程序中有重复的视图,我们可以将这个视图作为部分视图,在别的视图中加载这个文件,这种方式可以阻止代码重复

在Views->Shared目录下添加TestPratialView.cshtml视图

代码语言:javascript
复制
@model List<string>
<div class="border border-warning">
    This is partial View:
    <ul>
        @foreach (string str in Model)
        {
            <li>@str</li>
        }
    </ul>
</div>

这个视图文件接收一个List 类型,并且循环List中的每个项在页面上展示,我们可以通过下面方法在别的视图上引用这个部分视图@await Html.PartialAsync(“name_of_partialview”, model)

在TestLayout.cshtml视图中添加如下代码:

代码语言:javascript
复制
@await Html.PartialAsync("TestPartialView", new List<string> {
    "Classic ASP", "ASP.NET Web Forms", "ASP.NET MVC", "ASP.NET Core MVC"
})

如意我们传递部分视图的名字到@await Html.PartialAsync()方法,dotnet会在Shared目录下查找该文件,如果我们部分视图在别的目录下,我们必须提供视图所在文件的目录

运行应用程序进入 ,你将会发现部分视图的内容已经添加到视图上,展示如下:

9 视图组件

视图组件有些像部分视图但是又有一些不同,视图组件相比部分视图更强大,我们可以在里面创建服务器的逻辑,这是和部分视图完全不同的

视图组件是C#类,可以从视图中调用这个类并且我们提供数据模型到视图组件

有下面复杂的功能,你使用视图组件来完成而不是使用部分视图

1 在站点中创建身份验证面板,提供用户在不访问单独登录页面的情况下登录

2 根据用户的角色动态创建一个导航菜单

3 购物车面板,显示当前购物车中的产品

4 依赖性注射特征

视图组件是C#类继承于ViewComponent基类,视图组件必须定义一个Invoke()方法或者InvokeAsync()异步方法,在此方法中,视图组件必须执行为其创建的任务

视图组件可以在应用程序的任何地方创建,但是根据约定,我们一般创建在应用程序根目录下的Components文件夹

9.1 例子

让我们通过一个简单的例子来创建一个视图组件并且我们将会解释如何工作的,在解决方案目录下创建Components文件夹,在文件夹内创建一个Cart.cs类并且继承自ViewComponent基类在该类内部添加Invoke方法,代码如下:

代码语言:javascript
复制
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Views.Components
{
    public class Cart : ViewComponent
    {
        public string Invoke()
        {
            return "This is from View Component";
        }
    }
}

这个视图组件仅仅返回一个字符串消息,现在,从视图使用@await Component.InvokeAsync("NameofViewComponent")调用这个视图组件,这将调用视图组件中的Invoke方法

在_Layout.cshmtl中添加@await Component.InvokeAsync("Cart") 在页面顶部,代码如下:

代码语言:javascript
复制
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewData["Title"]</title>
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
</head>
<body>
    <header>
    </header>
    <div class="p-3 mb-2 border border-info">
        @await Component.InvokeAsync("Cart")
    </div>
</body>
</html>

现在运行应用程序,你将会看到字符串显示在页面上,检查下面图片

我们介绍一下视图组件的返回类型

9.2 视图组件的返回类型

在前面我们学习了关于视图组件返回字符串,视图组件也能返回IViewComponentResult接口通过调用Invoke方法,使用IViewComponentResult接口视图组件能够返回string,html,和partial view

类名

描述

ContentViewComponentResult

返回编码的HTML.例如Content("<h2>some text</h2>")

HtmlContentViewComponentResult

返回没有编码的HTML.例如HtmlContentViewComponentResult("<h2>some text</h2>")

ViewViewComponentResult

返回部分视图. Eg View("NameofView", model)

9.3 ContentViewComponentResult

ContentViewComponentResult类使用呈现编码的HTML针对视图组件,使用Content()方法创建一个ContentViewComponentResult类

让我们演示这个,修改Cart视图组件使用Content()方法返回IViewComponentResult类型

代码语言:javascript
复制
public IViewComponentResult Invoke()
{
   return Content("This is from <h2>View Component</h2>");
}

运行应用程序进行测试

如果检查页面源代码你会发现HTML被编码

代码语言:javascript
复制
This is from &lt;h2&gt;View Component&lt;/h2&gt;

这个HTML编码通过ASP.NET Core运行时完成,这样可以阻止黑客添加脚本到站点

9.4 HtmlContentViewComponentResult

HtmlContentViewComponentResult类返回未编码的HTML针对视图组件,修改Cart视图组件返回一个HtmlContent-ViewComponentResult类,代码如下:

代码语言:javascript
复制
public IViewComponentResult Invoke()
{
   return new HtmlContentViewComponentResult(new HtmlString("This is from <h2>View Component</h2>"));
}

运行应用,你将会看到如下信息展示在浏览器中

使用这个方法你需要确保你100%返回的信息是安全的而且不会被篡改

9.5 返回部分视图

你可以使用视图组件返回部分视图,ViewComponent基类提供了View()方法返回部分视图

有4个版本的View方法:

代码语言:javascript
复制
View();//选择默认部分视图
View(model);//选择默认部分视图并提供数据模型给它
View("viewname");//通过名字选择部分视图
View("viewname",model);//通过名字选择视图并且提供数据模型给它

ASP.NET Core将从下面位置查找部分视图:

代码语言:javascript
复制
/Views/{controller}/Components/{view component}/{partial view name}
/Views/Shared/Components/{view component}/{partial view name}

1 控制器是用来处理HTTP请求

2 如果在View()没有指定视图名称,{partial view name}使用Default.cshtml

9.6 复杂视图的例子

让我们创建一个复杂视图组件返回部分视图,创建一个模型类Product.cs在Models文件夹:

代码语言:javascript
复制
namespace AspNetCore.Views.Models
{
    public class Product
    {
        public string Name { get; set; }
        public int Price { get; set; }
    }
}

现在更新你的Cart视图组件返回一个View使用product模型

代码语言:javascript
复制
 public IViewComponentResult Invoke()
 {
     Product[] products = new Product[] {
                new Product() { Name = "Women Shoes", Price = 99 },
                new Product() { Name = "Mens Shirts", Price = 59 },
                new Product() { Name = "Children Belts", Price = 19 },
                new Product() { Name = "Girls Socks", Price = 9 }
            };

    return View(products);
 }

运行应用程序,你会发现下面错误

注意控制器处理HTTP请求是HomeController并且我们没有在View()中指定视图名称,因此ASP.Net Core会从下面位置搜索视图

代码语言:javascript
复制
/Views/Home/Components/Cart/Default.cshtml
/Views/Shared/Components/Cart/Default.cshtml

为了解决这个问题创建部分视图,创建一个Default.cshtml的Razor视图在/Views/Shared/Components/Cart/ 文件夹下并且添加下面代码

代码语言:javascript
复制
@model Product[]
<table class="table" style="width:50%">
    <thead class="thead-dark">
        <tr>
            <td><u>Product Name</u></td>
            <td><u>Price</u></td>
        </tr>
    </thead>
    <tbody>
        @{
            foreach (Product p in Model)
            {
                <tr class="table-secondary">
                    <td>@p.Name</td>
                    <td>@p.Price</td>
                </tr>
            }
        }
    </tbody>
</table>

运行应用程序进入https://localhost:7019/Home/TestLayout,这次你会发现部分视图包含在layout页面并且它在购物车中展示所有产品,检查下面图片

9.7 在视图组件中使用DI

我们可以在视图组件中使用依赖注入,只需要在视图组件构造函数中添加依赖的类,让我们创建一个服务,其任务是在购物车视图组件上提供折扣优惠券代码。通过此优惠券,用户可以获得产品总成本的折扣。在应用程序根目录上创建一个名为“Services”的新文件夹,并在其中添加一个Coupon.cs类

代码语言:javascript
复制
namespace AspNetCore.Views.Models
{
    public class Coupon
    {
        public string GetCoupon()
        {
            //get coupons from external database or an external web api call
            return "Discount10";
        }
    }
}

GetCoupon()方法提供折扣码来自数据库或者外部api,这里仅仅作为演示返回一个字符串

接下来在Programe.cs中注册Coupon 服务

代码语言:javascript
复制
builder.Services.AddTransient<Coupon>();

在Cart视图组件中注册这个服务. 代码如下:

代码语言:javascript
复制
using AspNetCore.Views.Models;
using AspNetCore.Views.Service;
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Views.Components
{
    public class Cart : ViewComponent
    {
        private Coupon _coupon;
        public Cart(Coupon coupon)
        {
            _coupon = coupon;
        }
        #region 返回复杂视图
        public IViewComponentResult Invoke()
        {
            Product[] products = new Product[] {
                new Product() { Name = "Women Shoes", Price = 99 },
                new Product() { Name = "Mens Shirts", Price = 59 },
                new Product() { Name = "Children Belts", Price = 19 },
                new Product() { Name = "Girls Socks", Price = 9 }
            };

            ViewBag.Coupon = _coupon.GetCoupon();
            return View(products);
        }
        #endregion
    }
}

现在我们在Default.cshtml视图中展示折扣信息,读取ViewBag变量并展示

代码语言:javascript
复制
@model Product[]
<table class="table" style="width:50%">
    <thead class="thead-dark">
        <tr>
            <td><u>Product Name</u></td>
            <td><u>Price</u></td>
        </tr>
    </thead>
    <tbody>
        @{
            foreach (Product p in Model)
            {
                <tr class="table-secondary">
                    <td>@p.Name</td>
                    <td>@p.Price</td>
                </tr>
            }
        }
    </tbody>
</table>
<p class="p-3 text-white bg-dark">Apply coupon - @ViewBag.Coupon</p>

运行应用程序并展示

9.8 父组件中的值传递给子组件

我们可以从父组件向子组件传递至,使用@await Component.InvokeAsync()的第二个参数提供一个匿名对象,在_Layout.cshtml文件修改InvokeAsync()传递一个false属性:

代码语言:javascript
复制
@await Component.InvokeAsync("Cart",new {showCart=false})

修改Cart组件代码并且在Invoke()方法中添加showCart参数,显示代码如下:

代码语言:javascript
复制
using AspNetCore.Views.Models;
using AspNetCore.Views.Service;
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Views.Components
{
    public class Cart : ViewComponent
    {
        private Coupon _coupon;
        public Cart(Coupon coupon)
        {
            _coupon = coupon;
        }
        #region 返回复杂视图
        public IViewComponentResult Invoke(bool showCart)
        {
            Product[] products;
            if (showCart)
            {
                products = new Product[] {
                new Product() { Name = "Women Shoes", Price = 99 },
                new Product() { Name = "Mens Shirts", Price = 59 },
                new Product() { Name = "Children Belts", Price = 19 },
                new Product() { Name = "Girls Socks", Price = 9 }
                };
                ViewBag.Coupon = _coupon.GetCoupon();
            }
            else
            {
                products = new Product[] { };
            }
            return View(products);
        }
        #endregion
    }
}

当showCart变量为true时我们显示cart产品,运行应用程序,这次我们没有显示任何产品

10 匿名视图组件

异步视图组件使用指定异步任务,InvokeAsync方法返回一个task对象,ASP.NET Core将等待任务完成并且在view中呈现结果

右击"Components"文件夹并且添加新的类命名为PageSize.cs,添加下面代码:

代码语言:javascript
复制
using Microsoft.AspNetCore.Mvc;
namespace AspNetCore.Views.Components
{
    public class PageSize: ViewComponent
    {
        public async Task<IViewComponentResult> InvokeAsync()
        {
            HttpClient client = new HttpClient();
            HttpResponseMessage response = await client.GetAsync("http://www.msn.com");
            return View(response.Content.Headers.ContentLength);
        }
    }
}

异步视图组件将获取MSN页数使用HTTP GET 请求并且将传递页数到default视图

在View/Home/Components/PageSize目录下创建一个Default.cshtml目录,在文件夹中添加下面代码:

代码语言:javascript
复制
@model long
<div class="p-3 mb-2 text-danger">Page size: @Model</div>

现在在_Layout.cshtml文件中调用异步组件,如下所示:

代码语言:javascript
复制
@await Component.InvokeAsync("PageSize")

运行程序,进入https://localhost:7113/Home/TestLayout,你将会看到MSN页面页数显示如下

11 @inject 指令

通过使用@inject指令可以把服务注入到View,假如我们有个服务提供了随机笑话,这个笑话来自随机的api. 因此在你应用程序中Service文件夹创建一个Joke.cs类使用下面代码:

代码语言:javascript
复制
using System.Text.Json;
namespace AspNetCore.Views.Service
{
    public class Joke
    {
        public async Task<string> GetJoke()
        {
            string apiResponse = "";
            using (var httpClient = new HttpClient())
            {
                using (var response = await httpClient.GetAsync("https://api.vvhan.com/api/joke"))
                {
                    apiResponse = await response.Content.ReadAsStringAsync();
                }
            }
            return apiResponse;
        }
    }
}

该类有一个名为 GetJoke 的方法,该方法调用 Web API 并取名为joke的笑话,最后返回,接下来,在 Program.cs 类中添加Joke为transient 服务

代码语言:javascript
复制
builder.Services.AddTransient<Joke>();

现在在HomeController中添加一个新的action方法

代码语言:javascript
复制
public IActionResult Joke()
{
    return View();
}

在Views->Home目录下添加Joke.cshtml代码如下

代码语言:javascript
复制
@using AspNetCore.Views.Service
@inject Joke joke;

<h2 class="text-primary">Today's Joke</h2>
<p>@await joke.GetJoke()</p>

在上面代码,我使用了@inject 指令引用依赖注入的服务-@inject Joke joke,这样我们就可以在页面上使用DI,最后我调用GetJoke方法-@await joke.GetJoke()展示笑话

运行程序,进入URL- https://localhost:7019/Home/Joke,会发现我们每次随机展示一个笑话

总结

通过这两篇文章介绍ASP.NET Core MVC中视图的应用包含创建视图,视图中使用Razor语法,在视图中调用action方法,共享视图文件,ASP.NET Core如何查找视图文件,Layout视图是如何工作的,部分视图和视图组件

参考文献

[1][1]https://www.yogihosting.com/aspnet-core-views/

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DotNet NB 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
多因子身份认证
多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档