[JQuery]JQuery的CheckBox操作控制

mikel阅读(725)

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
 2<HTML>
 3 <HEAD>
 4  <TITLE> New Document </TITLE>
 5  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 6  <link href="css/ingrid.css" rel="stylesheet" type="text/css">
 7<script language="JavaScript" src="JQuery-1.2.3.pack.js" type="text/JavaScript"></script>
 8  <SCRIPT LANGUAGE="JavaScript">
 9  <!–
10      $("document").ready(function(){
11          
12       $("#btn1").click(function(){
13           
14          $("[name='checkbox']").attr("checked",'true');//全选
15        
16       }
)
17       $("#btn2").click(function(){
18           
19          $("[name='checkbox']").removeAttr("checked");//取消全选
20        
21       }
)
22       $("#btn3").click(function(){
23           
24          $("[name='checkbox']:even").attr("checked",'true');//选中所有奇数
25        
26       }
)
27       $("#btn4").click(function(){
28           
29          $("[name='checkbox']").each(function(){
30              
31            
32              if($(this).attr("checked"))
33            {
34                $(this).removeAttr("checked");
35                
36            }

37            else
38            {
39                $(this).attr("checked",'true');
40                
41            }

42            
43          }
)
44        
45       }
)
46        $("#btn5").click(function(){
47       var str="";
48          $("[name='checkbox'][checked]").each(function(){
49              str+=$(this).val()+"\r\n";
50          }
)
51         alert(str);
52       }
)
53      }
)
54  //–>
55  
</SCRIPT>
56  
57 </HEAD>
58
59 <BODY>
60 <form name="form1" method="post" action="">
61   <input type="button" id="btn1" value="全选">
62   <input type="button" id="btn2" value="取消全选">
63   <input type="button" id="btn3" value="选中所有奇数">
64   <input type="button" id="btn4" value="反选">
65   <input type="button" id="btn5" value="获得选中的所有值">
66   <br>
67   <input type="checkbox" name="checkbox" value="checkbox1">
68   checkbox1
69   <input type="checkbox" name="checkbox" value="checkbox2">
70   checkbox2
71   <input type="checkbox" name="checkbox" value="checkbox3">
72   checkbox3
73   <input type="checkbox" name="checkbox" value="checkbox4">
74   checkbox4
75   <input type="checkbox" name="checkbox" value="checkbox5">
76   checkbox5
77   <input type="checkbox" name="checkbox" value="checkbox6">
78   checkbox6
79   <input type="checkbox" name="checkbox" value="checkbox7">
80   checkbox7
81   <input type="checkbox" name="checkbox" value="checkbox8">
82 checkbox8
83 </form>
84
85 </BODY>
86</HTML>
87

[FLEX]Flex与ASP.NET通过Remoting方式进行通讯

mikel阅读(704)

前两天研究了一下Flex与.NET如何进行数据交互,并写了一个文档,后面叙述得还不是很详细,还可以再研 究深一点。本文是关于Flex与ASP.NET通过Remoting方式进行通讯的内容,过段时间有空还会把其它的通讯方式也描述一下,顺便也会把 Flex3与FluorineFx数据类型转换这方面的内容讲一下,都是通过在网上找资料和自己研究所总结出来的,应该说讲得还是很浅,毕竟学得还不深, 继续努力学习!

一、软件:

1Flex平台:Adobe Flex Builder 3

2.Net平台:Visual Studio .Net 2008

3Remoting网关:Fluorine

4、第三方组件:RemoteObjectAMF0

 

二、介绍:

1Fluorine是一种开源的AMF(ActionScript Messaging Formatter)网关,专门负责Flex3.0.Net交互时的数据类型转换。Fluorine现支持ActionScript 2.0ActionScript 3.0,所以Fluorine也可作为Flash.Net交互时的AMF网关。

2RemoteObjectAMF0组件是一种基于MXML的第三方组件,用于连接AMF网关。

3、好处:

1)交互时数据类型的自动转换。因为Flex.NET的数据类型是不同的,例如FlexDate.NET中的DateTime类型。这样就导致Flex.NET进行数据交互过程中必须进行数据类型的转换。这种数据类型的转换我们可以自己通过编写相关的代码来实现,例如在Flex.NET中编写一个实体类对其取得的数据进行类型转换。而利用Fluorine这种网关来实现数据交互的话,它能够实现.NETFlex中的数据类型的自动对应转换,这样从一定程度上就减轻了我们对其数据类型处理的烦恼。

2)交互效率的提高:利用网关进行数据交互的话,它使得Flex能够直接与.Net的数据处理类进行通信,而不必像再通过另一层中间数据交互层来实现,从一定程度上它的交互效率会提高很多。

3)这是一个开源的网关。

 

 

三、基本配置

1、服务器端的搭建:

1)安装FluorineFx,安装完后在目录中会有“Source”及“Samples”两个文件夹,“Samples”文件夹中包含了一些在VS.Net环境中使用Fluorine的例子。“Source”文件夹中包含了有关Fluorine的源代码。(代码未具体去研究)

2)安装好Fluorine之后,系统自动在VS.Net 2008新建网站中增加一个模板:FluorineFx ASP.NET Web Application。选择该模板,创建一个.NET网站

 

                                                                               图3.1

 

a)打开Visual Studio 2008,分别选择 文件 -> 新建 -> 网站
    b)
选择已安装模板“FluorineFx ASP.NET Web Application”

