返回首页

介绍
我爱微软的脚本服务。我用他们所有的时间在我的日常工作​​。事实上,我爱他们,以至于我我在一边做的工作。话虽这么说,还有改进的余地,我用他们,我跨在那里他们可以更好地已实施的方式来。
对于那些不熟悉脚本服务,他们暴露在任何装饰与Web服务方法的Web服务扩展作为从客户端使用AJAX调用ScriptMethod属性。我个人使用他们是在我的网站业务逻辑层。背景
在目前的ASP.NET网站我发展,我用下面的架构:
{S0的}
我有一个母版页与一个全球性的样式表和JavaScript文件,以及使用jQuery和LT; ASP:ScriptManagergt;支持ScriptServices。每一页都有其自己的样式表(页面来处理特定的样式),其自己的JavaScript文件,当然其代码隐藏文件。
包含在ASPX页面是空的容器和模态弹出形式。页面上的内容的90%来自调用Web服务并显示结果。在Web服务,数据库的请求转换成XML(通常使用LINQ),然后返回到网页之前使用XSLT文件转换要插入容器。目前,我的所有。aspx.vb代码隐藏文件包含(最多)的安全检查,以未经授权的用户重定向家页;脚本服务中存在的所有的业务逻辑。
原来,每个网页有所有的CSS内联所有的HTML和JavaScript。aspx文件中,或位于从母版页的全球样式,但有相当凌乱不羁的,所以我分裂成独立的部分,这一切。
尽管这个架构很好地表示和业务逻辑层分开,它确实有一些缺点:检索由它生成的动态JavaScript脚本服务,创建一个额外的连接到Web服务器。无论用户是装饰用ScriptMethod属性的所有方法都暴露在客户端脚本。每个公开的方法的安全性,必须处理方法内(即,你必须确定,如果用户调用的方法实际上有权限里面做身体的方法)。 脚本服务是Web服务的扩展,仍然可以访问Web服务,你可能不是真的想。为了使用脚本服务,你必须有LT; ASP:在页面上(或母版页)(或AJAX Control Toolkit中等价)ScriptManagergt。这种控制转换成几个额外的LT; scriptgt,这反过来又需要更多的连接到服务器上检索它们的内部脚本的引用。
这些问题并非不可克服。例如,你可以在每个方法开始做安全检查,以确保用户有权限调用它。风险来了你忘了这样做,一些聪明的黑客,知道如何在IE8中使用的F12键,或以后开始手动调用脚本的方法,你可能没有预测的方式。
大多数网站也有多个用户风味。例如,在一个论坛网站页面,可能有市民观看的职位(只读访问),注册用户只能发布和删除自己的帖子,版主,用户可以批准的职位,并删除任何职位,管理员谁可以做到这一切,再加上管理用户列表。这使得很多写一个quot感; postingquot;页只显示/隐藏功能,基于用户是谁,而不是写基于相同的页面变化用户。如果你要保持在一个地方但是所有相关页面异步代码,使用微软的脚本服务,公开所有原型所有用户(包括行政的!)方法。甚至在每个方法的安全检查,揭示潜在的黑客的方法原型可能不是最好的事情。
作为编程书呆子型人喜欢推倒重来,我决定重新功能ScriptMethod的,但做的方式工作更好地为我和提高了安全性。的要求
我开始定义我所期待的最终结果有一些要求:在后面的代码页,它们适用于异步方法应该存在。在母版页或页面的祖先类中定义的异步方法予以曝光。异步页面上定义的方法应该是相对容易地通过网站内的其他网页能够被重用。protected修饰符声明的方法应该只暴露在定义它们的页面生成时,客户端脚本。开发人员应该能够很容易地确定条件下的方法接触到的客户端(例如,基于用户是谁,等等)。我们的网站已经有库的引用。
现在,我们知道我们的目标,我们就可以开始。解决方案
我们需要做的第一件事是定义了两个类继承自Attribute。首先将被应用到任何页面,其中包含异步方法, 第二,将被应用到任何开发商要公开异步代码的方法。

<AttributeUsage(AttributeTargets.Class)> _

Public Class AsyncClassAttribute

    Inherits Attribute



    Private MyScriptClassName As String = ""

    Public ReadOnly Property ScriptClassName() As String

        Get

            Return MyScriptClassName

        End Get

    End Property



    Public Sub New(ByVal scriptClassName As String)

        MyScriptClassName = scriptClassName

    End Sub

End Class

