ASP.NET 企业应用技术详解

Web开发的一些基本原则

一、最小权限原则

  只允许用户做某些操作,而不是不允许用户做某些操作。

  用户看到的是服务器端执行输出的结果,用户不可能看到aspx、aspx.cs源文件,目标另存为也是保存的服务器端执行后的结果。js、html是被输出到浏览器上的,用户有办法看到。

二、C#代码运行在服务器端,js代码运行在客户端。

  可以在空间的OnClientClick中编写客户端代码(js):return confirm(‘真的要删除吗?’)

  服务器端编写context.Response.Write("<srcipt ty[pe='text/javascript> alert(' 删除成功')</script>'");

会看到页面加载时弹出消息框,查看源文件可以看到上面的代码在html源文件的最上端,即浏览器先解析上面的js程序,在继续向下解析。

不能用这种方法来询问客户是否继续操作,因为这种方法阻塞的是客户端的解析和运行,不会对服务器端产生影响。

  服务器端添加Windows.Forms的引用,然后调用MessageBox。show();方法企图显示消息框式错误的,因为这个程序会运行在服务器端,而不是客户端,用户出发时消息框在服务器端弹出。

三、能在浏览器做的事就不要再服务器端做。如做一个加法运算,隐藏一个控件等。

四、客户端是不可信的

  客户端验证不能代替服务器端验证。客户端验证时为了方便用户使用,服务器端验证时为了确保数据合法。有些人可以越过浏览器直接和服务器通信,或禁用js等,如果省略服务器端的验证会不安全。

 不要把机密的数据算法等放到客户端。如输入密码后才可下载功能。如果仅是在html中把下载地址隐藏了,那用户一定可以看到。这样是不安全的,可以用Hyperlinker控件。让他的visible属性为false,只有用户输入正确密码后把visible为TRUE,为FALSE是在客户端html中式看不到这个控件的,只有提交返回后才把这个控件渲染回来。

  应该是在机密页面打开之前做权限校验,而不是在一个页面中做校验,如果正确就倒向机密页面,不正确就不导向。

缓存(Cache)

如果每次进入页面的时候都查询数据库生成页面内容的话,如果访问量非常大,则网站性能会非常差。而如果只有第一次访问的时候才查询数据库生成页面内容,以后都直接输出内容,则能提高系统性能。这样无论有多少人访问都只访问一次数据库,数据库压力不变。

缓存(Cache)是一种用空间换取时间的技术,存在于计算机中很多地方,用来将一些慢速设备中的常用数据保存在快速设备中,取数据的时候直接从快速设备中取。比如CPU二级缓存、Windows文件读取缓存。

缓存存在失效的问题:为了保证从缓存中读取数据和慢速数据中数据一致,则需要在慢速数据中对应的数据发生变化的时候,清除缓存中相应的数据(缓存依赖)。

缓存是改进网站性能的第一个手段,就像索引是改进数据库性能的第一个手段一样。ASP.net缓存主要分为:

页面缓存(中庸)、数据源缓存(最不灵活的)、数据缓存(灵活)这三种主要类型。

页面缓存

给页面添加<%@ OutputCache Duration=“15” VaryByParam=“none”%>标签就可以启用页面缓存,这样整个页面的内容都会被缓存,页面中的ASP.Net代码、数据源在缓存期间都不会被运行,而是直接输出缓存的页面内容。 Duration表示缓存时间,以秒为单位,超过这个时间则缓存失效,再次生成以后会再缓存15秒,以此类推。在Page_Load处设置断点、修改数据库数据测试。这个缓存是在服务器缓存的,不是在客户端,因为用HttpWatch还是能看到向服务器提交的请求的,只不过服务器看到有缓存就没有再执行页面类。一般只有看帖、看新闻、看视频的页面才缓存,CUD的页面没必要缓存。

缓存是针对所有这个页面的访问者。这样1个访问者和1万个访问者、一次访问和100万次访问对数据库的压力是一样的。

对于看新闻页面来讲,如果如上设置的话,则会缓存在第一个看到的新闻,因为?id=2、?id=3只是页面的不同参数而已,为了能让不同的新闻各自缓存,因此可以设置VaryByParam=“id”,表示对于相同页面的不同的id参数进行单独缓存。如果有多个确定缓存的参数,则将参数名用分号隔开即可,比如VaryByParam=“id;number”。测试。缓存可能会有过期数据的问题,因此根据需求选用。