c)运行项目,获取.NET自带服务器生成的端口,及网址,本项目中是 http://localhost:4166/FluorineTest/

3)利用VS的模板进行创建后,系统会自动加载一些引用,以及创建相关文件,并进行简单配置。创建完后的项目结构如图所示:

 

3.2

Bin”中的Dll就是用Fluorine的源文件所生成的程序集,“Templates”是一些模板。“WEB-INF/flex”中包含了XML都是些配置文件。“Gateway.aspx”是个空页面,其网页地址就是Fluorine的网关地址。

2、客户端的配置:

   客户端的配置有三种方法,一种是通过向导来设置参数,从而创建Flex;另一种是通过指定services-config.xml配置文件来设置;第三种是利用第三方组件RemoteObjectAMF0来连接,这种方式就不用再去配置services-config.xml。(推荐用第三种方法)

  1)向导设置方法:

步骤1. 新建Flex工程。选择ColdFusion Flash Remoting。如图3.3

步骤2. 配置服务器。Deployed to J2EE server。如图3.4

2services-config.xml配置文件来设置

 修改工程的属性,如图3.5

修改“Additional compiler arguments”,设置services-config.xml配置文件的路径,可以指向刚才建立的VS.Net项目中的“WEB-INF/flex”中的services-config.xml路径。也可以将services-config.xml这个文件拷贝到调用文件的同级目录中,然后如上面所设。

 3)利用第三方组件RemoteObjectAMF0来连接,这种方法讲到时再进行介绍。

 

四、通信过程

1、在VS.Net中编写数据处理类HelloWorld.cs文件(可以新建一个FluorineFx ServiceLibrary类库文件,将所有的数据处理类放到库中上,然后在网站中调用此类库,这里就不创建了)。HelloWorld.cs文件的代码如下所示:

using System;

using System.Data;

using System.Configuration;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using FluorineFx;

 

namespace FluorineHelloWorld

{

    /// <summary>

    ///HelloWorld 的摘要说明

    /// </summary>

    [RemotingService()]

    public class HelloWorld

    {

        public HelloWorld()

        {

            //

            //TODO: 在此处添加构造函数逻辑

            //

        }

        public string FromFluorine(string userName)

        {

            return "您好," + userName + "!此消息来自Fluorine Flash Remoting";

        }

    }

}

 

RemotingService属性并不是必需的,不过使用该属性,在配置了服务浏览器的Web应用上可以通过Console.aspx查看远程服务类文件,以及调用该服务的ActionScrip。例如可以在上页类文件中设置断点,然后将Console.aspx设置为起始页,启动项目。页面会跳转到Fluorine.aspx页面,当调用FromFluorine()函数时,就会中断。下图是对函数所进行的调用结果。

4.1

2、配置Flex工程中的services-config.xml。主要是设置这个endpoint属性。让其指向之前得到的网关地址,另外就是设置了“destination”。

<?xml version="1.0" encoding="UTF-8"?>

<services-config>

    <services>

        <service id="remoting-service"

                 class="flex.messaging.services.RemotingService"

                 messageTypes="flex.messaging.messages.RemotingMessage">

            <destination id="fluorine">

                <channels>

                    <channel ref="my-amf"/>

                </channels>

                <properties>

                    <source>*</source>

                </properties>

            </destination>

        </service>

    </services>

    <channels>

        <channel-definition id="my-amf" class="mx.messaging.channels.AMFChannel">

            <endpoint uri="http://localhost:4166/FluorineTest/Gateway.aspx"

              class="flex.messaging.endpoints.AMFEndpoint"/>

        </channel-definition>

    </channels>

</services-config>

 

3、如下创建一个MXML文件。

<?xml version="1.0" encoding="utf-8"?>

<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute">

    <mx:Script>

        <![CDATA[

            import mx.rpc.events.FaultEvent;

            import mx.rpc.events.ResultEvent;

            import mx.controls.Alert;

       

        public function clickBtnHelloWorld():void{

             sampleRemoteObject.FromFluorine(this.txtHelloWorld.text);

        }

            public function RemoteResult(re:ResultEvent):void

            {

                var str:String = re.result as String;

                Alert.show(str); 

            }

       

            public function RemoteFault(re:FaultEvent):void

            {

                Alert.show("Message:" + re.fault.faultString,"出错");

            }          

        ]]>

    </mx:Script>

 

    <!–这里Source 对应.NET类,前面是命名空间,后面是类名 source = 命名空间.类名–>

    <mx:RemoteObject

        id="sampleRemoteObject"

        destination="fluorine"

        source="FluorineHelloWorld.HelloWorld"

        showBusyCursor="true">

       

        <!–这里是.NET中的方法,name = 方法名 –>

        <mx:method name="FromFluorine" result="RemoteResult(event)" fault="RemoteFault(event)"/>       

    </mx:RemoteObject>

    <mx:Panel horizontalAlign="center" verticalAlign="middle" width="250" height="200" layout="absolute">

        <mx:TextInput x="35" y="10" id="txtHelloWorld" />

        <mx:Button x="82.5" y="40" label="调用" id="btnHelloWorld" click="clickBtnHelloWorld()"/>

    </mx:Panel>

</mx:Application>

 

这里创建了一个RemoteObject对象,并设置了其id属性,“destination”指向services-config.xml中的“destination”的idsource对应VS.Net类,前面FluorineHelloWorld是命名空间,后面HelloWorld是类名。“showBusyCursor”是指在交互时鼠标的状态是否为设置为繁忙。

