分享我的工作、生活与心情,让自己变得丰富多彩!
技术 | 2018-07-03 21:18
ABP提供了一些对象和函数集,使得了javascript开发简单且标准化。
下面,我们一一讲解ABP中的这些javascript API。
使用Ajax调用服务端的服务,并返回服务端响应的内容。因为ABP对于Ajax调用会返回一个标准的响应,因此,建议使用该方法处理标准的返回值。
现代应用程序频繁使用Ajax调用,特别是在SPA中,它几乎是和服务器交互的唯一方式。
Ajax调用包含了许多重复性的步骤:
一般来讲,在客户端javascript代码应该提供一个URL,data是否提供是可选的,以及选择一个执行Ajax调用的方法(Post,Get…)。必须等待然后才能处理返回的值。当向服务端发起调用时可能会发生错误(一般是网络错误)。服务端也可能发生错误,服务器可能发送了一个具有错误信息的失败响应。客户端代码应该处理服务端响应的错误,并选择性地通知用户(可能展示一个error对话框)。如果没有错误,且服务器返回了数据,客户端也必须处理。此外,一般它会阻塞一些(或者整个)屏幕区域,并展示一个繁忙的指示标志,直到Ajax操作结束。
服务端应该接收请求,然后执行服务端的代码,捕获任何异常并返回一个有效的响应给客户端。在发生错误的情况下,它可以有选择地发送一个错误消息给客户端;成功时,它可以返回数据给客户端。
ABP通过使用abp.ajax函数封装Ajax的调用,自动化了这其中的一些步骤。一个ajax调用的例子如下:
var newPerson = { name: 'Dougles Adams', age: 42 }; abp.ajax({ url: '/People/SavePerson', data: JSON.stringify(newPerson) }).done(function(data) { abp.notify.success('created new person with id = ' + data.personId); });abp.ajax以一个对象作为接收选项。你可以传递任何在jQuery的$.ajax方法中有效的任何参数。这里有一些 默认的值:dataType是‘json’,type是‘POST’,contentType是‘application/json’(因此,在发送到服务器之前,我们可以调用JSON.stringify将javascript对象转成JSON字符串)。你可以通过将选项传给abp.ajax重写默认值。
abp.ajax返回了promise。因此,你可以写done,fail,then等处理函数。上面的例子中,我们向 PeopleController的SavePerson的action发送了简单的Ajax请求。在 done处理函数中,我们获得了新添加的person的数据库Id,而且展示了一个成功的通知。让我们看一下该Ajax请求的 MVC控制器:
public class PeopleController : AbpController { [HttpPost] public JsonResult SavePerson(SavePersonModel person) { //TODO:将新的person保存到数据库,并返回该person的Id return Json(new {PersonId = 42}); } }SavePersonModel包含了Name和Age属性。SavePerson标记有 HttpPost特性,因为abp.ajax默认的方法是POST。这里通过返回一个匿名的对象简化了方法的实现。
这个看上去简单明了,但是ABP背后处理了许多重要的事情。让我们深入细节看一下:
虽然我们直接返回了一个具有PersonId=2的对象,但是ABP会使用一个MVCAjaxResponse对象封装了它。实际的Ajax响应是像下面那样的:
{ "success": true, "result": { "personId": 42 }, "error": null, "targetUrl": null, "unAuthorizedRequest": false }这里,所有的属性都是camelCase的(因为在javascript中这是惯例),即使在服务端代码中是PascalCased的。下面解释一下所有的字段:
success:一个布尔值,表示操作的成功状态。如果是true,abp.ajax会解析该promise,并调用 done处理函数。如果是false(如果在方法调用中发生了异常),它会调用 fail处理函数并使用abp.message.error函数展示一个 error消息。
result:控制器的action返回的实际值。如果success是true,而且服务器发送了一个返回值,它才有效。
error:如果success是false,那么该字段是一个包含了 message和 detail字段的对象。
targetUrl:这为服务器提供了一种重定向客户端到其他Url的可能性。
unAuthorizedRequest:这为服务器提供了通知客户端该操作没有授权或者用户没有认证的可能性。如果该值是true,那么abp.ajax会 重新加载当前的页面。
通过从AbpController类中派生就可以将返回值转换成一个封装的Ajax响应。 abp.ajax会识别并计算该响应。因此,它们成对工作。如果没有发生错误的话,那么abp.ajax的done处理函数会获得控制器返回的实际值(一个具有personId属性的对象)。
当从AbpApiController类派生时,也会存在相同的机制。
正如上面描述的,ABP会处理服务器中的所有异常,并返回一个具有错误信息的对象,如下所示:
{ "targetUrl": null, "result": null, "success": false, "error": { "message": "An internal error occured during your request!", "details": "..." }, "unAuthorizedRequest": false }可以看到,success是false,result是null。abp.ajax处理该对象,而且使用abp.message.error函数展示一个错误信息给用户。如果你的服务端代码抛出了一个UserFriendlyException类型的异常,它会直接给用户显示异常信息。否则,它会隐藏实际的错误(将错误写到日志中),并展示一个标准的“服务器内部错误…”信息给用户。所有的这些都是ABP自动处理的。
虽然ABP提供了一种使得调用Ajax很简单的机制,但是在真实世界的应用中,为每个Ajax调用编写javascript函数是很经典的,比如:
//创建一个抽象了Ajax调用的function var savePerson = function(person) { return abp.ajax({ url: '/People/SavePerson', data: JSON.stringify(person) }); }; //创建一个新的 person var newPerson = { name: 'Dougles Adams', age: 42 }; //保存该person savePerson(newPerson).done(function(data) { abp.notify.success('created new person with id = ' + data.personId); });对于每个Ajax调用都写个函数是个好的做法,但是这耗时且乏味。ASP.NET为应用服务层方法提供了自动生成这些类型的函数机制。请阅读《动态Web API层》
展示自动关闭的通知。
我们喜欢一些事情发生时展示一些精致的自动消失的通知,比如当保存一条记录或者问题发生时。ABP为这个定义了标准的APIs。
abp.notify.success('a message text', 'optional title'); abp.notify.info('a message text', 'optional title'); abp.notify.warn('a message text', 'optional title'); abp.notify.error('a message text', 'optional title');通知API默认是使用toastr库实现的。要使toastr生效,你应该引用toastr的css和javascript文件,然后再在页面中包含abp.toastr.js作为适配器。一个toastr成功通知如下所示:

你也可以用你最喜欢的通知库中实现通知。只需要在自定义javascript文件中重写所有的函数,然后把它添加到页面中而不是abp.toastr.js(你可以检查该文件看它是否实现,这个相当简单)中。
给用户展示消息对话框。
消息API用于给用户展示消息或者获得用户的确认。
消息API默认是使用sweetalert实现的。要让sweetalert生效,你应该包含它的css和javascript文件,然后再页面中添加 abp.sweet-alert.js的引用作为适配器。
例子如下:
abp.message.info('some info message', 'some optional title'); abp.message.success('some success message', 'some optional title'); abp.message.warn('some warning message', 'some optional title'); abp.message.error('some error message', 'some optional title');一个成功的消息如下所示:

例子如下:
abp.message.confirm( 'User admin will be deleted.', 'Are you sure?', function (isConfirmed) { if (isConfirmed) { //...删除用户 } } );这里的第二个参数(title)是可选的,因此,回调函数也可以是第二个参数。
一个确认消息的例子如下所示:

ABP内部使用了Message API。比如,如果Ajax调用失败了,那么它会调用abp.message.error。
使用一个区域(一个div,form,整个页面等)阻塞用户的输入。此外,还使得一个区域处于繁忙状态(具有一个繁忙的指示器,如‘loading…’)。
该API使用一个透明的涂层(transparent overlay)来阻塞整个页面或者该页面上的一个元素。这样,用户的点击就无效了。当保存一个表单或者加载一个区域(一个div或者整个页面)时这是很有用的,比如:
abp.ui.block(); //阻塞整个页面 abp.ui.block($('#MyDivElement')); //可以使用jQuery 选择器.. abp.ui.block('#MyDivElement'); //..或者直接使用选择器 abp.ui.unblock(); //解除阻塞整个页面 abp.ui.unblock('#MyDivElement'); //解除阻塞特定的元素UI Block API默认使用jQuery的blockUI插件实现的。要是它生效,你应该包含它的javascript文件,然后在页面中包含abp.blockUI.js作为适配器。
该API用于使得某些页面或者元素处于繁忙状态。比如,你可能想阻塞一个表单,然后当提交表单至服务器时展示一个繁忙的指示器。例子:
abp.ui.setBusy('#MyLoginForm'); abp.ui.clearBusy('#MyLoginForm');样例截图:

该参数应该是一个选择器(如‘#MyLoginForm’)或者jQuery选择器(如$(‘#MyLoginForm’))。要使得整个页面处于繁忙状态,你可以传入null(或者’body’)作为选择器。
setBusy函数第二个参数接收一个promise(约定),当该约定完成时会自动清除繁忙的状态。例子:
abp.ui.setBusy( $('#MyLoginForm'), abp.ajax({ ... }) );因为abp.ajax返回promise,我们可以直接将它作为promise传入。要学习惯于promise更多的东西,查看jQuery的Deferred。
UI Busy API是使用spin.js实现的。要让它生效,应该包含它的javascript文件,然后在页面中包含abp.spin.js作为适配器。
在客户端记录日志。
当你想要在客户端记录一些简单的日志时,你可以使用console.log(‘…’)API,这你已经知道了。但是这种写法不是所有的浏览器都支持的,而且可能会破坏你的脚本。因此,你应该首先检查console是否可用,此外,你可能想在别的地方记录日志,甚至你想以某种级别记录日志。ABP定义了安全的日志函数:
abp.log.debug('...'); abp.log.info('...'); abp.log.warn('...'); abp.log.error('...'); abp.log.fatal('...');你可以通过设置abp.log.level为abp.log.levels之一来更改日志级别(比如,abp.log.levels.INFO没有记录调试日志)。这些函数默认将日志记录到了浏览器的控制台里了。但如果你需要的话,你也可以重写或者扩展这个行为。
ABP提供了一些通用的工具功能。
用于立即创建更深的命名空间。假设我们有一个基命名空间‘abp’,然后想要创建或者获得‘abp.utils.strings.formatting’命名空间。不需要下面这样写:
//创建或获得namespace abp.utils = abp.utils || {}; abp.utils.strings = abp.utils.strings || {}; abp.utils.strings.formatting = abp.utils.strings.formatting || {}; //给该namespace添加一个function abp.utils.strings.formatting.format = function() { ... };我们可以这样写:
var formatting = abp.utils.createNamespace(abp, 'utils.strings.formatting'; //给该namespace添加一个function formatting.format = function() { ... };这样就简化了安全地创建深入的命名空间了。注意,第一个参数是必须存在的根命名空间。
这个和C#中的string.Format()很相似。用法示例:
var str = abp.utils.formatString('Hello {0}!', 'World'); //str = 'Hello World!' var str = abp.utils.form冉冉的365天 渝ICP备14008124号-2