如果想让任何不同的查询字符串都创建不同的缓存,则设置VaryByParam="*",一般情况下设置“*”就足够。

在WebUserControl中也可以像页面缓存一样设置控件的缓存。

注:id;name 组合缓存条件:只有两个参数的值组成的字符不一样的时候,才产生缓存

数据源缓存

设定ObjectDataSource的CacheDuration(缓存时间:秒),EnableCaching=true。这样每隔CacheDuration指定的时间段才调用SelectMethod指定的方法来执行数据库查询,其他时候都是直接返回缓存的数据。取数据的过程缓存,在缓存期间,绑定控件向ObjectDataSource要数据, ObjectDataSource直接将缓存的数据返回给控件,不再去向TypeName指向的类要数据。

缓存固定的时间适用于首页、文章列表等访问频繁的页面,对于看贴页面则不适合,假设有100万个帖子,如果每个帖子都是固定缓存1小时的话,假设一小时之内有10万个帖子被看了,那么就要缓存十万个帖子,非常占用内存,因为“百年一看”的“坟帖”偶然被访问一次也缓存一个小时,占用内存。这时候可以采用“滑动窗口(sliding)”策略,比如帖子缓存10分钟,如果10分钟之内又访问了,则缓存的失效时间修改为从被访问这一刻起的10分钟之后,以此类推。这样经常访问的帖子就可以“长期缓存”,而不经常访问的帖子也不会因为偶然访问而长期占用缓存。设置方法,数据源:CacheExpirationPolicy="Sliding"。面试可聊。todo:貌似滑动有问题。不是问题,Sliding只是策略,服务器会参考。

试验代码:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

using System.Data.SqlClient;

using System.Data;

 

namespace 缓存相关

{

    public partial class 数据源缓存 : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

            //加载时启用数据源缓存

            ObjectDataSource obj = new ObjectDataSource();

            obj.EnableCaching = true;

            obj.CacheDuration = 20;

            obj.CacheExpirationPolicy = DataSourceCacheExpiry.Sliding;  //访问后就清空重新开始计数

            obj.CacheExpirationPolicy = DataSourceCacheExpiry.Absolute;  //累计访问计数

     

        }

 

        private string name;

 

        public void GetInfo()

        {

            SqlConnection conn = new SqlConnection("连接字符串");

            conn.Open();

            SqlCommand cmd = new SqlCommand("@参数",conn);

            SqlParameter[] parms = {

                                   new SqlParameter("@参数","赋值变量"),

                                    new SqlParameter("@参数","赋值变量")

                                   };

            cmd.Parameters.AddRange(parms);

            SqlDataAdapter da = new SqlDataAdapter(cmd);

            DataTable dt = new DataTable();

            da.Fill(dt);

            if (dt.Rows.Count > 0)

            {

                DataBin();

            }

        }

        //绑定实体对像代码   省略

        public void DataBin()

        {

           

        }

    }

}

依赖于文件内容

CacheDependency cDep = new CacheDependency(filePath);

依赖于数据库内容(轮询机制/通知机制)

一:轮询机制

1.在数据库新建版本表。2.在数据库新建触发器(比如在新闻表上新建)。

3.使用C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727中的aspnet_regsql.exe:

注册:aspnet_regsql -S . -E -ed -d 数据库名 -et -t 版本表名

删除:aspnet_regsql -S . -E -d 数据库名 -dt -t 版本表名

取消数据库缓存依赖: aspnet_regsql -S . -E -dd 数据库名

数据库名 列出已注册表:aspnet_regsql -S . -E -d 数据库名 –lt

4.数据库依赖对象

SqlCacheDependency cDep =

new SqlCacheDependency("GSSMS", "CacheDep");

5.配置web.config

1.依赖于文件

System.Web.Caching.CacheDependency cDep =

 new System.Web.Caching.CacheDependency(filePath);

Cache.Add("fmsg", msg, cDep, System.Web.Caching.Cache.NoAbsoluteExpiration, System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, RemovedCallback);

aspnet_regsql -S . -E(集成登陆)/-U sa -P 123 -ed(启动/-dd关闭) -d(数据库名) GSSMS -et(指定缓存依赖的表名/-dt禁用表名) -t(表名) Aticle

2.依赖于数据库的web.config配置

<system.web>

<caching>

<sqlCacheDependency enabled="true">

<databases>

