依照老周的良好作风,开始之前先说点题外话。

前面的博文中,老周介绍过自定义 MVC 视图的搜索路径,即向 ViewLocationFormats 列表添加相应的内容,其实,对 Razor Page 模型,也可以向 PageViewLocationFormats 列表添加相应的搜索路径,比如 /MyPages/{1}/{0}.cshtml。其中,0 是视图名,1 是页面名称。比如这样。

            services.AddMvc().AddRazorOptions(opt =>
{
opt.ViewLocationFormats ...
opt.PageViewLocationFormats ...
});

然而,我们知道,基于 Razor 的 Web Page 模型是以页面为单位的,也就是说路径路由是直接指向页面的(不包含.cshtml 扩展名),即不需要 MVC 模型的路由方式。所以,我们并不需要修改 PageViewLocationFormats 中的内容。许多时候,我们只要告诉应用程序在哪个目录下查找 Page 就行了。

默认的搜索位置是 /Pages 目录,我们可以通过以下代码来修改。

        public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().AddRazorPagesOptions(opt =>
{
opt.RootDirectory = "/UI";
});
}

以上代码写在 Startup 类中,这个应该明白吧。RootDirectory 就是用来指定应用程序查找 Razor 页面的根目录路径,此处我指写了 /UI,所以,在我的项目中,我只要建一个 UI 目录,然后各类 Razor 页就往里面放就行了。

========================================================================================

好了,题外话扯完了,开始说正题吧。今天咱们聊聊有关异常处理的破事吧,也可以说是错误处理,反正就这个意思,你理解就好,专业名词不必较劲,只有那些吃饱了撑着的“学术人才”才会跟名词较劲。

老办法,咱们结合示例来讲述,这样各位观众不会乏味。

大家知道,娱乐产品肾Phone已经成为流行玩具,近年来,购买肾Phone不一定只能用货币,比较典型的一种支付方式是卖肾买Phone。说实话,现在许多国产娱乐产品也很便宜,配置也不错,几百块钱就能玩得刷刷响了,割肾真没什么必要。

为了方便人们以肾换 Phone ,老周特意开发了一个在线卖肾系统。大致流程是这样的,如果你有闲置的肾,可以打开主页,输入你的一些信息,然后报个价,其他用户看见后,如果觉得合理,就认购此肾。

为了使操作流程更简单,易上手,轻入门,该平台只需要输入姓名和肾的价格即可参加报价。

大致的页面代码如下。

        <form method="post">
<div class="form-group">
<label for="name">姓名:</label>
<input type="text" class="form-control" name="name"/>
</div>
<div class="form-group">
<label for="price">价格:</label>
<input type="number" name="price" class="form-control"/>
</div>
<div class="form-group">
<button type="submit" class="btn btn-success w-100">提 交</button>
</div>
</form>

Razor 页面很像我们以前玩过的 aspx 页面,每个页面都配套一个隐藏代码文件。Razor 页也会配有一个页面模型类,注意这个模型类要从 PageModel 派生,不是 Page 类,别搞错了,Page 类只是作为生成 HTML 代码的基类,我们的 .cshtml 文件在预编译后,是隐式继承自 RazorPage 类的。除非你要开发自己的标记语言,否则你不必理会这些类。

记住了,与 Razor 页关联的模型类是从 PageModel 类派生的,比如,本例中,当有人填写了闲置肾的相关信息后,以 POST 方式提交,这是候,如果页面模型类中包含了名字为 OnPost、OnPostAsync ……的方法时,就会自动调用。如果想把我们上面那个 form 中的 name 和 price 的值传递给方法,直接让 OnPost 方法的参数与 form 中的元素名称相同就可以了。

    public class IndexModel : PageModel
{
public IActionResult OnPost(string name, decimal price)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new Exception("你怎么不留下姓名啊,卖肾又不是丢人的事。");
}
if(price <= 0.0M)
{
throw new Exception("靠!你的肾这么不值钱吗?还免费送,包邮不?");
}
return RedirectToPage("/Success");
}
}