属性是非常基本的。这个属性允许你指定的类/对象的名称包含在客户端的方法脚本。我不单纯的页面类的名称相匹配的原因是,一些页面的名称可能是在JavaScript中的保留字,就更不用说了,Default.aspx的类的名称是愚蠢的东西一样quot; Default_aspxquot;,谁愿意使用呢?
下面是一个如何将使用此属性的例子:{C}
假设你暴露在上面的例子中命名的HelloWorld方法,你就可以从JavaScript调用它像这样:
Boogaloo.HelloWorld(/*args go here */);

接下来的属性是你想公开的方法,将被应用到:{体C3}
这个类看起来很斯巴达,但我们会谈论它有点迟。使用属性
我们有我们的属性,我们可以与他们甚至装饰类和方法。但现在是什么?这些属性如何真正做什么?
答案是属性无能为力。但是,我们现在可以看看他们的存在为基础的属性和行为。而且,由于我们的目标是把我们的异步方法在我们的网页脚本背后,我们应该把我们的代码,在页面本身,或更好,但在一个基类可以继承,我们所有的网页:{的C4}
下面是我们的基类,AyncPage,从System.Web.UI.Page继承的开始。我们做的第一件事是覆盖从OnLoadComplete方法。里面的方法,我们首先检查是否请求一个异步方法执行存在(后来)。如果没有,我们期待着看到另一页,如果已要求我们的公共方法的客户端脚本,在这种情况下,我们只输出客户端脚本和网页的内容没有。如果没有条件得到满足,这是一个普通的页面请求,所以我们需要生成客户端脚本调用我们的方法。
下一个方法是,我们将建立在AsyncPage BuildAsynchronousScriptCalls。这个私有方法有一个参数,一个布尔值,指示页请求是否是页面本身或客户端脚本。{C5的}
这段代码检查为AsyncClass属性和提取的客户端类的名称(默认为当前类的名称,否则),并使用一个StringBuilder构造的JavaScript方法的原型。如果请求是本地的,这个页面有一个母版页,我们呼吁我们的ExtractClientScriptMethods方法(见下文),传递给它的母版页的类型。最后,我们呼吁ExtractClientScriptMethods当前类的类型。一旦所有的脚本已经生成,我们要么使用的ClientScript的类注册到我们的脚本块所产生的页面或简单的转储我们使用Response.Write的JavaScript。
现在我们进入JavaScript生成ExtractClientScriptMethods的胆量;{5233}
在此方法中,我们使用反射来获取在我们的类的所有方法的列表。我们测试,看它是否有适用于它的AsyncMethodAttribute。要总结,我们建立名为我们公开的方法相同的JavaScript方法,参数加上三个额外的相同数量的onSuccess,onFailure处,和上下文。那些熟悉微软的脚本方法会知道,前两个是被调用JavaScript函数的异步调用时成功或失败(分别),第三是可以包含任何你想它包含一个上下文变量。所有这些额外的三个参数是可选的。
这些JavaScript方法体都含有一个名为__construct异步方法调用。这是一个方法,你需要在全球包括JavaScript文件中使用jQuery的ajax方法的异步调用服务器端方法:{C7-}
记住回到我们第一次检查,看看如果一个异步方法调用被要求在在onLoadComplete事件吗?好吧,如果你看我们在ajax方法的URL参数,包括一个查询字符串项称为quot; __asyncmethodquot;设置它为我们的方法的名称。方法的参数被转换为一个JSON字符串,并通过POST数据。它的存在,导致ExecuteAsyncMethod被调用,查询字符串设置:{C8的}
我不会去到大,这种方法是如何工作的细节,它的名字搜索在页面请求的方法,并在主页面(如果存在)。它验证的数量和类型的参数匹配,并试图调用该方法。是否成功或失败,此方法返回相同的结果:私有类的序列化到JSON AsyncResults的一个实例。让AJAX调用知道如果返回状态的成员成功与否(从而确定客户端是否被调用的onSuccess或onFailure处)。
此时,如果任何意义,你应该问我如何决定系​​统是否公开/调用根据当前用户的方法。这一切都归结到这从上面的代码块中的代码片断:
Dim attr As AsyncMethodAttribute = a



If Not attr.IsValid(Me) Then

    accessGranted = False

    Exit For

End If

