ASP.NET基础架构概述

留下评论

对应于IIS中的每一个虚拟目录,都会有一个应用程序域(domain)。这样,IIS就能将每个ASP.NET web
应用程序或者web service隔离开。这一点与经典的ASP不一样,ASP中的应用程序保护级别在IIS元信息中
配置,它决定了ASP应用程序是运行在IIS进程inetinfo.exe中,或者是在一个预定的Dllhost.exe实例中,
或者在一个Dllhost.exe共享实例中。

ISAPI接口提供了ASP.NET运行时与IIS之间的桥接作用,它是用非托管代码编写;
它非常精炼,仅仅提供了一种路由机制来把到达的请求传递到ASP.NET运行时。所有其他操作,甚至包括
处理请求的线程管理也在asp.net引擎和用户编写的代码中进行。
作为一种协议,ISAPI支持ISAPI扩展和ISAPI过滤器。ISAPI扩展是一个请求处理的接口,它提供处理web服务器
的输出和输出的逻辑。ASP和ASP.NET就是用ISAPI扩展来实现的,针对ASP.NET的扩展是<.NET FrameworkDir>\aspnet_isapi.dll。
我们可以通过使用aspnet_regiis.exe来注册使用特定版本的aspnet_isapi.dll来处理asp.net请求。
cd <.NET FrameworkDir>
aspnet_regiis -i
ISAPI过滤器允许我们查看进入IIS的每一个请求,
可以修改请求的内容或者改变请求处理的操作,例如请求信息的合法性验证。巧合的是,ASP.NET也提供了类似的概念:
HTTP Handler(相当于extension)和HTTP module(相对于filter)。

在IIS5中,aspnet_isapi.dll直接宿驻在进程inetinfo.exe中;另外,如果你设定网站或者虚拟目录的隔离
级别为中或者高,它会宿驻在另一个工作者进程叫aspnet_wp.exe。如果第一个ASP.NET请求到达该dll,它会
用可执行文件aspnet_wp.exe生成一个新的进程。并将请求交个这个进程去处理。这个进程接着会
装载并运行.net运行时。接下来的所以请求都将由ISAPI DLL通过命名管道被路由到该工作者进程处理。
在IIS6中,服务器进程(即inetinfo.exe)不再让第三方可执行代码(例如,ISAPI扩展)直接在其地址空间执行;
它总是会创建一个单独的工作者进程(叫w3wp.exe)-应用程序池(application pool)。ISAPI dll将在该进程中
被执行。w3wp.exe直接与内核态的驱动程序HTTP.SYS打交道。inetinfo.exe仅仅负责管理和配置服务。因此,IIS6
相比IIS5有较大的性能提升。此外,由于ISAPI DLL和.NET运行时运行在同一进程中,所以它们之间的通信也更加高效。

HTTP Module的使用:
1. 实现接口IHttpModule
2. 在web.config中增加配置节
   <configuration>
    <system.web>
        <httpModules>
        <add name="TestModule" type="WebApplication1.TestHttpModule, WebApplication1" />
        </httpModules>
    </system.web>
   </configuration>
HTTP Handler的使用:
1. 实现接口IHttpHandler(或者IHttpAsyncHandler),它只有一个方法ProcessRequest,但是WebForm和WebService都是通过Http Handler来
   实现的;
2. 在IIS中把.data文件扩展名映射到aspnet_isapi.dll;
3. 在web.config中增加配置节
   <system.web>
    <httpHandlers>
     <add verb="*" path="*.data" type="namespace.classname, assemblyname" />
    </httpHandlers>
   </system.web>

总结,ASP.NET请求如何从IIS一直到被处理并返回到客户端浏览器?
1. IIS获取请求
2. 查看文件扩展名映射至aspnet_isapi.dll
3. 进入工作者进程(IIS5中是aspnet_wp.exe,或者IIS6中是w3wp.exe)
4. .NET运行时被加载
5. IsapiRuntime.ProcessRequest()被所托管代码调用
6. 每一个请求会创建一哥IsapiWorkerRequest
7. HttpRuntime.ProcessRequest()被调用,并传入Work Request作为参数
8. 通过传入Work Request作为参数创建HttpContext对象
9. 传入HttContext,并调用HttpApplication.GetApplicationInstance()
10. HttpApplication.Init()开始流水线事件处理并hook httpModule和httphandle
11. HttpApplication.ProcessRequest()
12. 触发流水线事件处理
13. httphandler被调用
14. 控制重新返回到流水线事件处理,触发postrequest事件

ASP.NET安全验证要点
在经过验证httpmodule之后,HttpContext.User总是非空的;即便我们允许匿名访问
<authentication mode="none">,这时有一个特殊的非配置的httpmodule会对HttpContext.User
设置一个匿名的principal。所以,当我们创建自定义的验证模块时,总是需要创建IPrincipal对象
并将它赋给HttpContext.User。
form authentication --> GenericPrincipal(或者自定义类实现了接口IPrincipal)
windows authentication --> WindowsPrincipal

