Asp.net MVC3恢宏的Ajax异常处理特性

      在Asp.net MVC 3
Web开发中,我们见面大量使用各种ajax请求,针对ajax请求什么结何server端如何做深处理为?我们好扩大ActionFilterAttribute,实现一个Ajax异常处理特性。假设你是运用JQuery脚本开发来贯彻Ajax,看代码:

   1: #region AjaxExceptionAttribute

   2: /// <summary>

   3: /// Ajax Exception Handle Attribute

   4: /// </summary>

   5: [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]

   6: public class AjaxExceptionAttribute : ActionFilterAttribute, IExceptionFilter

   7: {

   8:     /// <summary>

   9:     /// Called when an exception occurs.

  10:     /// </summary>

  11:     /// <param name="filterContext">The filter context.</param>

  12:     public void OnException(ExceptionContext filterContext)

  13:     {

  14:         if (!filterContext.HttpContext.Request.IsAjaxRequest()) 

  15:             return;

  16:  

  17:         filterContext.Result = AjaxError(filterContext.Exception.Message, filterContext);

  18:  

  19:         //Let the system know that the exception has been handled

  20:         filterContext.ExceptionHandled = true;

  21:     }

  22:  

  23:     /// <summary>

  24:     /// Ajaxes the error.

  25:     /// </summary>

  26:     /// <param name="message">The message.</param>

  27:     /// <param name="filterContext">The filter context.</param>

  28:     /// <returns>JsonResult</returns>

  29:     protected JsonResult AjaxError(string message, ExceptionContext filterContext)

  30:     {

  31:         //If message is null or empty, then fill with generic message

  32:         if (String.IsNullOrEmpty(message))

  33:             message = "Something went wrong while processing your request. Please refresh the page and try again.";

  34:  

  35:         //Set the response status code to 500

  36:         filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError;

  37:  

  38:         //Needed for IIS7.0

  39:         filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;

  40:  

  41:         return new JsonResult

  42:         {

  43:             //can extend more properties 

  44:             Data = new AjaxExceptionModel () { ErrorMessage = message },

  45:             ContentEncoding = System.Text.Encoding.UTF8,

  46:             JsonRequestBehavior = JsonRequestBehavior.DenyGet

  47:         };

  48:     }

  49: } 

  50: #endregion

  51:  

  52: /// <summary>

  53: /// AjaxExceptionModel

  54: /// </summary>

  55: public class AjaxExceptionModel

  56: {

  57:     /// <summary>

  58:     /// Gets or sets the error message.

  59:     /// </summary>

  60:     /// <value>

  61:     /// The error message.

  62:     /// </value>

  63:     public string ErrorMessage { get; set; }

  64: }

代码已经出连锁注释。AjaxExceptionModel您了可以从定义再度多之习性,然后以Controller或Action上长这个特性。
像下面这HomeController有一个YouKnow的Action,这里吧示范我们有意throw一个Exception:

[AjaxException]

public class HomeController : BaseController

{

    [HttpPost]

    public ActionResult YouKnow(FormCollection fc)

    {

        throw new ArgumentNullException("YouKnow method: fc should not be null");

    }

}

搭下看HTML与JQuery:

<h4 id="lblMethodError">

</h4>

<br />

<h4 id="lblMethodSuccess">

</h4>

<br />

<h2>ajax post</h2>

<input type="button" value="Post method" id="inputajax1" />

<br />

<input type="button" value="Ajax method with error section" id="inputajax2" />

<p>

    <input type="button" value="Post method for undefined Url" id="inputajax3" />

</p>

<p>

    <input type="button" value="Post method to get Json Result" id="inputajax4" />

</p>

<br />

<h3 id="errorh3info">

</h3>

JQuery的全局AjaxError配置,可参考官方

$("#errorh3info").ajaxError(function (event, request, settings) {

    $(this).append("<li>settings.url:" + settings.url + "</li>");

    $(this).append("<li>request.status:" + request.status + "</li>");

    $(this).append("<li>request.statusText:" + request.statusText + "</li>");

 

    //request.responseText

    if (request.responseText != "") {

        var jsonValue = jQuery.parseJSON(request.responseText);

        $(this).append("<li>ErrorMessage:" + jsonValue.ErrorMessage + "</li>");

    }

});