RemoteObject中创建了一个method方法,“name”属性跟所要调用的VS.Net类中的函数名相同,“result”设置返回结果后的处理事件,“fault”设置交互过程中出错后的处理事件

4、运行Flex,结果如下:

4.2

4.3

 

五、使用RemoteObjectAMF0来连接fluorine网关

1、上面连接网关是利用了Flex自带的RemoteObject组件来实现,利用这个组件来实现的话,需要在创建项目时对项目进行配置,或者利用配置文档进行配置,这些在上面已经做了详细的介绍。现在介绍的是利用RemoteObjectAMF0组件来实现。这个组件是一种基于MXML的第三方组件,用于连接AMF网关,同时它是一个开源的组件。

2、下载RemoteObjectAMF0后解压,在“src”文件夹中就可以看到关于该组件的源代码,它基本上是对flex中的RemoteObject组件进行的重写。可以将“src”文件夹中的“com”文件夹全部拷贝到flex的工程中,也可以将其编译成库文件再引用到Flex工程中。

3、这时将“com”文件夹拷贝到了工程中。要使用该组件,默认情况下,要在MXML文件中的“Applications”标签中加入命名空间“xmlns:renaun="com.renaun.rpc.*"”。

4RomoteObjectAMF0组件的定义语法如下所示:

<renaun:RemoteObjectAMF0 endpoint="http://localhost:4166/FluorineTest/Gateway.aspx" id="sampleRemoteObject" source="FluorineHelloWorld.HelloWorld" showBusyCursor="true">

    <renaun:methods>

       <renaun:method name="FromFluorine" result="RemoteResult(event)" fault="RemoteFault(event)"/>

    </renaun:methods>

</renaun:RemoteObjectAMF0>

 

RemoteObjectAMF0组件的“endpoint”属性指明AMF网关地址,“source”属性指明类的名称空间,<名称空间:method>组件的name属性指向类中的方法,必须与类中的定义相同,result事件处理返回的数据。

5RemoteObjectAMF0的调用方法跟上面讲RemoteObject时差不多,比如都可以通过sampleRemoteObject.FromFluorine(this.txtHelloWorld.text);去调用.NET中的FromFluorine()方法。

[MVC]Asp.NetMvc无刷新上传

mikel阅读(824)

    先要说明一下,这篇文章有点“事发突然”和“滥竽充数”:)
    因为在老赵的不妨来做个尝试:UpdatePanel for ASP.NET MVC 正好谈到使用JQuery的ajax功能实现文件上传的问题,临时做起这个“简陋”的demo,本来是不打算把这个作为本系列的一部分的,不过既然要发一个文件上传的Demo上来,就暂且也把它算在MVC的一个“工具”,此谓“滥竽充数”。
    闲话少叙,因为老赵急着要看东西,先发上来,里面必要的地方已经做了写简要的说明,如有疑惑和建议希望大家提出来,我们一起探讨。
    ajax无刷新上传实例下载:http://files.cnblogs.com/szw/MVCTools_upload.rar

    PS:既然作为本系列的一部分,我把这个Demo做在了MVC项目中(WebForms项目中也一样可用),打开首页中的“文件上传”即可操作,上传文件默认保存在~/UploadFiles/文件夹中。

http://szw.cnblogs.com/
研究、探讨ASP.NET
转载请注明出处和作者,谢谢!

[JQuery]JQuery异步提交Form

mikel阅读(917)

最近研究JQuery,今天搞清楚了ajax要怎么实现,使用方法意外的简单。有兴趣的可以看我上次提到的手册,我这里演示一个简单的保存表单的例子。
提交表单的方法:
$.post(’JQuery.php?request=ajax’,$.getForms(’form1′),function (msg) {
alert(msg)
});
仅使用这么一句话就可以实现表单数据的静态提交了。 第一个参数是服务端的URL,第二个参数是表单的POST数据,第三个参数是执行成功后调用的方法.
$.getForms这个方法是自定义的,就是把表单中所有输入框值变成一个GET参数字符串形式.这个方法是我从xajax中 参考修改来的,本来JQuery.com上也有这样的插件但是当有name=aa[]这种形式的input时会出错,只能自己弄一个了。方法在 Forms.js文件中,这个文件中还有个$F函数从jQuery.com上得到的,是用jQuery实现了prototype.js中的同样功能,就是 取表单元素的值。
服务端就没什么特别的:
if ($_GET[’request’]==’ajax’) {
var_export($_POST);exit;
}
我们输出提交的信息作为测试,自己的应用自己处理就是了。
ajax始终用utf8编码传输的所以,如果你的项目不是utf8必须进行编码转换:
if ($_GET[’request’]==’ajax’) {
$_POST = charsetIconv($_POST);
}
function charsetIconv($vars) {
if (is_array($vars)) {
$result = array();
foreach ($vars as $key => $value) {
$result[$key] = charsetIconv($value);
}
} else {
$result = iconv(’utf-8′,’gbk’, $vars);
}
return $result;
}
这里是我在服务端编码的处理方式。
原来都在使用xajax现在准备完成使用 jQuery来替代,不仅有非常的JS扩展功能使用也很灵活。
DEMO地址  DEMO下载

[JQuery]JQuerey的ThickBox插件

mikel阅读(801)

