添加查看功能实现及异步编程和TagHelper

一、异步编程(Task)基本理解

1. Task 类

Task类是.NET 4.0之后提供的异步操作抽象,需要导入System.Threading.Tasks命名空间。
Task类用于表示无返回值的异步操作,对于带有返回值的异步操作应使用Task类的子类Task<TResult。
Task类和Task<TResult 类,后者是前者的泛型版本。TResult类型为Task所调用方法的返回值。
主要区别在于Task构造函数接受的参数是Action委托,而Task<TResult 接受的是Func<TResult 委托。
Task(Action)
Task<TResult(Func<TResult)

2. Task 异步编程的通俗理解

Task 异步编程模式是潮流,当然就是因为执行效率高。
怎么理解异步编程,通俗讲就是“未来完成时”。带Task的表示他现在不一定有结果,等有结果了,他会通知你。当然实际上的意义就是,CPU现在可以忙别的,等有结果了再去处理你的。想想医院的医生看病就OK,他让你先做检查,先去化验,等你拿着化验结果到了,他再具体判定。在你去化验的同时医生也不会闲着,他用这段时间给后面病人诊断。理解了这个,技术上就能搞清楚了。

简言之,就是“不空等结果,保存环境,等有结果了,恢复环境继续运行。同时他在等结果的同时去执行其他任务”。

异步就是不阻塞,不等 Task 方法执行完而是先去执行这个方法后边的代码。当写了 await 关键字的时候,就可以让 Task 执行完毕了才去执行它后边的代码。

3. Task类中的一些常用方法及应用

// 将参数中的异步操作在当前调度器中排队,并返回Task对象
(1)public static Task Run(Action action);
(2)public static Task<TResult Run<TResult (Func<TResult function);Task.Run方法是Task类中的静态方法,接受的参数是委托。返回值是为该Task对象。Task.Run(Action)
Task.Run<TResult (Func<Task<TResult )
(3)public void Wait(); //等待当前Task任务完成
Task类创建的任务会加入线程池中。在实际开发中,更多情况下使用Task类的静态方法Run()或者工厂类TaskFactory的成员方法StartNew()来创建和启动新的任务(TaskFactory taskFactory = new TaskFactory();taskFactory.StartNew(Action)😉。
虽然在异步方法中提示返回值可以为Task、Task<T 或者void,但是建议返回值选择Task或者Task<T 。
例子1:创建控制台项目(.Net Core的)

static void Main(string[] args) 
        { 
            Task Task1 = new Task(() => Console.WriteLine("Task1")); 
            Task1.Start(); 
            Console.ReadKey(); 
        } 

通过实例化一个Task对象,然后Start,这种方式中规中矩,但是实际应用中,通常采用更方便快捷的方式。
Task.Run(() => Console.WriteLine(“异步编程”));
这种方式直接运行了Task,不像上面的方法还需要调用Start();
默认情况下,Task任务是由线程池线程异步执行。要知道Task任务的是否完成,可以通过task.IsCompleted属性获得,也可以使用task.Wait来等待Task完成。Wait会阻塞当前线程。
例子2:

  static void Main(string[] args)
        {
            Task Task1 = Task.Run(() =>
            {
                Thread.Sleep(5000);
                Console.WriteLine("Foo");
                Thread.Sleep(5000);
            });
            Task1.Wait();//阻塞当前线程 ,等待上面任务完成再执行下面的代码
            Console.WriteLine(Task1.IsCompleted);
            
            Console.WriteLine(Task1.IsCompleted);
            Console.WriteLine("ok");
            Console.ReadKey();
        }

运行结果:在这里插入图片描述
把上面wait代码下移2行:

static void Main(string[] args)
        {
            Task Task1 = Task.Run(() =>
            {
                Thread.Sleep(5000);
                Console.WriteLine("Foo");
                Thread.Sleep(5000);
            });
            Console.WriteLine(Task1.IsCompleted);
            Task1.Wait();//阻塞当前线程,等待上面任务完成再执行下面的代码 
            Console.WriteLine(Task1.IsCompleted);
            Console.WriteLine("ok");
            Console.ReadKey();
        }

运行结果如下:在这里插入图片描述

4. async/await 关键字

C# 5.0之后引入了async和await关键字,更好的支持并发操作。
async用于标记异步方法。async标记的方法返回值必须为Task、Task<TResult、void其中之一。await用于等待异步方法的结果。await关键字可以用在async方法和Task、Task<TResult 之前,用于等待异步任务执行结束。
如:await _resultRepository.ListAsync();

二、添加和查看功能的实现

即添加Result记录和查看Result记录。sqlhelper

  • 1、【添加接口】项目下创建一个文件夹Repository,存放仓储文件,用于操作数据库。在文件夹下添加接口IResultRepository
public interface IResultRepository
   {
        Task<Result> GetByIdAsync(int id);
        Task<List<Result>> ListAsync();
        Task AddAAsync(Result result);
        //Task UpdateAsync(Result result);
Task<bool> UpdateAsync(Result result);
}
  • 2、【实现接口】实现接口类ResultRepository
public class ResultRepository : IResultRepository
    {
        private ResultContext resultContext;
        public ResultRepository(ResultContext _resultContext)
        {
            resultContext = _resultContext;
        }
        //无返回值的异步操作
        public Task AddAAsync(Result result)
        {
            resultContext.Results.Add(result);
            return resultContext.SaveChangesAsync();
        }

        //带有返回值的异步操作,返回值Result类型
        //需要导入using Microsoft.EntityFrameworkCore;
        public Task<Result> GetByIdAsync(int id)
        {
           return resultContext.Results.FirstOrDefaultAsync(r=>r.Id==id);
        }
        //带有返回值的异步操作,返回值为List<Result>类型
        public Task<List<Result>> ListAsync()
        {
            return resultContext.Results.ToListAsync();
        }
        //无返回值的异步操作
        //public Task UpdateAsync(Result result)
        //{
           // resultContext.Results.Update(result); //还是选这个好
            resultContext.Entry(result).State = EntityState.Modified;
            //return resultContext.SaveChangesAsync();
        }
改为下面的更好
//无返回值的异步操作
        public async Task<bool> UpdateAsync(Result result)
        {          
            resultContext.Results.Update(result);          
            return await resultContext.SaveChangesAsync()>0;
        }
    }
  • 3、【注入服务】注入服务
    打开startup.cs文件