<add name="GSSMS" connectionStringName="conStr2" pollTime="15000"/>

</databases>

</sqlCacheDependency>

</caching>
</system.web>

自定义缓存,依赖缓存

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

 

namespace 缓存相关

{

    public partial class 自定义缓存 : System.Web.UI.Page

    {

        protected void Page_Load(object sender, EventArgs e)

        {

        }

 

        //自定义缓存

        protected void Button1_Click(object sender, EventArgs e)

        {

            Cache.Remove("title");

            Cache.Insert("", "", null, DateTime.Now.AddHours(1), TimeSpan.Zero);

            if (Cache["title"] == null)

            {

                string title = "查询数据库的操作"; //查询数据库的操作结果

                if (title != null)

                {

                    Button1.Text = title;

                    Cache["title"] = title;

                }

            }

            else

            {

                Button1.Text = Cache["title"].ToString();        

            }

        }

 

        //依赖缓存   依赖于文件内容

        protected void Button2_Click(object sender, EventArgs e)

        {

            //Cache.Insert();

            //如果缓存中没有数据

            if (Cache["fmsg"] == null)

            {

                string path = Server.MapPath("~/a.txt");

                string msg = System.IO.File.ReadAllText(path);

                //创建文件依赖对象

                System.Web.Caching.CacheDependency cDep = new System.Web.Caching.CacheDependency(path);

                Cache.Add("fmsg", msg, cDep, System.Web.Caching.Cache.NoAbsoluteExpiration,

                    System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, RemoveCallback);

                Response.Write("刚才因为文件被修改所以缓存清空了,又创建了一个缓存,下次访问的时候就能看到了");

            }

            //缓存中有数据

            else

            {

                Response.Write("Cache['fmsg']=" + Cache["fmsg"].ToString());

            }

        }

        //回调函数   当数据清空的时候

        void RemoveCallback(string key, object value, System.Web.Caching.CacheItemRemovedReason reason)

        {

            string logPath = Server.MapPath("~/cache.log");

            System.IO.File.AppendAllText(logPath,"CacheDependency中,cache["+key+"]="+value.ToString()+"因为"+reason.ToString()+

                "被移除了");

        }

 

        //Cache.Insert方法的使用

        protected void Button3_Click(object sender, EventArgs e)

        {

          //  为数据库中的表新建对应的表,表的标示码,版本号。

          //  为原来的表创建触发器,当发生改变的时候使版本号变化

            //配置web.config文件 等

            string msg = "数据库取出来的数据";     //查询数据库的操作结果

            System.Web.Caching.SqlCacheDependency sqlDep = new

                System.Web.Caching.SqlCacheDependency("依赖数据库名","依赖表名");

            Cache.Insert("fmsg", msg, sqlDep, System.Web.Caching.Cache.NoAbsoluteExpiration,

                    System.Web.Caching.Cache.NoSlidingExpiration, System.Web.Caching.CacheItemPriority.Normal, RemoveCallback);

        }


    }

}

缓存其他

页面缓存、数据源缓存等内部都是使用HttpRuntime.Cache来实现缓存的,在一些页面缓存、数据源缓存完成不了的特殊的缓存要求中,可以直接调用HttpRuntime.Cache进行缓存。 HttpRuntime.Cache是“单例的、全局的的管理器”

HttpRuntime.Cache进行缓存。

页面缓存用HttpResponse.RemoveOutputCacheItem(pagevirthpath)的方法进行清除

(*)清除整个网站的缓存,对于小网站来说很实用。在缓存还未失效的时候可能需要立即清空缓存,让数据库的修改立即反映到界面中,在Inserted、Updated中调用这个方法清除所有的缓存。ASP.Net没有提供现成的方法,可以使用Hack级别的代码,见备注。这段代码代码清除了所有的自定义缓存、页面缓存和数据源的缓存。