ASP.NET MVC中不得不知的13个扩展点

留下评论

ASP.NET MVC中不得不知的13个扩展点
1. RouteConstraint
   实现接口IRouteContraint;
2. RouteHandler
   一般在路由确定之后,我们会依赖mvc提供的MvcRouteHandler去处理http请求;
3. ControllerFactory
   默认的控制器创建工厂会去查找所有实现了IController并且类名以Controller结尾的类,
   然后用其无参构造函数初始化它。如果你需要使用依赖注入,那么你就不能用默认的工厂类了,
   你必须使用带控制反转的控制器工厂类。例如MvcContrib,或者Ninject Controller Factory。
4. ActionInvoker
   它负责通过方法名,动作名或者其他选择子属性来调用动作,接着它调用动作方法并着一些已定义的过滤,
   最后它才执行动作结果。
   如果你认为默认提供的ControllerActionInvoker消耗了太大的时间,那么你可以替换它。
5. ActionMethodSelectorAtribute
   默认实现会通过名字来选择相应的动作,但是你也可以实现自己的方法选择子。mvc框架中的AcceptVerbs就是
   一个例子。
   一个可能的应用场景是你想根据浏览器类型或者是语言设置来确定动作。
6. AuthorizationFilter
   filter会在动作之前被执行,它们会验证请求是否合法;
   自带的Authorize属性就是一个典型例子,它验证当前用户是否可以执行这个动作。还有一个例子
   是ValidateAntiForgeryToken,用于防止CSRF攻击。
7. ActionFilter
   它在动作之前和之后被执行。一个例子是OutputCache。我个人认为,它很利于视图的组建化,动作
   只需要专注于主要逻辑,视图所需要的其他数据可以通过action filter来获取。
8. ModelBinder
   默认提供的实现会通过名字直接把http参数映射到动作方法的参数上,例如我们有http参数
   user.address.city,它会找到方法参数user中名为Address的属性,然后设置这个属性的City属性的值。
9. ControllerBase
   通过Wizard创建的控制器会默认继承至ControllerBase;当然你可以定义个公共的控制器继承至它,然后其他
   所以的控制器都继承至你定义的那个公共控制器。
10. ResultFilter
    与ActionFilter相仿,在ActionResult之前和之后被执行。
11. ActionResult
    需要实现ExecuteResult方法。
12. ViewEngine
13. HtmlHelper
    我们必须保证View里面非常短小简洁,所以会通过扩展HtmlHelper来尽量让View是可测的。

Model理解篇之ModelMetaData

留下评论

在理解Model时有个很重要的概念叫ModelMetaData。顾名思义,它表示模型的元信息。
例如,我们可以通过访问它的Properties属性得到模型的公共属性。
一般我们喜欢把一个表征数据实体的类叫做模型,例如,
public class Contact {
    public string FirstName {get; set;}
    public string LastName {get; set;}
    public int Age {get; set;}
}
我们会把Contact叫做模型;但是,当我们谈到ModelMetaData时,情况有些变化。当我们
在视图里访问ViewData.ModelMetaData时,ModelMetaData能提供Contact的所有元信息;
接着我们可以通过ModelMetaData.Properties来得到Contact的三个公共属性的元信息,是
三个ModelMetaData实例!让我们再进一步,当访问FirstName对应的ModelMetaData实例时,
会得到ModelType为string,并且ContainerType为Contact。