public void ConfigureServices(IServiceCollection services)
        {
            //设置连接数据库字符串
            var connection = @"server=.;Database=ResultDB;UId=sa;PWD=123456;";
            //注入上下文类,告知上下文ResultContext去与哪个数据库想关联
            services.AddDbContext<ResultContext>(options=>
            {
        //options.UseSqlServer(Configuration.GetConnectionString("ResultConnection")));//这样去获取配置文件中的连接字符串也行
            options.UseSqlServer(connection);
            }); 
//通过接口形式注入ResultRepository服务
services.AddScoped<IResultRepository, ResultRepository>();
……
}
  • 4、【创建ViewModel】
    Add操作需要对应的实体,不建议直接使用数据库实体。这里添加一个对应的ViewModel来展示对应的实体。即再添加一个ViewModels文件夹,接着添加ResultModels.cs,代码如下:
public class ResultModel
    {
        [Key] 
// [DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)] // 主键自增id
        public int Id { get; set; }
        [Required]
        [MaxLength(10)]
        [Display(Name = "姓名")]
        public string StuName { get; set; }
        [Required]
        [MaxLength(100)]
        [Display(Name = "标题")]
        public string Title { get; set; }
        [Required]
        [Display(Name = "成果概述")]
        public string Discription { get; set; }
//创建时间不需要,后续添加时为系统现在时间
    }
  • 5、【使用服务】在Controller文件夹下添加控制器(MVC控制器-空)ResultController。
    实现Index操作及Add操作