ThickBox 是基于 JQueryJavaScript 编写的网页UI对话窗口小部件. 它可以用来展示单一图片, 若干图片, 内嵌的内容, iframed的内容, 或以 AJAX 的混合 modal 提供的内容.
查看实例演示
特性:

  • ThickBox 是用超轻量级的 JQuery 库 编写的. 压缩过 jQuery 库只15k, 未压缩过的有39k.
  • ThickBox 的 JavaScript 代码CSS 文件只占12k. 所以压缩过的 jQuery 代码和 ThickBox 总共只有27k.
  • ThickBox 能重新调整大于浏览器窗口的图片.
  • ThickBox 的多功能性包括(图片,iframed 的内容,内嵌的内容,AJAX 的内容).
    • 展示单一图片(single image)
    • 展示图片集(multiple images)
    • 展示内嵌内容(inline content)
    • 展示被iFrame的内容(iframed content)
    • 展示AJAX内容(AJAX content)
    • 其他:教程本身还自带了一个很酷的JS跳转脚本
  • ThickBox 能隐藏 Windows IE 6 里的元素.
  • ThickBox 能在使用者滚动页面或改变浏览器窗口大小的同时始终保持居中. 点击图片, 覆盖层, 或关闭链接能移除 ThickBox.
  • ThickBox 的创作者决定动画应该因人而异, 所以 ThickBox 不再使用动画了. 这是特性吗? 哦, 有人说是呀.

如何实现 ThickBox :
1. ThickBox 要求使用 jQuery JavaScript 库; 正因如此, 你需要外调 jquery.js 文件在你的网页的 head 元素内, 接着还要外调 thickbox.js 文件 (注意: jquery.js 必须放在调用资源的第一位). 例子如下:
<script type="text/javascript" src="path-to-file/jquery.js"></script> <script type="text/javascript" src="path-to-file/thickbox.js"></script>
一旦你外调了 .js 文件, 打开 thickbox.js 并寻找加载图片的名字 (loadingAnimation.gif). 找到后, 根据它在你服务器上的位置确定更改它的路径.
2. 在你的网页中外调 ThickBox CSS 文件. 例子如下:
<link rel="stylesheet" href="path-to-file/thickbox.css" type="text/css" media="screen" />

<style type="text/css" media="all">@import "path-to-file/thickbox.css";</style>
或, 打开 thickbox.css 文件并复制粘贴样式到你现有的样式表中.
3. 观看例子, 学习使用不同的方法调用 ThickBox 的功能.
支持的和经测试过的浏览器:
Windows IE 6.0, Windows FF 1.5.0.5, Windows Opera 9.0, Macintosh Safari 1.3.2 &amp; 2.0.3, Macintosh FF 1.5
MIT 许可
http://www.opensource.org/licenses/mit-license.php
许可特此批出, 免费, 给任何人提供此软件的拷贝和他相关文档中的("软件"), 使用此软件不受任何限制, 所不受的限制包括: 有权利使用, 拷贝, 修改, 合并, 出版, 分发, 颁发从属许可, 和/或买卖该软件的拷贝.
打包下载代码及教程

[JQuery]JQuery的FckEditor插件

mikel阅读(798)

What does it do?

 
 

Try it yourself

Conventional Submission (iFRAME)

This type of submission always works without the plugin.

 

Ajax Submission (DIV)

This type of submission would not work without this plugin.

(Ajax Form submission powered by the jQuery Form Plugin)

 
 

Download

All you really need is FKCEditor (DUH!), jQuery (of course) and the jQuery FCKEditor Plugin.

But if you want to submit your form via Ajax, then you need to get the jQuery Form Plugin by Malsup.

 
 

Usage

  • Method 1: replacing ALL textareas in a page with THE SAME settings

    <textarea name="fck1" cols="50" rows="6"></textarea>
    <textarea name="fck2" cols="50" rows="6"></textarea>
    <textarea name="fck3" cols="50" rows="6"></textarea>
    <script> $(function(){ $('textarea').fck({path: '/path/to/fck/directory/'}); }); </script>
    
  • Method 2: replacing SOME textareas in a page with THE SAME settings
    In this example, only textarea fck3 will not be converted into a FCKEditor.

    <textarea name="fck1" class="fck" cols="50" rows="6"></textarea>
    <textarea name="fck2" class="fck" cols="50" rows="6"></textarea>
    <textarea name="fck3" cols="50" rows="6"></textarea>
    <script> $(function(){ $('textarea.fck').fck({path: '/path/to/fck/directory/'}); }); </script>
    
  • Method 3: replacing SOME textareas in a page with DIFFERENT SETTINGS (see demo)

    <textarea name="fck1" cols="50" rows="6"></textarea>
    <textarea name="fck2" cols="50" rows="6"></textarea>
    <textarea name="fck3" cols="50" rows="6"></textarea>
    <script>
    $(function(){
    $.fck.config = {path: '/path/to/fck/directory/', height:300 };
    $('textarea#fck1').fck(/* default settings */);
    $('textarea#fck2').fck({ toolbar:'MyCustomerToolbar' });
    $('textarea#fck3').fck({ toolbar:'MyCustomerToolbar', height:200 });
    });
    </script>
    
 
 

Important pointers…

  • This is a working idea that hasn't yet been fully tested.
    Tested and works on Firefox 2, Opera, Safari (Win), IE7 and IE6 (all in WinXP SP2).
  • The same principle can be applied to TinyMCE, Codepress and any other rich-text editors.
    Any input regarding other rich-text editors is welcome.
  • The plugin will intercept known methods and install itself against related plugins (currently only the jQuery Form Plugin).
    Any input regarding integrating this plugin with other JQuery plugins is welcome.