通常,ViewData的ModelMetaData属性提供了一个该类的实例。另外,我们也可以通过
ModelMetaData的类静态方法FromStringExpression和FromLambdaExpression来
创建该类的实例。这两个方法会把字符串(例如"PropertyName")或者是一个表达式(例如
“m=>m.PropertyName")转换成相应的ModelMetaData实例。另外,这也是为什么大部分
Html Helper的扩展方法一般会至少重载两个版本的原因。
那么一个ModelMetaData实例中究竟存储了哪些信息呢?
1. Model和ModelType
   模型的值及其类型;其中,值可以为null。
2. ContainerType和PropertyName
   模型所在容器对象的类型以及模型的值是来自于容器对象的哪个属性。并不是所有的模型
   都来自于属性值,所以这些成员可以为null。
3. Properties
   模型的所有公共属性。
另外我们还可以从ModelMetaData获取关于模型的其它信息:
1. ConvertEmptyStringToNull
   标志用于指示postback回来的空字符串是否需要转换成null;
   缺省值为true;
2. DataTypeName
   一些常见的DataType例如EmailAddress, Html, Password, Url;
   缺省值为null;
3. Description
   缺省值为null;
4. DisplayFormatString
   在模板里显示模型值时用到;
   缺省值为null;
5. DisplayName
   主要用于Html.Label/LabelFor来生成UI上的提示信息。
   缺省值为null;
6. EditFormatString
   在模板里编辑模型值时用到;
   缺省值为null;
7. HideSurroundingHtml
   标志位;通常用于生成hidden input;
   缺省值为null;
8. IsComplexType
   不能在代码中设置该值;
9. IsNullableValueType
   不能在代码中设置该值;
10. IsReadOnly
11. IsRequired
12. NullDisplayText
    当模型值为null时显示的文本;
    缺省值为null;
13. ShortDisplayName
    用于表格式list view的标题;如果为null,就使用DisplayName;
14. ShowForDisplay
    标志位表针在display模式时是否显示;
    缺省值为true:
15. ShowForEdit
    标志位表针在Edit模式时是否显示;
    缺省值为true:
16. SimpleDisplayText
    指示一个复杂对象的概要
17. TemplateHint
    hint影响应该对该模型应用哪个模板;
    缺省值为null;
18. Watermark
    在文本框中编辑该模型时作为水印显示的文本;
    缺省值为null;
还有两个Helper方法:
1. GetDisplayName() 优先顺序 DisplayName ?? PropertyName ?? ModelType.Name;
2. GetValidators() 可以运行server端验证,或者是生成client端的验证规则;
那么,ModelMetaData的值从哪儿来的呢?
默认情况下,来自于System.ComponentModel和System.ComponentModel.DataAnnotations命名空间下的属性类;
但是在asp.net mvc 2中,其提供者是pluggable的。
当使用默认的DataAnnotations model metadata provider时,如下属性类会影响模型的元信息:
1. HiddenInput (System.Web.Mvc)
2. UIHint (System.ComponentModel.DataAnnotations)
3. DataType (System.ComponentModel.DataAnnotations)
4. ReadOnly (System.ComponentModel)
5. DisplayFormat (System.ComponentModel.DataAnnotations)
6. ScaffoldColumn (System.ComponentModel.DataAnnotations)
   它会影响ShowForDisplay和ShowForEdit的值;
7. DisplayName

CSS position解析

留下评论

CSS的定位属性可以有四种值

static
表示会根据页面的默认流式布局来设定元素的位置,这也是在默认情况下被选用的值;
fix
表示元素的位置相对于整个window全局对象,那么,当拖动浏览器滚动条时,该元素的位置仍然不会变;
注意:在IE7,IE8中使用标签!DOCTYPE指定文档类型后,该值才有意义;另外,由于使用fix的元素会被从正常的流式布局中移除,因此,它不会影响其他元素在正常布局中的位置;
relative
是相对于该元素在正常布局中本应该所在位置而言的;为元素预留的空间在正常布局中仍然被保留;
absolute
位置相对于第一个满足条件其poistion不是static的父节点;如果这样的节点不存在,就采用;
absolute也会让元素被移出正常的流式布局中;

position:absolute不被正常的流式布局所影响;同样,它也不影响正常的流式布局。它们的父容器只能是如下两种:
1. 最近的定位设置不等于static的祖先;
2. 全局的window或视口;
position:fix跟absolute的表现基本相同,只不过它的父容器只能是全局的window。fix的定位方式非常适合于那些总是可见的区域。
可惜的是,IE6并不识别这个属性值。更恐怖的是,IE6会把用正常的流式布局规则来处理之。
浏览器会为每个显示的网页保持一个栈式的上下文信息,所有显示的元素会按照它们在代码中出现的次序依次被压入栈。当然,
z-index属性可以打破这个默认的规则。如果z-index被应用于position:absolute的元素,浏览器会生成一个单独的栈式上下文。
任何positioning属性等于absolute或relative的子元素都被加入这个新生成的栈式上下文,而不是网页的栈式上下文;否则,其子元素
仍被压入新生成的栈式上下文,但是其定位信息将会被忽略,即采用static属性值,位置使用auto,z-index也使用auto。

javascript good blog

留下评论

http://nefariousdesigns.co.uk/archive/2006/05/object-oriented-javascript/

Understanding JavaScript’s this keyword

JavaScript的六种境界

留下评论

http://dean.edwards.name/weblog/2006/06/levels/
1.

alert("Hello World");

2.

  • var WORLD = "World";
    function hello(who) {
      alert("Hello " + who);
    };
    hello(WORLD);
  • 3.

  • <button onclick="hello(WORLD)">Say Hello</button>
  • 4.

  • <button id="hello">Say Hello</button>
    var button = document.all.hello;
    button.onclick = function() {
      hello(WORLD);
    };
  • 5.

  • var button = document.getElementById("hello");
    button.addEventListener("click", function(event) {
      hello(WORLD);
    }, false);
  • 6.

  • var Hello = new Binding({
      greet: function(who) {
        alert("Hello " + who);
      },
    
      onclick: function() {
        this.greet(Hello.WORLD)
      }
    }, {
      WORLD: "World"
    });
    document.bind("#hello", Hello);