1public class ResultController : Controller
    {
        private IResultRepository _resultRepository;
        public ResultController(IResultRepository resultRepository)
        {
            _resultRepository = resultRepository;
        }
        //提问:resultRepository对象什么时候产生/注入的呢?
       
        public async Task<IActionResult> Index()
        {
            var results = await _resultRepository.ListAsync();
            return View(results);
        }
      
//展示添加页面所需2public IActionResult Add()
        {
            return View();
        }
//处理添加逻辑3[HttpPost]
        public async Task<IActionResult> Add(ResultModel model)
        {
//指前端那些表单验证无效/失败
            if(!ModelState.IsValid)
            {
                return BadRequest(ModelState);
            }
            await _resultRepository.AddAAsync(new Models.Result
            {
                StuName = model.StuName,
                Title = model.Title,
                Discription = model.Discription,
                Create = DateTime.Now
            });
            return RedirectToAction("index");
        }
  • 6、添加对应视图
    Add.cshtml在这里插入图片描述
    (使用布局页,使用的是BootStrap)
    修改下视图代码
@model ResultUploadSystem.ViewModels.ResultModel

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Add</title>
</head>
<body>

    <h4>ResultModel</h4>
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form method="post" asp-action="Add">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="StuName" class="control-label"></label>
                    <input asp-for="StuName" class="form-control" />
                    <span asp-validation-for="StuName" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Title" class="control-label"></label>
                    <input asp-for="Title" class="form-control" />
                    <span asp-validation-for="Title" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Discription" class="control-label"></label>
                    <input asp-for="Discription" class="form-control" />
                    <span asp-validation-for="Discription" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <input type="submit" value="Create" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div>

    <div>
        <a asp-action="Index">Back to List</a>
    </div>
   
</body>
</html>

Index.cshtml
在这里插入图片描述

@model IEnumerable<ResultUploadSystem.Models.Result>

@{
    Layout = null;
}
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>Index</title>
</head>
<body>
<p>
   此处黄色底纹是由默认Create改为Add
    <a asp-action="Add">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.StuName)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Discription)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Create)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.StuName)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Discription)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Create)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.Id">Edit</a> |
                <a asp-action="Details" asp-route-id="@item.Id">Details</a> |
                <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>
</body>
</html>

运行效果:
在这里插入图片描述
在这里插入图片描述
这些视图默认代码如何理解,下面小节讲。

三、TagHelper【标签助手】的理解与用法

1.概念

TagHelper(标签助手)是asp.net core mvc的新特性,把HTML和服务器内容混合在一起,准确说标签助手使服务器端代码能够参与在Razor文件中创建和呈现HTML元素。

2.究竟什么是TagHelper

在MVC项目中使用过HtmlHelper。比如当需要在View上添加一个导航栏的时候,我们就会添加下面代码到页面上去:

<ol><li>@Html.ActionLink("HomeText", "Index", "Home")</li></ol> 

这里有一些HTML元素li。还有以@开头的一些C#代码,当View解析的时候,这些C#代码会被解析成HTML元素。

<li><a href="/">HomeText</a></li>

当我们用TagHelper,我们同样可以用下面的代码来获得上面同样的效果:

<ol><li><a asp-controller="Home" asp-action="Index">HomeText2</a></li></ol>

在这里,a元素的属性asp-controller和asp-action并不是HTML5的属性,而是这个TagHelper的属性。
这个其实就是内置的AnchorTagHelper。当然.Net Core内置了很多其他TagHelper。
注意,虽然TagHelper看起来有点像我们之前服务器控件的写法,但是它不是服务器控件。它提供了一个HTML友好的开发体验。使用TagHelper的Razor标记看起来更像标准的HTML。熟悉HTML/CSS/JavaScript的前端设计师可以直接编辑Razor,而不需要学习C#的Razor语法。

3.如何开启TagHelper的使用

在需要使用的View上注册TagHelper。
@addTagHelper [the full type name of taghelper,] the assembly name
第一参数是TagHelper类的全名,当你只需要使用某一个TagHelper时候,你可以在此指定你所用的TagHelper类全名,包括它的NameSpace。
第二个参数是程序集名。,如果你要使用程序集中所有的TagHelpers,可以使用“*”或者省略这一个参数。@addTagHelper *, Microsoft.AspNet.Mvc.TagHelpers
如果你只希望使用某个TagHelper,如:AnchorTagHelper,那么只需要一下代码:
@addTagHelper Microsoft.AspNet.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNet.Mvc.TagHelpers
然后就可以用了,如:

<a asp-controller="Home" asp-action="About">About</a>