(*)ASP.Net缓存默认是保存在内存中的,还可以配置保存到数据库中。大型网站还会配合使用Memcached服务器等, Memcached能够真正运行的要运行在Linux下,windows下也有版本,.net通过Memcached的.Net客户端报来访问Memcached服务器。

 /// <summary>

        /// 递归清理VirtualDirectory下所有页面的缓存

        /// </summary>

        /// <param name="vd"></param>

        private static void ClearPageCache(VirtualDirectory vd)

        {

            foreach (object obj in vd.Children)

            {

                if (obj is VirtualDirectory)

                {

                    ClearPageCache(obj as VirtualDirectory);//递归移除子目录下的缓存

                }

                else if (obj is VirtualFile)

                {

                    VirtualFile vf = obj as VirtualFile;

                    HttpResponse.RemoveOutputCacheItem(vf.VirtualPath);//移除页面缓存

                }

                else

                {

                    throw new Exception("未知Children类型");

                }

            }

        }

        /// <summary>

        /// 清理ASP.Net缓存

        /// </summary>

        public static void ClearOutputCache()

        {

            //移除自定义缓存

            foreach (var item in HttpRuntime.Cache.Cast<DictionaryEntry>().ToArray())

            {

                HttpRuntime.Cache.Remove((string)item.Key);

            }

            ClearPageCache(HostingEnvironment.VirtualPathProvider.GetDirectory("/"));//清理页面缓存

            

            //移除ASP.Net中ObjectDataSource等的缓存,因为这些控件将缓存放到了_cacheInternal。这种反射方法清理缓存可能会随着不同版本而失效。

            Type ct = HttpRuntime.Cache.GetType();

            FieldInfo cif = ct.GetField("_cacheInternal", BindingFlags.NonPublic | BindingFlags.Instance);

            Type cmt = HttpRuntime.Cache.GetType().Assembly.GetType("System.Web.Caching.CacheMultiple");

            Type cachekeyType = HttpRuntime.Cache.GetType().Assembly.GetType("System.Web.Caching.CacheKey");

            FieldInfo cachesfield = cmt.GetField("_caches", BindingFlags.NonPublic | BindingFlags.Instance);

            object cacheInternal = cif.GetValue(HttpRuntime.Cache);

            object caches = cachesfield.GetValue(cacheInternal);

            Type arrayType = typeof(Array);

            MethodInfo arrayGetter = arrayType.GetMethod("GetValue", new Type[] { typeof(int) });

            object cacheSingle = arrayGetter.Invoke(caches, new object[] { 1 });

            FieldInfo entriesField = cacheSingle.GetType().GetField("_entries", BindingFlags.Instance | BindingFlags.NonPublic);

            Hashtable entries = (Hashtable)entriesField.GetValue(cacheSingle);

            List<object> keys = new List<object>();

            foreach (object o in entries.Keys)

            {

                keys.Add(o);

            }

            MethodInfo remove = cacheInternal.GetType().GetMethod("Remove", BindingFlags.NonPublic | BindingFlags.Instance, null,

                new Type[] { cachekeyType, typeof(CacheItemRemovedReason) }, null);

            foreach (object key in keys)

            {

                remove.Invoke(cacheInternal, new object[] { key, CacheItemRemovedReason.Removed });

            }

        }

AJAX简介

没有AJAX会怎么样?普通的ASP.Net每次执行服务端方法的时候都要刷新当前页面,比如实现显示服务器的时间。每次都要刷新页面的坏处:页面刷新打断用户操作、速度慢、增加服务器的流量压力。如果没有AJAX,在youku看视频的过程中如果点击了“顶、踩”、评论、评论翻页,页面就会刷新,视频就会被打断。开发一个看效果:用FLVPlayer播放视频,然后开发一个顶踩的功能,看没有ajax会打断视频,然后将按钮用UpdatePanel包起来就不会打断视频了。用HttpWatch看没有AJAX的时候服务器返回的是整个页面,有了AJAX服务器只返回几个按钮的内容。

AJAX(Asynchronous JavaScript and XML,异步JavaScript和XML)是一种进行页面局部异步刷新的技术。用AJAX向服务器发送请求和获得服务器返回的数据并且更新到界面中,不是整个页面刷新,而是在HTML页面中使用JavaScript创建XMLHTTPRequest对象来向服务器发出请求以及获得返回的数据,就像JavaScript版的WebClient一样,在页面中由XMLHTTPRequest来发出Http请求和获得服务器的返回数据,这样页面就不会刷新了。 XMLHTTPRequest是AJAX的核心对象

XMLHTTPRequest

开发一个AJAX功能需要开发服务端和客户端两块程序。以一个显示服务端时间为例。首先开发一个GetDate1.ashx,输出当前时间。在HTML页面中放一个按钮,在按钮的onclick中创建XMLHTTP向GetDate1.ashx发送请求,获得返回的数据并且显示到界面上。代码见备注。面试常考:不使用UpdatePanel、JQuery等AJAX库编写一个AJAX程序。