[MVC]使用Forms Authentication实现用户注册、登录 (三)用户实体替换

mikel阅读(932)

IPrincipalIIdentity

  通过查阅文档,我们可以看到HttpContext.User属性的类型是IPrincipal接口。然而我们知道,接口通常是不能直接访问的,其背后必定隐藏了一个实现了该接口的对象。那么这个实际对象的类型是什么呢?

  让我们在前面示例的MasterPagePage_Init方法上加一个断点,再次运行程序,可以得到HttpContext.User属性的真正类型是System.Security.Principal.GenericPrincipal

  查看IPrincipal接口的定义,可以看到它只有一个公开属性——Identity,其类型是这里要提到的另外一个重要接口IIdentity。通过上面的断点跟踪,我们还能知道对于GenericPrincipal而言,其Identity属性的实际类型是GenericIdentity,也是位于System.Security.Principal命名空间中。

  由此,我们引出了.NET Framework中关于Principal(实体)的整个类型系统。所有这些类型都位于mscorlib.dll程序集中,由此也可以看出,这套模型隶属于整个系统的基石。

 

实现自己的IPrincipal

  要想用自己的实体对象替换HttpContext.User,就必须让自己的实体对象实现IPrincipal接口;通常还必须伴随着实现IIdentity接口。

  目前系统中有的是一个数据实体对象。一般而言,实现IPrincipal接口有一下两种方式——

l  编写单独的类型实现IPrincipal接口,并在其中包含数据实体对象;

l  修改数据实体对象使其实现IPrincipal接口。

  对于这两种方式而言,其Identity属性可以通过以下三种方式实现——

l  使用.NET Framework提供的GenericIdentity

l  创建自定义的类,实现Identity接口;

l  修改数据实体对象或自定义的实体类,让它们同时实现IPrincipalIIdentity接口。

  对于简单的应用程序而言,通常可以修改数据实体对象,使其同时实现IPrincipalIIdentity接口。而就复杂的分层架构应用程序,则建议在逻辑层创建分别实现了IPrincipalIIdentity接口的对象。本文的示例      明显属于前一种情况,因此我们考虑修改作为数据实体类的UserObject类,让其实现两个接口。以下是修改完毕的UserObject类:

 

public class UserObject : IPrincipal, IIdentity

{

     /// <summary>

     /// 用户名。

     /// </summary>

     public string Name;

 

     /// <summary>

     /// 密码散列值。

     /// </summary>

     public string PasswordHash;

 

     /// <summary>

     /// 密码salt值。

     /// </summary>

     public string PasswordSalt;

 

     #region IIdentity Members

 

     public string AuthenticationType

     {

         get

         {

              return "Froms";

         }

     }

 

     public bool IsAuthenticated

     {

         get

         {

              return true;

         }

     }

 

     string IIdentity.Name

     {

         get

         {

              return this.Name;

         }

     }

 

     #endregion

 

     #region IPrincipal Members

 

     public IIdentity Identity

     {

         get

         {

              return this;

         }

     }

 

     public bool IsInRole(string role)

     {

         return false;

     }

 

     #endregion

}

 

  首先我们来看一下对IIdentity接口的实现。该接口要求三个属性——AuthenticationTypeIsAuthenticatedNameAuthenticationType表示该用户标识所使用的验证类型,这里返回的是“Forms”;IsAuthenticated属性表示当前用户是否已经通过验证(即是否已登录。在这个例子里,我们只针对已登录用户进行实体替换,所以这个属性总是返回true。通常,实际的Web应用程序编写时还有一种习惯,就是为未登录用户(称之为匿名用户)也提供一个用户实体对象,此时就需要为IsAuthenticated提供逻辑,判断用户是否已通过验证了。最后IIdentity接口还要求对象提供一个Name属性,在这里,由于已经存在了Name字段,因此才用“显示接口实现”来提供Name属性,返回对象自身的Name字段即可。

  接下来我们看一下IPrincipal接口的实现。该接口要求提供一个Identity属性和一个IsInRole方法。由于UserObject类本身已经实现了IIdentity接口,因此在Identity属性中直接reutren this即可。因为我们这个示例不涉及用户分组(角色)方面的技术,因此IsInRole方法总是返回false

 

用户实体替换

  用户实体替换即使用我们自己编写的类型的实例来替换HttpContext.User属性。实体替换应该发生在HttpApplicationPostAuthenticateRequest事件发生时,因为此时ASP.NET已经从客户端得到了用户凭证Cookie并进行了解密和校验。

  我们既可以编写一个HttpModule来处理PostAuthenticateRequest事件,也可以在Global..asax文件中添加时间处理器。这里为了简单,我们选择在Global.asax中添加如下事件处理器:

 

void Application_PostAuthenticateRequest(object sender, EventArgs e)

{

     HttpApplication app = (HttpApplication)sender;

     if(app.Context.User.Identity.Name != "")  // 仅在已登录时替换

     {

         UserObject user = DataAccess.GetUserByName(app.Context.User.Identity.Name);

         app.Context.User = user;

         Thread.CurrentPrincipal = user;

     }

}

 

  在这里我们首先进行了判断,如果用户已登录,才进行实体替换。当然你也可以选择未未登录用户也提供一个匿名用户实体。

  接下来,我们通过本来已经存放在HttpContext.User.Identity中的用户标识得到了数据实体对象,然后分别将其赋予HttpContext.UserThread.CurrentPrincipal

  至此,我们的示例代码就完工了。没有提到的是,完成了这一步之后,你就可以通过类似下面的代码在任何可以访问到HttpContext的地方获取用户实体了:

 

UserObject user = HttpContext.Current.User as UserObject;

if(user != null)

{

       // 可以使用user

}

else

{

       // 用户未登录

}

 

  需要注意,由于在这里我们仅对已登录用户进行了用户实体替换,所以代码使用as进行类型转换并结合if语句进行判断是必需的。

 

小结

  好吧,这一部分说的是用户实体替换。

[MVC]ASP.NET MVC Preview 4 分析 - 2. Filter

mikel阅读(840)

过滤器 (Filter) 是 MVC 的一个重要特征,它提供了非常灵活的扩展和解耦机制。P4 版的过滤器总算像那么回事了,同时做了更深度的划分,使得开发人员可以控制更多的细节和流程。
1. IActionFilter
主要用来干预 Action 的执行,我们可以通过上下文对象修改请求参数或者取消 Action 的执行。

public interface IActionFilter
{
  void OnActionExecuting(ActionExecutingContext filterContext);
  void OnActionExecuted(ActionExecutedContext filterContext);
}

默认实现是 ActionFilterAttribute,这也是我们开发自定义过滤器通常所用的基类。

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
  public virtual void OnActionExecuting(ActionExecutingContext filterContext)
  {
  }
  public virtual void OnActionExecuted(ActionExecutedContext filterContext)
  {
  }
  // …
}