当然,如果你想取消某个TagHelper的注册,可以使用removeTagHelper,比如
@removeTagHelper Microsoft.AspNet.Mvc.TagHelpers.AnchorTagHelper, Microsoft.AspNet.Mvc.TagHelpers
一旦TagHelper被取消注册了,其对应的Tag就不能被解析成这种TagHelper了。
说明:如果想在所有的视图文件中都使用TagHelper,那么可以在Shared文件夹下_ViewImports.cshtml文件中引入TagHelper。
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
不过默认是引用好了的哦——【无需自己引用可以直接使用】。

四、常见TagHelper的Tag属性与应用

1.AnchorTagHelper 锚连接

这个TagHelper被应用在所有锚元素<a>上,它拥有以下属性:
asp-action——指定action方法名。
asp-controller——指定controller名。
asp-fragment——指定URL片段名。
asp-host——指定访问的主机(host)名。
asp-protocol——指定访问协议,比如http或者https。
asp-route——指定路由名。
最终这个TagHelper会被解析成具有href属性的锚元素,这个href的内容就是基于以上这些属性的值生成的。
<a asp-action="Create">Create New</a>

2.LabelTagHelper

与HtmlExtension.LabelFor功能一样,它只有一个属性asp-for,用来指定绑定Model里某个字段,很多其他的TagHelpers也具有这个属性。。它作用在label元素上。

3.InputTagHelper

这个TagHelper被应用在input元素上,与HtmlHelper中的TextBoxForHTML一样,这个TagHelper会生成一个绑定到model中某个字段的Input元素。它支持一下属性:
asp-for——用来指定绑定model某个字段
asp-format——用来设置显示的Format,通常被用来给货币、日期和时间类型的值设置Format
比如,Birthday是model里的一个日期类型的字段。

<input asp-for="Birthday" asp-format="{0:yyyy-MM-dd}"/>
<input asp-for="StuName" class="form-control" />
注意:我们也可以把一个内嵌对象赋给asp-for,比如:
<input asp-for="Address.Street" type="text" />

4.ValidationMessageTagHelper

与HtmlHelper中的ValidationMessageFor一样,这个TagHelper是用来显示验证失败信息。它应用在span元素上,而且只有唯一的一个属性asp-validation-for,被用来指定所验证的对象----Model中某个字段。

<input asp-for="Birthday" asp-format="{0:yyyy-MM-dd}"/>
<span asp-validation-for="Birthday"/>

5.ValidationSummaryTagHelper

像HTMLHelper扩展的ValidationSummary一样,它是用来验证错误的汇总信息。它只支持一个属性asp-validation-summary,具有以下几种值:
None——不显示任何验证信息
ModelOnly——只显示Model错误信息,不包括属性错误信息
All——显示所有信息
它应用在div元素上

<div class="validation" asp-validation-summary="ModelOnly"/>

6.FormTagHelper

与HtmlHelper中的BeginForm一样,它用来生成一个form元素,它应用在form元素上,支持以下属性:
asp-action——
asp-controller——

<form asp-action="Add" method="post">

7.SelectTagHelper

SelectTagHelper作用在Select元素上,支持asp-for和asp-items属性。

asp-for——与我们上面介绍的一样,用来绑定model中某个字段。
asp-items——被用来指定Select元素的Option集合,它的值类型是IEnumerable<SelectListItem>
<select asp-for="Country" asp-items="ViewBag.Countries"></select>
如果要在Select中添加一个默认选择的项,我们可以这样做:
<select asp-for="Country" asp-items="ViewBag.Countries">
   <option selected="selected" value="">Choose Country</option>
</select>
我们可以赋任何类型的IEnumerable<SelectListItem>实例给asp-items,可能是某个变量或者某个实例的一个属性等。
比如:
@{
    SelectListItem[] items =
    {
        new SelectListItem() { Text = "item 1" },
        new SelectListItem() { Text = "item 2" }
    };
}
<select asp-for="Country" asp-items="items"></select>

8.OptionTagHelper

应用在option元素上,和select元素一起使用,通常被用来读取option元素信息,而不改变元素内容。唯一可能修改的是在有的情况下,会根据父亲select元素将option的selected状态设成"selected"。

<select asp-for="Country" asp-items="ViewBag.Countries">
   <option selected="selected" value="">Choose Country</option>
</select>

9.TextAreaTagHelper

应用在textarea元素上,目前只支持唯一一个属性asp-for

<textarea asp-for="Discription"></textarea>

10.LinkTagHelper