也可以在xmlhttp.open中向服务器传递参数:xmlhttp.open("POST", "GetDate1.ashx?, false),如果传递给服务器的请求里有中文,则需要使用Javascript函数encodeURI来进行URL编码。

案例:用AJAX实现顶和踩:不用数据库,用全局变量。

var xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); //创建XMLHTTP对象,相当于

            xmlhttp.open("POST", "GetDate1.ashx"); //“准备”向服务器的GetDate1.ashx发出Post请求。这里还没有发出请求

            //XMLHTTP默认(也推荐)不是同步请求的,也就是open方法并不像WebClient的DownloadString那样把服务器返回的数据拿到才返回,是异步的,因此需要监听onreadystatechange事件

            xmlhttp.onreadystatechange = function() {

            if (xmlhttp.readyState == 4) {//readyState == 4 表示服务器返回数据了

                if (xmlhttp.status == 200) {//如果状态码为200则是成功

                    //接收服务器的返回数据,没有用send的返回值,而是在onreadystatechange    事件里来接收的

                        document.getElementById("s1").innerHTML = xmlhttp.responseText; //responseText属性为服务器返回的文本

                    }

                    else {

                        alert("AJAX服务器返回错误!");

                    }

                }

            }

            //不要以为if (xmlhttp.readyState == 4) {在send之前执行!!!!

            //if (xmlhttp.readyState == 4)只有在服务器返回值以后才会执行,而send之后过一会儿服务器才会返回数据

            xmlhttp.send(); //这时才开始发送请求

            //发出请求后不等服务器返回数据,就继续向下执行,所以不会阻塞,界面就不卡了,这就是AJAX中“A”的含义“异步”

页面详细代码:

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Ajax.aspx.cs" Inherits="Ajax" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title></title>

    <script src="Scripts/common.js" type="text/javascript"></script>

    <script type="text/javascript">

        function createXmlHttp() {//创建xhr对象

            var xhobj = false;

            try {

                xhobj = new ActiveXObject("Msxml2.XMLHTTP"); // ie msxml3.0+

            } catch (e) {

                try {

                    xhobj = new ActiveXObject("Microsoft.XMLHTTP"); //ie msxml2.6

                } catch (e2) {

                    xhobj = false;

                }

            }

            if (!xhobj && typeof XMLHttpRequest != 'undefined') {// Firefox, Opera 8.0+, Safari

                xhobj = new XMLHttpRequest();

            }

            return xhobj;

        }

        //声明变量

        var xhr = false;

        //在浏览器加载完所有的页面资源后创建 异步对象

        window.onload = function () {

            xhr = createXmlHttp();

        }

        //点击按钮时调用此方法,使用AJAX到服务器拿数据

        function doAjax() {

            //设置参数

            xhr.open("GET", "Ajax.aspx?isAjax=1", true);            

            //设置回调函数

            xhr.onreadystatechange = watching;

            //出发

            xhr.send(null);

        }

        //回调函数

        function watching() {

            alert(xhr.readyState);

            //检查 异步对象 的准备状态是否=4,如果等于4说明服务器已经将数据发回给异步对象了

            if (xhr.readyState >= 4) {

                if (xhr.status == 200) {//正常返回,判断服务器返回的状态码是否=200

                    var txt = xhr.responseText;//获得服务器返回的字符数据

                    document.getElementById("divMsg").innerHTML = txt;//显示到页面div中

                } else {

                    document.getElementById("divMsg").innerHTML = "服务器出错啦!" + xhr.status;

                }

            }

        }

        function test() {

            alert(ChangeDateFormat("\/Date(1302451200000)\/"));

        }

    </script>

</head>

<body>

    <form  runat="server">

    <input type="button" value="AJAX请求" onclick="doAjax()" />

    <input type="button" value="test" onclick="test()"/>

    <div >

    </div>

    </form>

</body>

</html>

JQuery AJAX

new ActiveXObject("Microsoft.XMLHTTP")是IE中创建XMLHttpRequest对象的方法。非IE浏览器中创建方法是new XmlHttpRequest()。为了兼容不同的浏览器需要编写很多代码,见备注。

回调函数中data参数为服务器返回的数据, textStatus为服务器返回状态码, textStatus为"success"表示成功。