于button增加一个Post请求:

$('#inputajax1').click(function () {

    $.post('/Home/YouKnow/'

   , { id: 1 }

   , function (data) {

       $('div#right-box.data').html(data);

   });

});

这会儿View上拿展示, 我们以视ErrorMessage是JSON对象的习性:

settings.url:/Home/YouKnow/

request.status:500

request.statusText:error

ErrorMessage:Value cannot be null. Parameter name: YouKnow method: fc
should not be null

自为足以如此:

//ajax post when throw an exception at server side

$('#inputajax2').click(function () {

    $.ajax({

        type: "POST",

        url: "/Home/YouKnow2",

        data: "fail=1",

        dataType: "json",

        error: function (xhr, status, error) {

            // Show the error

            $('#lblMethodError').append(xhr.responseText);

            $('#lblMethodError').show();

        },

        success: function (data, textSuccess) {

            // show the success message

            $('#lblMethodSuccess').show();

        }

    });

});

这儿View上,比地方很请求多显示同一长达消息,
这是为咱们这里定义了温馨error处理callback.

{“ErrorMessage”:”Value cannot be null.\r\nParameter name: YouKnow method: fc should not be null”}

当我们请一个请勿存在Action时也:

//request undefined url

$('#inputajax3').click(function () {

    $.post('/Home/YouKnow2233/'

   , { id: 1 }

   , function (data) {

       $('div#right-box.data').html(data);

   });

});

页面上用显得:

settings.url:/Home/YouKnow2233/

request.status:0

request.statusText:error

末我们来拘禁这个ActionFilter的单元测试,这里以Moq类库:

[TestMethod]

public void Test_Native_AjaxExceptionAttribute()

{

    //arrange

    var header = new System.Collections.Specialized.NameValueCollection();

    header.Add("X-Requested-With", "XMLHttpRequest");

 

    var mockRequest = new Mock<HttpRequestBase>();

    mockRequest.SetupGet(http => http.Headers).Returns(header);

 

    var mockResponse = new Mock<HttpResponseBase>();

 

    var mockHttpContext = new Mock<HttpContextBase>();

    mockHttpContext.SetupGet(c => c.Request).Returns(mockRequest.Object);

    mockHttpContext.SetupGet(c => c.Response).Returns(mockResponse.Object);

 

    var context = mockHttpContext.Object;

    var exceptonContextMock = new Mock<ExceptionContext>();

    exceptonContextMock.SetupGet(ac => ac.HttpContext).Returns(context);

    string errorStr="error";

    exceptonContextMock.SetupGet(ec => ec.Exception).Returns(new AggregateException(errorStr));

 

    //act

    var ajaxAttribute = new AjaxExceptionAttribute();

    var exceptionContext = exceptonContextMock.Object;

    ajaxAttribute.OnException(exceptionContext);

 

    //verify

    mockRequest.VerifyAll();

    mockResponse.VerifyAll();

    mockHttpContext.VerifyAll();

    exceptonContextMock.VerifyAll();

 

    //assert

    var jsonResult = exceptionContext.Result as JsonResult;

    Assert.IsNotNull(jsonResult.Data);

    Assert.IsTrue(exceptionContext.HttpContext.Request.IsAjaxRequest());

    Assert.AreEqual((jsonResult.Data as AjaxExceptionModel).ErrorMessage, errorStr);

    Assert.AreEqual(JsonRequestBehavior.DenyGet, jsonResult.JsonRequestBehavior);

    Assert.AreEqual(typeof(AggregateException), exceptionContext.Exception.GetType());

 

} 

方的UnitTest我们Mock
HttpContext,HttpRequest,HttpResponse来落实对ActionFilter的测试。
但愿你Web开发出帮助。

作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意要保留这个段子声明,且当文章页面明显位置于来原文连接,否则保留追究法律责任的权。
拖欠文章吧又披露在自己的独门博客中-Petter Liu
Blog。

相关文章