ActionExecutingContext 有个很重要的属性 Cancel,通过它我们可以取消 Action 和后续 Filter 的执行。

public class ActionExecutingContext : ControllerContext
{
  // Methods
  public ActionExecutingContext(ControllerContext controllerContext, MethodInfo actionMethod,
    IDictionary<string, object> actionParameters);
  // Properties
  public MethodInfo ActionMethod { get; private set; }
  public IDictionary<string, object> ActionParameters { get; private set; }
  public bool Cancel { get; set; }
  public ActionResult Result { get; set; }
}
public class ActionExecutedContext : ControllerContext
{
  // Methods
  public ActionExecutedContext(ControllerContext controllerContext, MethodInfo actionMethod,
    bool canceled, Exception exception);
  // Properties
  public MethodInfo ActionMethod { get; private set; }
  public bool Canceled { get; private set; }
  public Exception Exception { get; private set; }
  public bool ExceptionHandled { get; set; }
  public ActionResult Result { get; set; }
}

举例说明一下。

public class TestController : Controller
{
  [Filter1(Order = 1)]
  [Filter2(Order = 2)]
  [Filter3(Order = 3)]
  public ActionResult Index()
  {
  }
}

当我们在 Filter2.OnActionExecuting 中执行取消操作时,那么实际输出效果应该就是下面这样子。

class Filter2 : Filter1
{
  public override void OnActionExecuting(ActionExecutingContext filterContext)
  {
    filterContext.Cancel = true;
  }
}

输出:
TestController.OnActionExecuting
Filter1.OnActionExecuting
Filter2.OnActionExecuting
Filter1.OnActionExecuted
TestController.OnActionExecuted
我 们发现 Action 和排在后面的 Filter3 没有被调用,同时 Filter2 的 OnActionExecuted 也没有被执行。由于 Filter.Order 最小值是 -1,而 Controller.Order = -1,因此默认情况下 Controller Filter 总是被调用执行。
2. IResultFilter
可以利用该类型过滤器修改输出结果,诸如视图引擎和输出数据等等。

public interface IResultFilter
{
  void OnResultExecuting(ResultExecutingContext filterContext);
  void OnResultExecuted(ResultExecutedContext filterContext);
}

其默认实现同样是 ActionFilterAttribute。

public abstract class ActionFilterAttribute : FilterAttribute, IActionFilter, IResultFilter
{
  // …
  public virtual void OnResultExecuting(ResultExecutingContext filterContext)
  {
  }
  public virtual void OnResultExecuted(ResultExecutedContext filterContext)
  {
  }
}

在 ResultExecutingContext 中也有个 Cancel 属性,通过它我们可以阻止 View 输出和后续 Filter 执行。

public class ResultExecutingContext : ControllerContext
{
  // Methods
  public ResultExecutingContext(ControllerContext controllerContext, ActionResult result);
  // Properties
  public bool Cancel { get; set; }
  public ActionResult Result { get; set; }
}
public class ResultExecutedContext : ControllerContext
{
  // Methods
  public ResultExecutedContext(ControllerContext controllerContext, ActionResult result,
    bool canceled, Exception exception);
  // Properties
  public bool Canceled { get; private set; }
  public Exception Exception { get; private set; }
  public bool ExceptionHandled { get; set; }
  public ActionResult Result { get; private set; }
}

同样在上文例子中的 Filter2.OnResultExecuting 中设置取消操作。

class Filter2 : Filter1
{
  public override void OnResultExecuting(ResultExecutingContext filterContext)
  {
    filterContext.Cancel = true;
  }
}

输出:
TestController.OnResultExecuting
Filter1.OnResultExecuting
Filter2.OnResultExecuting
Filter1.OnResultExecuted
TestController.OnResultExecuted
Action 返回的 View(ActionResult) 以及 Filter3、Filter2.OnResultExecuted 都没有被执行。
3. IAuthorizationFilter
这是新增的过滤器类型,它拥有最先执行的特权,用来实现登录验证操作。

