2015年6月28日星期日

ASP.NET MVC 自定义错误页面心得 - kavensu

本邮件内容由第三方提供,如果您不想继续收到该邮件,可 点此退订
ASP.NET MVC 自定义错误页面心得 - kavensu  阅读原文»

自定义错误页面的目的,就是为了能让程序在出现错误/异常的时候,能够有较好的显示体验。

所以,首先要先了解,我们可以在哪里捕获异常。

当程序发生错误的时候,我们可以在两个地方捕获:

  1. Global里面的Application_Error 。
  2. HandleErrorAttribute 中的OnException。(需要新建一个类,继承HandleErrorAttribute)

那我们到底应该在哪里处理错误好呢?下面我来给大家说说他们的区别。

Application_Error

程序中发生的所有异常,都可以在这里捕获。但是有一个不足的地方,那就是,如果我们在这里捕获异常之后,需要显示错误页面,那么浏览器上的地址是会改变的,已经被重定向了。也就是说,浏览器上显示的地址,并不是真正发生错误的地址,而是仅仅是显示错误信息的页面地址。这个不足,跟在Web.config的customError中配置错误页面是一样的。

很多时候,我们是希望在访问某个URL后发生了错误,显示错误页面之后,URL还是不变。因此,在这里处理异常并不能满足这种需求。

OnException。(继承HandleErrorAttribute)

MVC的特点就是,每一个请求都对应一个Controller,当在某个Controller中发生异常时,我们都可以在OnException中捕获。但是,如果根本就找不到这个Controller,那么这种错误OnException就无能为力了。举个例子:

假设有个Controller叫About,当访问http://host/About/Index发生错误时,是可以在OnException中捕获的。但如果我访问http://host/Aboute/Index的时候,因为根本不存在Aboute控制器,所以这种错误是无法在OnException捕获的,如果要捕获这种错误,只能在Application_Error中处理。虽然OnException不能捕获所有的错误,但是,它可以解决Application_Error错误页面重定向的问题,在显示错误页面的时候,URL保持不变。

执行顺序

如果发生了错误,会先执行OnException,如果设置 filterContext.ExceptionHandled = true; 则说明该错误已被错误,不会再执行Application_Error,否则会继续执行Application_Error。

参考代码

protected void Application_Error(Object sender, EventArgs e)
{
//当路径出错,无法找到控制器时,不会执行FilterConfig中的OnException,而会在这里捕获。
//当发生404错误时,执行完OnException后,还会执行到这里。
//当发生其他错误,会执行OnException,但在base.OnException中已经处理完错误,不会再到这里执行。
var lastError = Server.GetLastError();
if (lastError != null)
{
var httpError = lastError as HttpException;

if (httpError != null)
{
//Server.ClearError();
switch (httpError.GetHttpCode())
{
case 404:
Response.Redirect(
"/Views/Static/404.html");
break;
}
}
}
}

[AttributeUsage(AttributeTargets.Class, Inherited = true, AllowMultiple = false)]
public class LogExceptionAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
string controllerName = (string)filterContext.RouteData.Values["controller"];
string actionName = (string)filterContext.RouteData.Values["action"];
HandleErrorInfo info
= new HandleErrorInfo(filterContext.Exception, controllerName, actionName);

HttpRequestBase request
= filterContext.RequestContext.HttpContext.Request;
string broser = request.Browser.Browser;
string broserVersion = request.Browser.Version;
string system = request.Browser.Platform;
string errBaseInfo = string.Format("UserId={0},Broser={1},BroserVersion={2},System={3},Controller={4},Action={5}", AuthAttribute.GetUserId(), broser, broserVersion, system, controllerName, actionName);
LogUtil.Error(errBaseInfo, filterContext.Exception, Website.LOG_ID);