OnPost 不是 PageModel 基类的方法,而是我们自己写的,只是代码约定,Asp.net Core 里面用到很多代码约定,它在运行的时候会查找这些特定的名字。

上面代码中,还对传递进来的 form 值进行验证,如果不符合要求,会抛出异常。

一般来说,在 Startup 类的 Configure 方法中,我们会判断一下,如果应用程序处于开发阶段,为了方便测试,应该加入这些代码。

      if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

这样,我们在测试时能看到详细的异常信息。

但是,在实际便用时,我们不能公开这么详细的信息,这样容易勾起人们的犯罪冲动。所以,一般会添加一个页面,专门用来显示错误信息。比如:

@page

<div class="card">
<div class="card-header bg-danger">
<span class="text-light">错误</span>
</div>
<div class="card-body">
<span class="card-text">唉,真抱歉。你提交的肾不符合国际标准,没人要的。</span>
</div>
</div>

然后我们要在 Startup.Configure 方法中配置一下。

  app.UseExceptionHandler("/Error");

加上这一行后,当发生异常时,就会跳转到 /Error 页面。

不过,你也许会觉得,虽然不能公开异常信息,但一些必要的描述应该要的,不然,用户不知道发生了啥事。我们可以通过 HttpContext 的 Features 集合获取一个用来处理异常的 Feature,它的原型接口是 IExceptionHandlerFeature,我们不必关心它的实现类型是谁,只要访问它的 Error 属性就能得到关联的 Exception 实例。

因此,我们的错误页可以改一下。

@page
@using Microsoft.AspNetCore.Diagnostics
@{
IExceptionHandlerFeature exf = HttpContext.Features.Get<IExceptionHandlerFeature>();
Exception ex = exf?.Error;

} <div class="card">
<div class="card-header bg-danger">
<span class="text-light">错误</span>
</div>
<div class="card-body">
@if (ex == null)
{
<span class="card-text">唉,真抱歉。你提交的肾不符合国际标准,没人要的。</span>
}
else
{
<span class="card-text">@ex.Message</span>
}
</div>
</div>

通过以下代码获得异常实例的引用。

    IExceptionHandlerFeature exf = HttpContext.Features.Get<IExceptionHandlerFeature>();
Exception ex = exf?.Error;

这样就可以在页面上显示异常的描述信息了。

可能你又想到了,我不想输出个页面,我只想返回一些简单的文本,那么,你在 Startup.Configure 中可以这样写。

            app.UseExceptionHandler(x =>
{
x.Run(async context =>
{
var ex = context.Features.Get<Microsoft.AspNetCore.Diagnostics.IExceptionHandlerFeature>()?.Error;
string msg = ex == null ? "发生错误。" : ex.Message;
context.Response.ContentType = "text/plain;charset=utf-8";
await
context.Response.WriteAsync(msg);
});
});

里面的变量 x 就是当前的 IApplicationBuilder ,与传递给 Configure 方法的 app 参数类型一样,这时候我们可以用 Reponse 的方法返回自定义的文本。

好了,今天的内容就介绍到这儿吧,其实异常处理还有一种方法——使用 Filter,这个咱们留到下一篇博文再和大伙分享。

本文示例源代码下载