应用在link元素上,支持备用的样式文件。它具有以下属性:
href——指定样式资源的链接地址。
asp-href-include——指定所有需要被加载的样式文件路径,当有多个时,以逗号来分隔每一个;这里的路径是相对于应用程序中wwwroot的相对路径。
asp-href-exclude——指定那些不需要被加载的样式文件路径,当有多个时,以逗号来分隔每一个;这里的路径是相对于应用程序中wwwroot的相对路径。
asp-fallback-href——指定备用资源链接地址。
asp-fallback-href-include——指定所有需要被加载的备用样式文件路径,当有多个时,以逗号来分隔每一个;这里的路径是相对于应用程序中wwwroot的相对路径。
asp-fallback-href-exclude——指定那些不需要被加载的备用样式文件路径,当有多个时,以逗号来分隔每一个;这里的路径是相对于应用程序中wwwroot的相对路径。
asp-fallback-test-class——用来检测加载失败的样式名。
asp-fallback-test-property——用来检测资源加载失败所用的测试属性。
asp-fallback-test-value——用来检测资源加载失败所用的测试值。
asp-file-version——bool值,用来指定是否需要将文件版本信息加入到url地址中。
例如,在下面例子中,当从网络上(http://ajax.aspnetcdn.com/ajax/bootstrap-touch-carousel/0.8.0/css/bootstrap-touch-carousel.css)加载样式文件失败时,加载本地相应的样式文件(~/lib/bootstrap-touch-carousel/css/bootstrap-touch-carousel.css)。通过检测样式类carousel-caption中display属性是否是none来判断网络上样式文件是否加载成功。
<link rel="stylesheet"
href="//ajax.aspnetcdn.com/ajax/bootstrap-touch-carousel/0.8.0/css/bootstrap-touch-carousel.css"
asp-fallback-href="~/lib/bootstrap-touch-carousel/css/bootstrap-touch-carousel.css"
asp-fallback-test-class="carousel-caption"
asp-fallback-test-property="display"
asp-fallback-test-value="none" />

11.EnvironmentTagHelper

应用在environment元素上,根据不同names的设置呈现不同的内容。它支持以下属性:
names——指定环境名,当有多个时候以逗号分隔。这里判断的依据是,读取IHostingEnvironment的EnvironmentName的值,与environment元素中的names匹配,当匹配上的时候就呈现出里面的内容,否则移除该environment元素。
在很多情况下,我们想在开发环境使用一套配置信息,在生产环境又是另外一套,这时候就需要使用条件判断语句了,不过在新版的MVC中,使用EnvironmentTagHelper提供的Environment元素标签就可以了,示例如下:

<environment names="Development">
        <link rel="stylesheet" href="~/lib2/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="~/css/site.css" />
 </environment>
<environment names="Staging,Production">
        <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
        asp-fallback-href="~/lib2/bootstrap/dist/css/bootstrap.min.css"
        asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
        <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
    </environment>

在上述代码中,我们定于,如果是Development环境就使用本地的js文件,否则(Staging或Production环境)就使用网络上的css文件。asp-append-version="true"为静态文件提供唯一版本号。

12.ScriptTagHelper

应用在script元素上,和LinkTagHelper一样,它也具有fallback功能, 只不过这里判断的不是class样式,而是用来判断默认的js文件是否加载成功。
它支持以下属性:
src指定要加载的js源地址。
asp-src-include指定要加载的js文件,当有多个文件时以逗号分隔。这里文件路径是相对于程序webroot的相对路径。
asp-src-exclude指定不需要加载的js文件,当有多个文件时以逗号分隔。这里文件路径是相对于程序webroot的相对路径。
asp-fallback-src指定备用的js源地址。
asp-fallback-src-include指定需要加载的备用js文件,当有多个文件格式时以逗号分隔。这里文件路径是相对于程序webroot的相对路径。
asp-fallback-src-exclude指定不需要加载的备用js文件,当有多个文件时以逗号分隔。这里文件路径是相对于程序webroot的相对路径。
asp-file-version——bool值,用来指定是否需要将文件版本信息加入到url地址中。
<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.10.2.min.js"
    asp-fallback-src="~/lib/jquery/jquery.min.js">
</script>
此外,还可以根据需要自定义TagHelper。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值