if (!filterContext.ExceptionHandled)
{
if (filterContext.HttpContext.IsCustomErrorEnabled)
{
filterContext.HttpContext.Response.Clear();
HttpException httpex
= filterContext.Exception as HttpException;
if (httpex != null)
{
filterContext.HttpContext.Response.StatusCode
= httpex.GetHttpCode();
// info = new HandleErrorInfo(ex, controllerName, actionName);
//switch (httpex.GetHttpCode())
//{
// case 403:
// break;
// case 404:
// break;
// default:
// base.OnException(filterContext);
// break;
//}
}
else
{
filterContext.HttpContext.Response.StatusCode
= 500;
}

filterContext.Result
= new ViewResult() { ViewName = "/Views/Shared/Error.cshtml", ViewData = new ViewDataDictionary<HandleErrorInfo>(info) };
filterContext.ExceptionHandled
= true;
Scala学习(六)---Scala对象 - sunddenly  阅读原文»

Scala中的对象

摘要:

在本篇中,你将会学到何时使用Scala的object语法结构。在你需要某个类的单个实例时,或者想为其他函数找一个可以挂靠的地方时,你就会用到它。本篇的要点包括:

1. 用对象作为单例或存放工具方法

2. 类可以拥有—个同名的伴生对象

3. 对象可以扩展类或特质

4. 对象的apply方法通常用来构造伴生类的新实例

5. 如果不想显式定义main方法,可以用扩展App特质的对象

6. 你可以通过扩展Enumeration对象来实现枚举

单例对象

Scala没有静态方法静态字段,你可以用object这个语法结构来达到同样目的。对象定义了某个类的单个实例,包含了你想要的特性。例如:

object Accounts {

private var lastNumber=0

def newUniqueNumber() = { lastNumber+=1, lastNumber}

}

当你在应用程序中需要一个新的唯一账号时,调用Accounts.newUniqueNumber()即可。对象的构造器在该对象第一次被使用时调用。在本例中,Accounts的构造器在Accounts.newUniqueNumber()的首次调用时执行。如果一个对象从未被使用,那么其构造器也不会被执行。

对象本质上可以拥有类的所有特性,它甚至可以扩展其他类或特质。只有一个例外:你不能提供构造器参数。对于任何你在Java或C++中会使用单例对象的地方,在Scala中都可以用对象来实现:

■ 作为存放工具函数常量的地方

■ 高效地共享单个不可变实例

■ 需要用单个实例来协调某个服务时,可参考单例模式

注意:很多人都看低单例模式。Scala提供的是工具,可以做出好的设计,也可以做出糟糕的设计,你需要做出自己的判断。

伴生对象

在Java或C++中,你通常会用到既有实例方法又有静态方法的类。在Scala中,你可以通过和与类同名的"伴生"对象来达到同样的目的。例如:

class Account {

val id=Account.newUniqueNumber()

private var balance =0

def deposit (amount: Double) { balance+=amount }

}

object Account{ // 伴生对象

private var lastNumber=0

private def newUniqueNumber() = { lastNumber+=1;lstNumber }

}

和它的伴生对象可以相互访问私有特性。它们必须存在于同一个源文件中这说明了类的伴生对象可以被访问,但并不在作用域当中。举例来说,Account类必须通过Account.newUniqueNumber()而不是直接用newUniqueNumber()来调用伴生对象的方法。

扩展类或特质的对象

一个object可以扩展类以及一个多个特质,其结果是一个扩展了指定类以及特质类的对象,同时拥有在对象定义中给出的所有特性。一个有用的使用场景是给出可被共享的缺省对象。举例来说,考虑在程序中引入一个可撤销动作的类:

abstract class UndoableAction (val description: String) {

def undo() : Unit

def redo() : Unit

}

默认情况下可以是"什么都不做"。当然了,对于这个行为我们只需要一个实例即可:

object DoNothingAction extends UndoableAction("Do nothing") {

override def undo () {}

override def redo () {}

}

DoNothingAction对象可以被所有需要这个缺省行为的地方共用。

val actions=Map( "open" -> DoNothingAction,"save" -> DoNothingAction,…) // 打开和保存功能尚未实

apply方法

apply含义

我们通常会定义和使用对象的apply方法。当遇到如下形式的表达式时,apply方法就会被调用:

Object(参数1,…,参数N)

通常,这样—个apply方法返回的是伴生类的对象举例来说,Array对象定义了apply方法,让我们可以用下面这样的表达式来创建数组:

Array("Mary", "had", "a", "little", "lamb")

为什么不用构造器呢?对于嵌套表达式而言,省去new关键字会方便很多,例如:

Array (Array (1, 7),Array (2, 9))

注意:Array(100)和new Array(100)很容易搞混。前一个表达式调用的是apply(100),输出一个单元素整数100的Array。而第二个表达式调用的是构造器this(100),结果是Array[Nothing],包含了100个null元素。

apply示例

这里有一个定义apply方法的示例:

class Account private (val id: Int, initialBalance: Double) {

private var balance=initiaIBalance

………

}

object Account { //伴生对象

def apply (initialBalance: Double) =

new Account (newUniqueNumber(), initialBalance)

}

这样一来你就可以用如下代码来构造账号了:

val acct = Account (1000.0)

应用程序对象

main方法

每个Scala程序都必须从一个对象的main方法开始,这个方法的类型为Array[String]=> Unit:

object Hello{

def main (args: Array[String]) {

println("Hello, World! ")

}

}

扩展App特质

除了每次都提供自己的main方法外,你也可以扩展App特质,然后将程序代码放人构造器方法体内:

object Hello extends App{

println("Hello, World! ")

}

命令行参数

如果你需要命令行参数,则可以通过args属性得到:

object Hello extends App{

if (args.length > 0)

println("Hello, "+args (0))

else

println("Hello, World! ")

}

时间特质

如果你在调用该应用程序时设置了scala.time选项的话,程序退出时会显示逝去的时间

scalac Hello.scala

scala -Dscala.time Hello Fred

Hello, Fred

[total 4ms]

所有这些涉及一些小小的魔法。App特质扩展自另一个特质Dela

阅读更多内容

没有评论:

发表评论