【ASP.NET Core】处理异常(上篇)的更多相关文章

  1. Asp.net Core全局异常监控和记录日志

    前言           系统异常监控可以说是重中之重,系统不可能一直运行良好,开发和运维也不可能24小时盯着系统,系统抛异常后我们应当在第一时间收到异常信息.在Asp.net Core里我使用拦截器 ...

  2. Asp.Net Core 发布异常 502.5 [The Application process failed to Start]

    出现这个问题大部分时间都是因为发布时,少打包了一些文件.. 只打包了.Net Core的运行时库,没有打包Asp.Net Core 运行时.. 需要在打包指导文件中加入以下节点 <Propert ...

  3. asp.net core全局异常过滤并监控系统BUG将异常信息记录到日志

    添加: using Dw.Util.Helper; using Microsoft.AspNetCore.Mvc.Filters; using System; using System.Collect ...

  4. 我的asp.net core目录

    推荐 Asp.NETCore轻松学系列阅读指引目录(asp.net core 2.2) 官方文档翻译 http://www.cnblogs.com/dotNETCoreSG/p/aspnetcore- ...

  5. ASP.NET Core 中间件自定义全局异常处理

    目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...

  6. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  7. ASP.NET Core的配置(4):多样性的配置来源[上篇]

    较之传统通过App.config和Web.config这两个XML文件承载的配置系统,ASP.NET Core采用的这个全新的配置模型的最大一个优势就是针对多种不同配置源的支持.我们可以将内存变量.命 ...

  8. ASP.NET Core的配置(3): 将配置绑定为对象[上篇]

    出于编程上的便利,我们通常不会直接利用ConfigurationBuilder创建的Configuration对象读取某个单一配置项的值,而是倾向于将一组相关的配置绑定为一个对象,我们将后者称为Opt ...

  9. asp.net core MVC 全局过滤器之ExceptionFilter异常过滤器(一)

    本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter异常过滤器(一) asp.net cor ...

随机推荐

  1. Hive HQL学习

    HQL学习   1.hive的数据类型 2.hive_DDL 2.1创建.删除.修改.使用数据库     Default数据库,默认的,优先级相对于其他数据库是最高的   2.2重点:创建表_内部表_ ...

  2. eclipse中如何同期化

    打开MyEclipse8.0help->Software Updates->find and install(如果没有这个就用help->Software Updates->A ...

  3. Linux IO时事检测工具iostat

    Linux IO时事检测工具iostat iostat命令用于检测linux系统io设备的负载情况,运行iostat将显示自上次运行该命令以后的统计信息.用户可以通过指定统计的次数和时间来获得所需的统 ...

  4. Number()和new Number()的区别以及一种简单实现

    看MDN Beginners文档的时候注意到了这种用法 var n1 = Number(123); , 冒出的第一个疑问就是和 var n2 = new Number(123); 有什么区别呢? 首先 ...

  5. python环境搭建--pycharm的安装及使用

    学习网址: --菜鸟教程(2.0和3.0) http://www.runoob.com/python/python-tutorial.html http://www.runoob.com/python ...

  6. 【原创】ligerGrid使用初长成

    第一步:下载ligerUI  ,官网: http://www.ligerui.com/ 里边有详细的API.demo等信息,选择需要的版本下载. 第二步:解压缩,得到ligerUI文件夹,里边包含js ...

  7. Intel DPDK 全面解读

    高性能网络技术 随着云计算产业的异军突起,网络技术的不断创新,越来越多的网络设备基础架构逐步向基于通用处理器平台的架构方向融合,从传统的物理网络到虚拟网络,从扁平化的网络结构到基于 SDN 分层的网络 ...

  8. Java8内存模型—永久代(PermGen)和元空间(Metaspace)(转)

    Java8内存模型—永久代(PermGen)和元空间(Metaspace) 查看原文点击传送门:http://www.cnblogs.com/paddix/p/5309550.html 提示:本文做了 ...

  9. js 生成 UUID

    在项目中遇到要生成 UUID 的需求,第一反应就是有没有原生的生成方法,找了找,发现没有,只能自己建立算法 function. 下面是我用的算法 function uuid(len, radix) { ...

  10. Linux下MongoDB安装和配置详解

    1.下载安装包 将解压到/usr/local/mongodb 文件夹下 # mkdir /usr/local/mongodb # tar zxvf mongodb-linux-x86_64-3.2.9 ...