public interface IAuthorizationFilter
{
  void OnAuthorization(AuthorizationContext filterContext);
}

默认实现是 AuthorizeAttribute。

public sealed class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
  // Methods
  public AuthorizeAttribute();
  public void OnAuthorization(AuthorizationContext filterContext);
  // Properties
  public string Roles { get; set; }
  public string Users { get; set; }
}

AuthorizeAttribute 通过对 HttpContext.User 进行一系列的判断操作,然后输出一个新增的 ActionResult —— HttpUnauthorizedResult,这算是其中最有价值的代码了。

public class HttpUnauthorizedResult : ActionResult
{
  public override void ExecuteResult(ControllerContext context)
  {
    // …
    // 401 is the HTTP status code for unauthorized access – setting this
    // will cause the active authentication module to execute its default
    // unauthorized handler
    context.HttpContext.Response.StatusCode = 401;
  }
}

上下文对象中也有个 Cancel,通过它可以告诉 ActionInvoker 停止后面的调用操作,跳转到登录页。

public class AuthorizationContext : ControllerContext
{
  // Methods
  public AuthorizationContext(ControllerContext controllerContext, MethodInfo actionMethod);
  // Properties
  public MethodInfo ActionMethod { get; private set; }
  public bool Cancel { get; set; }
  public ActionResult Result { get; set; }
}

详情可参考下面这些代码。

public sealed class AuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
  public void OnAuthorization(AuthorizationContext filterContext)
  {
    // …
    IPrincipal user = filterContext.HttpContext.User;
    if (!user.Identity.IsAuthenticated)
    {
      filterContext.Cancel = true;
      filterContext.Result = new HttpUnauthorizedResult();
      return;
    }
    if (!String.IsNullOrEmpty(Users))
    {
      IEnumerable<string> validNames = SplitString(Users);
      bool wasMatch = validNames.Any(name => String.Equals(name, user.Identity.Name,
        StringComparison.OrdinalIgnoreCase));
      if (!wasMatch)
      {
        filterContext.Cancel = true;
        filterContext.Result = new HttpUnauthorizedResult();
        return;
      }
    }
    if (!String.IsNullOrEmpty(Roles))
    {
      IEnumerable<string> validRoles = SplitString(Roles);
      bool wasMatch = validRoles.Any(role => user.IsInRole(role));
      if (!wasMatch)
      {
        filterContext.Cancel = true;
        filterContext.Result = new HttpUnauthorizedResult();
      }
    }
  }
}
public class ControllerActionInvoker
{
  public virtual bool InvokeAction(string actionName, IDictionary<string, object> values)
  {
    // …
    AuthorizationContext authContext = InvokeAuthorizationFilters(methodInfo,
      filterInfo.AuthorizationFilters);
    if (authContext.Cancel)
    {
      // not authorized, so don't execute the action method or its filters
      InvokeActionResult(authContext.Result ?? EmptyResult.Instance);
    }
    // …
  }
  protected virtual AuthorizationContext InvokeAuthorizationFilters(…)
  {
    // …
    AuthorizationContext context = new AuthorizationContext(ControllerContext, methodInfo);
    foreach (IAuthorizationFilter filter in filters)
    {
      filter.OnAuthorization(context);
      // short-circuit evaluation
      if (context.Cancel)
      {
        break;
      }
    }
    return context;
  }
}

ControllerActionInvoker 通过 InvokeAuthorizationFilters() 调用 AuthorizeAttribute,然后依次判断登录和角色信息。如果条件不符,则设置取消操作并返回一个 HttpUnauthorizedResult,这个 ActionResult 被 InvokeAciton 所激活,因此才有了 "context.HttpContext.Response.StatusCode = 401" 跳转。
4. IExceptionFilter
用于捕获 Filter 和 Action 执行异常,以便实现自定义错误页面。

public interface IExceptionFilter
{
  void OnException(ExceptionContext filterContext);
}

默认实现是 HandleErrorAttribute。

public sealed class HandleErrorAttribute : FilterAttribute, IExceptionFilter
{
  // Methods
  public HandleErrorAttribute();
  void OnException(ExceptionContext filterContext);
  // Properties
  public Type ExceptionType { get; set; }
  public string View { get; set; }
}

从上下文中我们可以获取具体的异常信息,可以使用 ExceptionHandled 来阻止后续 HandleErrorAttribute 执行,还可以设置一个 ActionResult 来显示错误页面。

public class ExceptionContext : ControllerContext
{
  // Methods
  public ExceptionContext(ControllerContext controllerContext, Exception exception);
  // Properties
  public Exception Exception { get; private set; }
  public bool ExceptionHandled { get; set; }
  public ActionResult Result { get; set; }
}
public sealed class HandleErrorAttribute : FilterAttribute, IExceptionFilter
{
  public void OnException(ExceptionContext filterContext)
  {
    // …
    if (controller == null || filterContext.ExceptionHandled)
    {
      return;
    }
    // …
    HandleErrorInfo model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
    filterContext.Result = new ViewResult()
    {
      TempData = controller.TempData,
      ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
      ViewEngine = controller.ViewEngine,
      ViewName = View,
    };
    filterContext.ExceptionHandled = true;
    filterContext.HttpContext.Response.Clear();
    filterContext.HttpContext.Response.StatusCode = 500;
  }
}