记得IsValid方法在AsyncMethodAttribute类默认返回真。我做的目的,作为并非所有的网站都会有同样的规则或用户类型。期望是你开发,将派生从AsyncMethodAttribute创建一个类,它接受一些价值它的构造,它在isValid使用的方法决定是否应公开的一部分。
(希望)使之更清楚,我已经包括了一个样本的网站,做到了这一点。样品
为了证明这一切是如何工作的,我已经创建了一个称为AsyncMethodsDemo,本文所附的示例网站。这是一个简单的单页消息发布网站的下列规定:所有经批准的,非删帖大家都可见只有注册用户可以创建新的职位标准用户职位是不可见的,直到被版主或管理员批准 版主,管理员,和笔者后可以删除帖子只有管​​理员可以添加或删除用户
哑/丑/缺乏数据验证/等,这个发布网站,请不要抱怨。证明异步方法,它确实存在。对于数据库,我用一个简单的XML文件在App_Data文件夹。是的,如果多的人访问该网站在同一时间,数据会发生碰撞。再次,它是不是该网站的点。实施安全
为了保证我的方法,我需要定义一个用户我的系统支持各种类型的枚举。此枚举在UserType.vb定义:{C10的}
然后,我创建一个新的属性派生类从AsyncMethodAttribute使用此枚举:{C11的}
然后,我宣布一个新类继承从AsyncPage,包含我SiteUser的实例对象。 ForumAsyncMethodAttribute使用这个类来检查当前登录的用户,并比较其UserType中成员属性的ValidUser这一成员。这是如何确保我们的客户端脚本生成,唯一的方法当前用户被曝光。现在在我们的Default.aspx.vb代码背后,我们可以宣布类似下面的方法...
...和JavaScript中的GetUsers通话将只显示,如果当前登录的用户是管理员。由于我们装饰UserType中列举Flags属性,我们可以使用位运算符指定多个用户有效的方法。回想一下,说明我们的要求,版主和管理员可以批准帖子:
<ForumAsyncMethod(UserType.Moderator Or UserType.Administrator)> _

Protected Sub ApprovePost(ByVal id As Integer)

    Dim db As New Database

    db.Data.<Posts>.<Post>

    (id).@Approved = "1"

    db.Save()

End Sub

同样,UserType中的每个人都将匹配对任何用户类型,因为它的二进制值是11111111。
在客户端,我们调用我们的方法,就像我们调用脚本的方法:
function approvePost(id)

{

    if (!confirm('Are you sure you want to approve this post?')) return;

    Forums.ApprovePost(id, refreshPosts, alertResult);    

}

随意在不同类型的用户登录,然后看看在Default.aspx的源来看看JavaScript代码的变化。我希望你会被受理。
享受此代码,并让我知道如果您有任何意见或疑问!历史2011年8月10日 - 最初的文章。

回答

评论会员:游客 时间:2012/02/04
三倍G:两个问题:1)你今年多大了?2)多少年了你的工作​​与ASP.NET应用程序?保持良好的工作
克莱顿Rumley
评论会员:游客 时间:2012/02/04
一些很古怪的问题,但在这里你走:1)我从我33岁生日几天的路程。2)我已经工作了自2001年以来的ASP.NET。我还曾与ASP自1997年ISH自1999年以来和PHP
。三倍G:你很成功的ASP.NET程序员!我挖,在第一时间和我在艰巨的环境感到惊讶!享受你是生日
评论会员:!Kamyar 时间:2012/02/04
令人印象深刻。写得很好,很好的解释。
从这篇文章学到了许多新的东西。将一个C#版本也不错(不硬转换,只是更熟悉...)
评论会员:游客 时间:2012/02/04
克莱顿Rumley:很高兴你喜欢的文章你不问我,包括C#,我的文章的第一人。在下一篇文章中,我肯定会包括用VB,C#代码,我通常使用。克莱顿
Celal AK:我翻译的C#。它的工作。不需要的静态方法。我可以访问页面,控制和主属性。很不错。
优秀
评论会员:克莱顿Rumley 时间:2012/02/04
谢谢你的客气话。我很高兴你喜欢
评论会员:保罗ç史密斯 时间:2012/02/04
大解释,我喜欢你的方法。很想看到这个版本的C#
评论会员:克莱顿Rumley 时间:2012/02/04
谢谢你的反馈。 C#版本不会是很难做到的,因为我没有做任何事情,在VB中的特殊。如果转换代码是不是你杯茶,你刚才编译的属性和成1的VB DLL页面基类,添加在您的ç#网站的参考和派生从AsyncMethod在C#中自己的类
评论会员:游客 时间:2012/02/04
。thatraja:保罗ç史密斯写道:希望能看到一个C#版本this.Hi,请检查这个博客后{A3}thatraja{A4纸}|没有人仍然是一个处​​女,生活螺丝大家{S1}