JQuery中提供了简化ajax使用的方法。$.ajax()函数是JQuery中提供的ajax访问函数,$.post()是对$.ajax()的post方式提交ajax查询的封装, $.get()是对$.ajax()的get方式提交ajax查询的封装。推荐用post方式,因为post方式没有缓存的问题,演示,get方式中缓存处理的处理方法。代码见备注。todo:好像服务端异常404、500等回调方法并不会被调用。

如果有请求参数则在第二个参数用字典方式来设置。 $.post("GetDate1.ashx", {"id":"2"},function(data, textStatus) {。JQuery帮我们进行了URL编码,因此参数中有中文也不用担心。

请求、处理、响应!服务器返回给客户端的就是一堆文本。如果服务器Write一堆文本,客户端拿到的就是一堆文本,if(data=="true")。怎么样调试AJAX程序的错误。要看浏览器有没有向服务器发出请求。分别查看“请求、处理、响应”三个阶段。

AJAX程序排错技巧:先用HttpWatch看浏览器有没有向服务器发出请求,如果没有的话检查本地代码,如果有的话,看服务器的返回,如果服务器返回有异常,则通过调试的方式让程序在发生异常的点断住。如果服务器没有返回异常,接着看服务器返回的内容是不是期望的。调试AJAX程序最好的工具就是HttpWatch!!!

1、兼容浏览器的创建XMLHttp对象的方法

function CreateXmlHttp()

        {

            var xmlhttp;

            //非IE浏览器创建XmlHttpRequest对象

            if (window.XmlHttpRequest)

            {

                xmlhttp = new XmlHttpRequest();

            }

            //IE浏览器创建XmlHttpRequest对象

            if (window.ActiveXObject)

            {

                try

                {

                    xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");

                }

                catch (e)

                {

                    try

                    {

                        xmlhttp = new ActiveXObject("msxml2.XMLHTTP");

                    }

                    catch (ex) { alert("AJAX创建失败!");}

                }

            }

            return xmlhttp;

        }

2、JQuery的post封装

$.post("GetDate1.ashx", function(data, textStatus) {

$("#Button2").val(data);

});

请求参数:$.post("GetDate1.ashx", {"id":"2"},function(data, textStatus) {

Json

AJAX传递复杂数据如果自己进行格式定义的话会经历组装、解析的过程,因此AJAX中有一个事实上的数据传输标准JSon。Json(是一个标准,就像XML一样,Json规定了对象以什么样的格式保存为一个字符串)将复杂对象序列化为一个字符串,在浏览器端再将字符串反序列化为JavaScript可以读取的对象。看一下Json的格式。Json被几乎所有语言支持。

C#中将.Net对象序列化为Json字符串的方法:JavaScriptSerializer().Serialize(p), JavaScriptSerializer在System.Web.Extensions.dll中,是.Net3.x 中新增的类,如果在.Net2.0中则需要用第三方的组件。

JQuery AJAX得到的data是Json格式数据,用$.parseJSON(data)方法将JSon格式数据解析为JavaScript对象

可以在post函数最后一个函数传递"json"则data就是反序列化以后的对象,免去了parseJSON

微软AJAX解决方案(*)

ASP.Net中内置的简化AJAX开发的控件UpdatePanel

  • 放入ScriptManager,将要实现AJAX效果的控件放到UpdatePanel中即可。
  • UpdatePanel原理探秘,用HttpWatch看。
  • 只把需要无刷新更新的部分放到UpdatePanel中。
  • UpdatePanel用来实现一些对性能要求不高的需求非常方便。
  • 从原理分析为什么在客户端把TextBox变红,AJAX请求以后又变白了。

Timer实现定时AJAX效果,原理分析。

UpdateProgress显示“正在加载数据”。

AJAX Toolkit简介。

全局文件

添加Web→全局应用程序类,注意文件名不要改。

  • 全局文件是对Web应用声明周期的一个事件响应的地方
  • 将Web应用启动时初始化的一些代码写到Application_Start中,比如后面讲的Log4Net的初始化等。应用关闭的时候Application_End调用。
  • 当一个Session启动的时候Session_Start被调用,Session结束(用户主动退出或者超时结束)Session_End被调用。
  • 当一个用户请求来的时候Application_BeginRequest方法被调用
  • 当应用中出现未捕获异常,Application_Error被调用(常考,ASP.Net中的错误处理机制),用HttpContext.Current.Server.GetLastError()获得异常信息,然后用Log4Net记录到日志中。

使用案例:实现图片的防盗链,讨论;屏蔽指定的IP地址。

图片防盗链发过去一个错误图片同样浪费资源。

 protected void Application_BeginRequest(object sender, EventArgs e)

        {

            var Request = HttpContext.Current.Request;

            if (Request.Url.PathAndQuery.StartsWith("/domDemo2/images/mm/"))//防止美女时钟的图片盗链

            {

                //判断是否盗链

                if (Request.UrlReferrer == null || !IsSameHost(Request.UrlReferrer, Request.Url))

                {

                    HttpContext.Current.Response.Write("请勿直接访问图片,请在美女时钟页面中访问!");

                    HttpContext.Current.Response.End();

                }

            }

        }

        /// <summary>

        /// 判断uri1和uri2是否是在同一台主机上

        /// </summary>

        /// <param name="uri1"></param>

        /// <param name="uri2"></param>

        /// <returns></returns>

        private static bool IsSameHost(Uri uri1, Uri uri2)

        {

            return Uri.Compare(uri1, uri2, UriComponents.Host, UriFormat.SafeUnescaped, StringComparison.CurrentCultureIgnoreCase) == 0;

        }

错误页

当页面发生错误的时候,ASP.Net会将错误信息展示出来(Sqlconnection的错误就能暴露连接字符串),这样一来不好看,二来会泄露网站的内部实现信息,给网站带来安全隐患,因此需要定制错误页,发生错误时显示开发人员定制的页面。404页面放点广告也是好的嘛。

配置web.config,配置customErrors区域:

<customErrors mode="On" defaultRedirect="MyErrorPage.aspx">
       <error statusCode="403" redirect="NoAccess.htm" />
       <error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>

mode三个可选值:On:总是显示定制错误页面;Off:不显示定制错误界面,直接显示调用堆栈等异常信息;remoteonly:对于本机的访问显示调用堆栈等异常信息,对于外部用户的显示定制错误页面。一般设置为RemoteOnly,这样发生错误的话,管理员可以在服务器的浏览器中看详细错误信息,普通用户看不到。学习演示的时候mode设置为On,否则看不到定制页。可以在定义错误页中判断Request.UserHostAddress来设置某些ip看到异常信息,可以读取Session如果是管理员则可以看异常信息。

error子元素设定对于不同的状态码使用不同的错误页,很多网站都把404做一个特殊的错误页。没有单独设置的状态码错误则显示defaultRedirect中指定的页面。

错误页即可以使用htm页面,也可以使用aspx页面。在aspx页面中可以用HttpContext.Current.Server.GetLastError()拿到异常对象。一般不要把异常信息显示给用户,而是使用后面讲的Log4Net等将异常记录到系统日志。如果要在错误页面中拿到异常对象,比如customErrors中设置redirectMode="ResponseRewrite",因为默认是客户端重定向,在错误页面中就拿不到异常对象了。

URL重写(UrlRewrite)

为什么要URL重写?1、有利于SEO,带参数的URL权重较低;2、地址看起来更正规,推广uid。

伪静态:看起来像普通页面,而非动态生成的页面。

原理:在Global.asax的Application_BeginRequest 中读取Request.Url 得到请求的URL(View-3.aspx),然后用HttpContext.Current.RewritePath(ReWriteUrl)进行重写(也就是交由另外一个页面处理这个请求)(View.aspx?tid=3格式) http://www.cnblogs.com/hd/archive/2005/06/20/177633.html

也可以使用微软的URLRewrite,只要修改配置文件就可以进行URL重写。照着文档自学配置。

configSections下增加

<section name="RewriterConfig"type="URLRewriter.Config.RewriterConfigSerializerSectionHandler, URLRewriter" /> 

<configuration>中增加

 <RewriterConfig>

    <Rules>

      <RewriterRule>

        <LookFor>~/ViewArticle-(\d+)\.aspx</LookFor>

        <SendTo>~/ViewArticle.aspx?Id=$1</SendTo>

      </RewriterRule>

      <RewriterRule>

        <LookFor>~/ArticleList-(\d+)\.aspx</LookFor>

        <SendTo>~/ArticleList.aspx?catId=$1</SendTo>

      </RewriterRule>

    </Rules>

  </RewriterConfig>

system.web下增加

<httpHandlers>
  <add verb="*" path="*.aspx"type="URLRewriter.RewriterFactoryHandler, URLRewriter" >
</httpHandlers>