ControllerActionInvoker 使用 try…catch 来捕获执行异常,并通过 InvokeExceptionFilters 完成 OnException 调用。

public class ControllerActionInvoker
{
  public virtual bool InvokeAction(string actionName, IDictionary<string, object> values)
  {
    // …
    try
    {
      // …
    }
    catch (Exception ex)
    {
      // something blew up, so execute the exception filters
      ExceptionContext exceptionContext = InvokeExceptionFilters(ex, filterInfo.ExceptionFilters);
      if (!exceptionContext.ExceptionHandled)
      {
        throw;
      }
      InvokeActionResult(exceptionContext.Result);
    }
    // …
  }
  protected virtual ExceptionContext InvokeExceptionFilters(exception, filters)
  {
    // …
    ExceptionContext context = new ExceptionContext(ControllerContext, exception);
    foreach (IExceptionFilter filter in filters)
    {
      filter.OnException(context);
    }
    return context;
  }
}

附: Controller 实现了上述所有的过滤器类型。

public abstract class Controller :
  IActionFilter,
  IAuthorizationFilter,
  IController,
  IDisposable,
  IExceptionFilter,
  IResultFilter
{
}

—————–
本文仅分析一些调用细节,有关使用方法可参考 《ASP.NET MVC Preview 4 Release (Part 1) 》 (中文版)。

[MVC]Asp.net Mvc Framework 七 (Filter及其执行顺序)

mikel阅读(790)

应用于Action的Filter
ASP.NETMvc中当你有以下及类似以下需求时你可以使用Filter功能
判断登录与否或用户权限,决策输出缓存,防盗链,防蜘蛛,本地化设置,实现动态Action
filter是一种声明式编程方式,在ASP.NET MVC中它只能应用在Action上
Filter要继承于ActionFilterAttribute抽象类,并可以覆写void OnActionExecuting(FilterExecutingContext)和
void OnActionExecuted(FilterExecutedContext)这两个方法
OnActionExecuting是Action执行前的操作,OnActionExecuted则是Action执行后的操作
下面我给大家一个示例,来看看它的的执行顺序
首先我们先建立 一个Filter,名字叫做TestFilter

using System.Web.Mvc;

namespace MvcApplication2.Controllers
{
    
public class TestFilter : ActionFilterAttribute
    
{
        
public override void OnActionExecuting(FilterExecutingContext
           filterContext) 
{
            filterContext.HttpContext.Session[
"temp"+= "OnActionExecuting<br/>";
        }


        
public override void OnActionExecuted(FilterExecutedContext
            filterContext) 
{
            filterContext.HttpContext.Session[
"temp"+= "OnActionExecuted<br/>";
        }

    }

}

在这里我们在Session["temp"]上标记执行的顺序
我们在Controller中的Action中写以下代码

        [TestFilter]
        
public void Index() {
this.HttpContext.Session["temp"+= "Action<br/>";
            RenderView(
"Index");
        }

在这个Action执行的时候,我们也为Session["temp"]打上了标记.
最后是View的内容
很简单我们只写

<%=Session["temp"%>

这样我们就可以执行这个页面了
在第一次执行完成后,页面显示

OnActionExecuting
Action

这证明是先执行了OnActionExecuting然后执行了Action,我们再刷新一下页面
则得到

OnActionExecuting
Action
OnActionExecuted
OnActionExecuting
Action

这是因为OnActionExecuted是在第一次页面 显示后才执行,所以要到第二次访问页面时才能看到
Controller的Filter
Monorail中的Filter是可以使用在Controller中的,这给编程者带来了很多方便,那么在ASP.NET MVC中可不可以使用Controller级的Filter呢.不言自喻.
实现方法如下Controller本身也有OnActionExecuting与OnActionExecuted方法 ,将之重写即可,见代码

namespace MvcApplication2.Controllers
{
    
using System.Web.Mvc;
    
public class EiceController : Controller
    
{
        
public void Index() {        this.HttpContext.Session["temp"+= "Action<br/>";

            RenderView(
"Index");
        }

        
public void Index2() {
            
            RenderView(
"Index");
        }

        
protected override void OnActionExecuting(FilterExecutingContext
           filterContext) 
{
            filterContext.HttpContext.Session[
"temp"+= "OnActionExecuting<br/>";
        }


        
protected override void OnActionExecuted(FilterExecutedContext
            filterContext) 
{
            filterContext.HttpContext.Session[
"temp"+= "OnActionExecuted<br/>";
        }

    }

}

这里要注意一点,这两个方法 一定要protected
要是想多个Controller使用这个Filter怎么办?继承呗.
Filter的具体生存周期
这是官方站的一数据.

  1. 来自controller虚方法 的OnActionExecuting .

  2. 应用于当前Controller的Filter中的OnActionExecuting:

    先执行基类的,后执派生类的

  3. 执行应用于Action的Filter的OnActionExecuting顺序:
    先执行基类的,后执派生类的

  4. Action 方法

  5. 应用于Action的Filter的OnActionExecuted 的执行顺序

    先执行派生类的,后执行基类的

  6. 应用于当前Controller的Filter中的OnActionExecuted方法

    先执行派生类的,后执行基类的

  7. Controller中的虚方法 OnActionExecuted

示例可见http://quickstarts.asp.net/3-5-extensions/mvc/ActionFiltering.aspx
Asp.net Mvc Framework 系列