品雨凉秋http://blog.yesky.com/Blog/yangkai1217/复制地址

Every man is the master of his own fortune. .

公告栏
喜得凤凰求美眷,只羡鸳鸯不羡仙。。。!!!


控制面板
日历
<2008年7月>
SuMoTuWeThFrSa
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789
留言簿(1)
文章分类
文章档案
日记分类
日记档案
数字生活
友情链接
我的博客圈
ip是多少呢
阅读(3) | 评论(0)编辑 | 举报
阅读(129) | 评论(1)编辑 | 举报
阅读(137) | 评论(0)编辑 | 举报
阅读(210) | 评论(2)编辑 | 举报


按此在新窗口浏览图片
虞美人 

李煜
春花秋月何时了,往事知多少。
小楼昨夜又东风,
故国不堪回首月明中。
雕栏玉砌应犹在,只是朱颜改。
问君能有几多愁,
恰似一江春水向东流。
阮郎归
李煜
东风吹水日衔山,春来长是闲。
落花狼籍酒阑珊,笙歌醉梦间。
佩声悄,晚妆残,凭谁整翠鬟?
留连光景惜朱颜,黄昏独倚阑。

按此在新窗口浏览图片
夏夜即事
倦绣佳人幽梦长,金笼鹦鹉唤茶汤。
窗明麝月开宫镜,室霭檀云品御香。
琥珀杯倾荷露滑,玻璃栏纳柳风凉。
水亭处处齐纨动,帘卷朱楼罢晚妆。
按此在新窗口浏览图片
寄人 张泌
别梦依依到谢家,
小廊回合曲阑斜。
多情只有春庭月,
犹为离人照落花。

按此在新窗口浏览图片
浣溪沙
玉碗冰寒滴露华,
粉融香雪透轻纱,
晚来妆面胜荷花。
鬓亸欲迎眉际月,
酒红初上脸边霞,
一场春梦日西斜。

按此在新窗口浏览图片
我 是一朵盛开的夏荷
多希望
你能看见现在的我
风霜还不曾来侵蚀
秋雨也未滴落
青涩的季节又已离我远去
我已亭亭 不忧 也不惧
现在 正是
我最美丽的时刻
重门却已深锁
在芬芳的笑靥之后
谁人知我莲的心事
无缘的你啊
不是来得太早 就是
太迟
席慕容 《莲的心事》

按此在新窗口浏览图片
周子横山隐,开门临城隅。连峰入户牖,胜概凌方壶。
时作白纻词,放歌丹阳湖。水色傲溟渤,川光秀菰蒲。
当其得意时,心与天壤俱。闲云随舒卷,安识身有无。
抱石耻献玉,沉泉笑探珠。羽化如可作,相携上清都。
李白《赠丹阳横山周处士惟长》
采桑子
天容水色西湖好,
云物俱鲜。
鸥鹭闲眠,
应惯寻常听管弦。
风清月白偏宜夜,
一片琼田。
谁羡骖鸾,
人在舟中便是仙。
欧阳修
按此在新窗口浏览图片
卢照邻《元日述怀》
篮仕无中秩,归耕有外臣。
人歌小岁酒,花舞大唐春。
草色迷三径,风光动四邻。
愿得长如此,年年物候新。

按此在新窗口浏览图片
[清] 许承祖
水上新红漾碧虚,
卢园景物尽邱墟。
就中只觉游鱼乐,
我亦忘机乐似鱼。
减字木兰花
寻花携李。
红漾轻舟汀柳外。
小簇春山。
溪雨岩云不饱帆。
相逢心醉。
容易堆盘银烛泪。
痛饮何言。
犀箸敲残玉酒船。
【宋】 作者:【朱敦儒】
七里滩声舜庙前,
杏花初盛草芊芊。
绿昏晴气春风岸,
红漾轻纶野水天。
不为伤离成极望,
更因行乐惜流年。
一瓢无事麛裘暖,
手弄溪波坐钓船。
【唐】作者:温庭筠
作品:敬答李先生

按此在新窗口浏览图片 
《凤求凰》:
“凤兮凤兮归故乡,遨游四海求其凰。时未遇兮无所将,何悟今兮升斯堂!有艳淑女在闺房,室迩人遐毒我肠。何缘交颈为鸳鸯,胡颉颃兮共翱翔!凰兮凰兮从我栖,得托孳尾永为妃。交情通意心和谐,中夜相从知者谁?双翼俱起翻高飞,无感我思使余悲。”

按此在新窗口浏览图片
黄巢《题菊花》
飒飒西风满院栽,
蕊寒香冷蝶难来。
他年我若为青帝,
报与桃花一处开。
菊梦
篱畔秋酣一觉清,和云伴月不分明。
登仙非慕庄生蝶,忆旧还寻陶令盟。
睡去依依随雁断,惊回故故恼蛩鸣。
醒时幽怨同谁诉:衰草寒烟无限情!
---潇湘妃子

按此在新窗口浏览图片
赋得红梅花(邢岫烟)
桃未芳菲杏未红,冲寒先喜笑东风。
魂飞瘐岭春难辨,霞隔罗浮梦未通。
绿萼添妆融宝炬,缟仙扶醉跨残红。
看来岂是寻常色,浓淡由他冰雪中。
女娲石上偈语
无材可去补苍天,枉入红尘若许年。
此系身前身后事,倩谁记去作奇传?

阅读(300) | 评论(2)编辑 | 举报

1 oracle数据库.
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url="jdbc:oracle:thin:@localhost:1521:orcl"; //orcl为数据库的SID
String user="test";
String password="test";
Connection conn= DriverManager.getConnection(url,user,password);   

2、DB2数据库
Class.forName("com.ibm.db2.jdbc.app.DB2Driver ").newInstance();
String url="jdbc:db2://localhost:5000/sample"; //sample为你的数据库名
String user="admin"; String password="";
Connection conn= DriverManager.getConnection(url,user,password);   

3、Sql Server7.0/2000数据库
Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
String url="jdbc:microsoft:sqlserver://localhost:1433;DatabaseName=mydb"; //mydb为数据库
String user="sa"; String password="";
Connection conn= DriverManager.getConnection(url,user,password);

4、Sybase数据库 Class.forName("com.sybase.jdbc.SybDriver").newInstance();
String url =" jdbc:sybase:Tds:localhost:5007/myDB";//myDB为你的数据库名
Properties sysProps = System.getProperties();
SysProps.put("user","userid"); SysProps.put("password","user_password");
Connection conn= DriverManager.getConnection(url, SysProps);   

5、Informix数据库
Class.forName("com.informix.jdbc.IfxDriver").newInstance();
String url = "jdbc:informix-sqli://123.45.67.89:1533/myDB:INFORMIXSERVER=myserver; user=testuser;password=testpassword"; //myDB为数据库名
Connection conn= DriverManager.getConnection(url);   

6、MySQL数据库
Class.forName("org.gjt.mm.mysql.Driver").newInstance(); //或者Class.forName("com.mysql.jdbc.Driver"); String url ="jdbc:mysql://localhost/myDB?user=soft&password=soft1234&useUnicode=true&characterEncoding=8859_1" //myDB为数据库名 Connection conn= DriverManager.getConnection(url);   

7、PostgreSQL数据库
Class.forName("org.postgresql.Driver").newInstance();
String url ="jdbc:postgresql://localhost/myDB" //myDB为数据库名
String user="myuser";
String password="mypassword";
Connection conn= DriverManager.getConnection(url,user,password);   

8、access数据库直连用ODBC的
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver") ;
String url="jdbc:odbc:Driver={MicroSoft Access Driver (*.mdb)};
DBQ="+application.getRealPath("/Data/ReportDemo.mdb");
Connection conn = DriverManager.getConnection(url,"","");
Statement stmtNew=conn.createStatement() ;

阅读(365) | 评论(0)编辑 | 举报

   第一次FIN  197 8K 哇卡卡

 

阅读(295) | 评论(1)编辑 | 举报

转自http://www.codeproject.com/Ajax/aspnetajaxtips.asp

Introduction

Microsoft recently released Beta 2 of ASP.NET AJAX. Although it's a very powerful framework, when you will build a real AJAX site like those out there in the Web 2.0 world, you will face many problems that you will hardly find documented anywhere. In this article, I will show some advance level ideas that I learned while building Pageflakes. We will look at the advantages and disadvantages of Batch calls, AJAX call timeouts, browser call jam problem, ASP.NET 2.0's bug in web service response caching, and so on.

Update 12/22/2006: Updated for the ASP.NET AJAX RC Release.

Why use ASP.NET AJAX

When others see Pageflakes, the first question they ask me is: "Why did you not use Protopage or Dojo library? Why Atlas?" Microsoft Atlas (renamed to ASP.NET AJAX) is a very promising AJAX framework. They are putting a lot of effort on it, making lots of reusable components that can really save you a lot of time and give your web application a complete face lift at reasonably low effort or changes. It integrates with ASP.NET very well, and it is compatible with the ASP.NET Membership and Profile provider. The AJAX Control Toolkit project contains 28 extenders which you can drag & drop on your page, tweak some properties, and add pretty cool effects on the page. Check out the examples to see how powerful the ASP.NET AJAX framework has really become.

When we first started developing Pageflakes, Atlas was in infant stage. We were only able to use the page method and Web Service method call features of Atlas. We had to make our own drag & drop, component architecture, popups, collapse/expand features etc. But now, you can have all these from Atlas and thus save a lot of development time. The web service proxy feature of Atlas is a marvel. You can point a <script> tag to a .asmx file and you get a JavaScript class generated right out of the web service definition. The JavaScript class contains the exact methods that you have on the web service class. This makes it really easy to add/remove new web services, and add/remove methods in web services which does not require any changes on the client side. It also offers a lot of control over the AJAX calls, and provides rich exception trapping feature on the JavaScript. Server side exceptions are nicely thrown to the client side JavaScript code, and you can trap them and show nicely formatted error messages to the user. Atlas works really well with ASP.NET 2.0, eliminating the integration problem completely. You need not worry about authentication and authorization on page methods and web service methods. So, you save a lot of code on the client side (of course, the Atlas Runtime is huge for this reason), and you can concentrate more on your own code than building up all these framework related code.

The recent version of Atlas works nicely with ASP.NET Membership and Profile services, giving you login/logout features from JavaScript without requiring page postbacks, and you can read/write Profile objects directly from JavaScript. This comes very handy when you heavily use ASP.NET membership and profile providers in your web application, which we do at Pageflakes.

On earlier versions of Atlas, there was no way to make HTTP GET calls. All calls were HTTP POST, and thus quite expensive calls. Now, you can say which calls should be HTTP GET. Once you have HTTP GET, you can utilize HTTP response caching features which I will show you soon.

Batch calls are not always faster

ASP.NET AJAX has a feature in the CTP release (and previous releases) which allows batching multiple requests into one request. It works transparently, you won't notice anything, nor would you need to write any special code. Once you turn on the Batch feature, all web service calls made within a duration gets batched into one call. Thus it saves roundtrip time and total response time.

The actual response time might be reduced, but the perceived delay is higher. If three web service calls are batched, the first call does not finish first. All three calls finish at the same time. If you are doing some UI updates upon completion of each WS call, it does not happen one by one. All of the calls complete in one shot and then the UI gets updated in one shot. As a result, you do not see incremental updates on the UI, instead a long delay before the UI updates. If any of the calls, say the third call downloads a lot of data, the user sees nothing happening until all three calls complete. So, the duration of the first call becomes nearly the duration of the sum of all three calls. Although the actual total duration is reduced, the perceived duration is higher. Batch calls are handy when each call is transmitting a small amount of data. Thus three small calls get executed in one roundtrip.

Let's work on a scenario where three calls are made one by one. Here's how the calls actually get executed.

The second call takes a little bit time to reach the server because the first call is eating up the bandwidth. For the same reason, it takes longer to download. Browsers open two simultaneous connections to the server. So at a time, only two calls are made. Once the second/first call completes, the third call is made.

When these three calls are batched into one:

Here the total download time is reduced (if IIS compression is enabled), and there's only one network latency overhead. All three calls get executed on the server in one shot, and the combined response is downloaded in one call. But to the user, the perceived speed is slower because all the UI update happens after the entire batch call completes. The total duration the batch call will take to complete will always be higher than that for two calls. Moreover, if you do a lot of UI updates one after another, Internet Explorer freezes for a while, giving the user a bad impression. Sometimes, expensive updates on the UI makes the browser screen go blank and white. But Firefox and Opera does not have this problem.

Batch calls have some advantages too. The total download time is less than that for downloading individual call responses because if you use gzip compression in IIS, the total result is compressed instead of individually compressing each result. So, generally, a batch call is better for small calls. But if a call is going to send a large amount of data or is going to return, say, 20KB of response, then it's better not to use batch. Another problem with batch call is, say two calls are very small but the third call is quite big, and if these three calls get batched, the smaller calls are going to suffer from the long delay due to the third larger call.

Bad calls make good calls timeout

If two HTTP calls somehow get stuck for too long, those two bad calls are going to make some good calls expire too, which in the meantime got queued. Here's a nice example:

Collapse
function TestTimeout()
{
    debug.trace("--Start--");
    TestService.set_defaultFailedCallback( 
            function(result, userContext, methodName)
    {
        var timedOut = result.get_timedOut();
        if( timedOut )
            debug.trace( "Timedout: " + methodName );
        else
            debug.trace( "Error: " + methodName );
    });
    TestService.set_defaultSucceededCallback( function(result)
    {
        debug.trace( result );
    });
    
    TestService.set_timeout(5000);
    TestService.HelloWorld("Call 1");
    TestService.Timeout("Call 2");
    TestService.Timeout("Call 3");
    TestService.HelloWorld("Call 4");
    TestService.HelloWorld("Call 5");
    TestService.HelloWorld(null); // This one will produce Error
}

On the server side, the web service is very simple:

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class TestService : System.Web.Services.WebService {

    public TestService () {

        //Uncomment the following line if using designed components 
        //InitializeComponent(); 
    }

    [WebMethod][ScriptMethod(UseHttpGet=true)]
    public string HelloWorld(string param) {
        Thread.Sleep(1000);
        return param;
    }
    
    [WebMethod][ScriptMethod(UseHttpGet=true)]
    public string Timeout(string param) {
        Thread.Sleep(10000);
        return param;
    }
}

I am calling a method named "Timeout" on the server which does nothing but wait for a long time so that the call gets timed out. After that, I am calling a method which does not timeout. But guess what the output is:

Only the first call succeeded. So, if at any moment, the browser's two connections get jammed, then you can expect other waiting calls are going to timeout as well. 

In Pageflakes, we used to get nearly 400 to 600 timeout error reports from users' browsers. We could never find out how this could happen. First, we suspected slow internet connection. But that cannot happen for so many users. Then we suspected something is wrong with the hosting provider's network. We did a lot of network analysis to find out whether there were any problems on the network or not. But we could not detect any. We used SQL Profiler to see whether there were any long running queries which timed out the ASP.NET request execution time. But no luck. We finally discovered that, it mostly happened due to some bad calls which got stuck and made the good calls expire too. So, we modified the Atlas Runtime and introduced automatic retry on it, and the problem disappeared completely. However, this auto retry requires a sophisticated open heart bypass surgery on the ASP.NET AJAX framework JavaScript. The idea is to make each and every call retry once when it times out. In order to do that, we need to intercept all web method calls and implement a hook on the onFailed callback, which will call the same web method again if the failure reason was a timeout.

Another interesting discovery we made while we were traveling was that whenever we tried to visit Pageflakes from a hotel or an airport wireless internet connection, the first visit always failed and all the web service calls on first attempt always failed. Until we did a refresh, nothing worked. This was another major reason why we implemented immediate auto retry of web service calls, which fixed the problem.

Here's how to do it. Sys$Net$WebServiceProxy$invoke function is responsible for making all Web Service calls. So, we replace this function with a custom implementation which passes a custom onFailure callback. That custom callback gets fired whenever there's an error or timeout. So, when there's a time out, it calls the this function again and thus a retry happens.

Collapse
Sys.Net.WebServiceProxy.retryOnFailure = 
    function(result, userContext, methodName, retryParams, onFailure)
{
    if( result.get_timedOut() )
    {
        if( typeof retryParams != "undefined" )
        {
            debug.trace("Retry: " + methodName);
            Sys.Net.WebServiceProxy.original_invoke.apply(this, retryParams );
        }
        else
        {
            if( onFailure ) onFailure(result, userContext, methodName);
        }
    }
    else
    {
        if( onFailure ) onFailure(result, userContext, methodName);
    }
}

Sys.Net.WebServiceProxy.original_invoke = Sys.Net.WebServiceProxy.invoke;
Sys.Net.WebServiceProxy.invoke = 
    function Sys$Net$WebServiceProxy$invoke(servicePath, methodName, useGet, 
        params, onSuccess, onFailure, userContext, timeout)
{   
    var retryParams = [ servicePath, methodName, useGet, params, 
        onSuccess, onFailure, userContext, timeout ];
    
    // Call original invoke but with a new onFailure
    // handler which does the auto retry
    var newOnFailure = Function.createDelegate( this, 
        function(result, userContext, methodName) 
        { 
            Sys.Net.WebServiceProxy.retryOnFailure(result, userContext, 
                methodName, retryParams, onFailure); 
        } );
        
    Sys.Net.WebServiceProxy.original_invoke(servicePath, methodName, useGet, 
        params, onSuccess, newOnFailure, userContext, timeout);
}

When run, it will retry each timed out call once.

Here you see the first method succeeded and all the others timed out and was retried. But you will see that after a retry they all succeed. This happens because server side method do not timeout on retry. So, this proves that our implementation is correct. 

Browsers allow two calls at a time and don't expect any order

Browsers make two concurrent AJAX calls at a time to a domain. If you make five AJAX calls, the browser is going to make two calls first, then wait for any one of them to complete and then make another call until all remaining four calls are complete. Moreover, you cannot expect calls to execute in the same order as you make the calls. Here's why:

Here you see, call 3's response download is quite big, and thus takes longer than call 5. So, call 5 actually gets executed before call 3.

So, the world of HTTP is unpredictable.

Browsers do not respond when more than two calls are in queue

Try this, go to any start page in the world which will load a lot of RSS on the first visit (e.g., Pageflakes, Netvibes, Protopage), and while loading, try to click on a link which will take you to another site or try to visit another site. You will see the browser is stuck. Until all queued AJAX calls in the browser completes, the browser will not accept any other activity. This is worst in Internet Explorer. But Firefox and Opera do not have this much of a problem.

The problem is, when you make a lot of AJAX calls, the browser keeps all calls in a queue and executes two at a time. So, if you click on something or try to navigate to another site, the browser has to wait for running calls to complete before it can take another call. The solution to this problem is to prevent more than two calls being queued in browser at a time. We need to maintain a queue ourselves, and send calls to the browser's queue from our queue one by one.

The solution is quite shocking, brace for impact:

Collapse
var GlobalCallQueue = {
    _callQueue : [],    // Maintains the list of webmethods to call
    _callInProgress : 0,    // Number of calls currently in progress by browser
    _maxConcurrentCall : 2, // Max number of calls to execute at a time
    _delayBetweenCalls : 50, // Delay between execution of calls 
    call : function(servicePath, methodName, useGet, 
        params, onSuccess, onFailure, userContext, timeout)
    {
        var queuedCall = new QueuedCall(servicePath, methodName, useGet, 
            params, onSuccess, onFailure, userContext, timeout);

        Array.add(GlobalCallQueue._callQueue,queuedCall);
        GlobalCallQueue.run();
    },
    run : function()
    {
        /// Execute a call from the call queue
        
        if( 0 == GlobalCallQueue._callQueue.length ) return;
        if( GlobalCallQueue._callInProgress < 
            GlobalCallQueue._maxConcurrentCall )
        {
            GlobalCallQueue._callInProgress ++;
            // Get the first call queued
            var queuedCall = GlobalCallQueue._callQueue[0];
            Array.removeAt( GlobalCallQueue._callQueue, 0 );
            
            // Call the web method
            queuedCall.execute();
        }
        else
        {
            // cannot run another call. Maximum concurrent 
            // webservice method call in progress
        }            
    },
    callComplete : function()
    {
        GlobalCallQueue._callInProgress --;
        GlobalCallQueue.run();
    }
};

QueuedCall = function( servicePath, methodName, useGet, params, 
    onSuccess, onFailure, userContext, timeout )
{
    this._servicePath = servicePath;
    this._methodName = methodName;
    this._useGet = useGet;
    this._params = params;
    
    this._onSuccess = onSuccess;
    this._onFailure = onFailure;
    this._userContext = userContext;
    this._timeout = timeout;
}

QueuedCall.prototype = 
{
    execute : function()
    {
        Sys.Net.WebServiceProxy.original_invoke( 
            this._servicePath, this._methodName, this._useGet, this._params,  
            Function.createDelegate(this, this.onSuccess), // Handle call complete
            Function.createDelegate(this, this.onFailure), // Handle call complete
            this._userContext, this._timeout );
    },
    onSuccess : function(result, userContext, methodName)
    {
        this._onSuccess(result, userContext, methodName);
        GlobalCallQueue.callComplete();            
    },        
    onFailure : function(result, userContext, methodName)
    {
        this._onFailure(result, userContext, methodName);
        GlobalCallQueue.callComplete();            
    }        
};

QueuedCall encapsulates one web method call. It takes all the parameters of the actual web service call and overrides the onSuccess and onFailure callbacks. We want to know when a call completes or fails so that we can issue another call from our queue. The GlobalCallQueue maintains the list of all web service calls. Whenever a web method is called, we first queue the call in the GlobalCallQueue and executes calls from the queue one by one ourselves. It ensures, browser does not get more than 2 web service calls at a time and thus browser does not get stuck

In order to enable the queue based call, we need to override the ASP.NET AJAX web method invocation again, as we did before.

Sys.Net.WebServiceProxy.original_invoke = Sys.Net.WebServiceProxy.invoke;
Sys.Net.WebServiceProxy.invoke = 
    function Sys$Net$WebServiceProxy$invoke(servicePath, methodName, 
        useGet, params, onSuccess, onFailure, userContext, timeout)
{   
    GlobalCallQueue.call(servicePath, methodName, useGet, params, 
        onSuccess, onFailure, userContext, timeout);
}

Caching web service response on the browser and saving bandwidth significantly

Browsers can cache images, JavaScript, CSS files on a user's hard drive, and it can also cache XML HTTP calls if the call is a HTTP GET. The cache is based on the URL. If it's the same URL, and it's cached on the computer, then the response is loaded from the cache, not from the server when it is requested again. Basically, the browser can cache any HTTP GET call and return cached data based on the URL. If you make an XML HTTP call as HTTP GET and the server returns some special header which informs the browser to cache the response, on future calls, the response will be immediately returned from the cache and thus saves the delay of network roundtrip and download time.

At Pageflakes, we cache the user's state so that when the user visits again the following day, the user gets a cached page which loads instantly from the browser cache, not from the server. Thus the second time load becomes very fast. We also cache several small parts of the page which appears on user's actions. When the user does the same action again, a cached result is loaded immediately from the local cache and thus saves the network roundtrip time. The user gets a fast loading site and a very responsive site. The perceived speed increases dramatically.

The idea is to make HTTP GET calls while making Atlas web service calls and return some specific HTTP Response headers which tell the browser to cache the response for some specific duration. If you return the "Expires" header during the response, the browser will cache the XML HTTP response. There are two headers that you need to return with the response which will instruct the browser to cache the response:

HTTP/1.1 200 OK 
Expires: Fri, 1 Jan 2030 
Cache-Control: public

This will instruct the browser to cache the response till Jan 2030. As long as you make the same XML HTTP call with the same parameters, you will get cached response from the computer and no call will go to the server. There are more advanced ways to get further control over response caching. For example, here is a header which will instruct the browser to cache for 60 seconds but not contact the server and get a fresh response after 60 seconds. It will also prevent proxies from returning cached response when the browser local cache expires after 60 seconds.

HTTP/1.1 200 OK 
Cache-Control: private, must-revalidate, proxy-revalidate, max-age=60

Let's try to produce such response headers from an ASP.NET web service call:

[WebMethod][ScriptMethod(UseHttpGet=true)]
public string CachedGet()
{
    TimeSpan cacheDuration = TimeSpan.FromMinutes(1);
    Context.Response.Cache.SetCacheability(HttpCacheability.Public);
    Context.Response.Cache.SetExpires(DateTime.Now.Add(cacheDuration));
    Context.Response.Cache.SetMaxAge(cacheDuration);
    Context.Response.Cache.AppendCacheExtension(
           "must-revalidate, proxy-revalidate");

    return DateTime.Now.ToString();
}

This will result in the following response headers:

The Expires header is set properly. But the problem is with the Cache-control. It is showing that "max-age" is set to zero which will prevent the browser from doing any kind of caching. If you seriously want to prevent caching, you should emit such a cache-control header. Looks like exactly the opposite thing happened.

The output is as usual incorrect, and not cached:

There's a bug in ASP.NET 2.0 that you cannot change the "max-age" header. As max-age is set to zero, ASP.NET 2.0 sets the Cache-control to private because max-age = 0 means no cache is needed. So, there's no way you can make ASP.NET 2.0 return proper headers which caches the response.

Time for a hack. After decompiling the code of the HttpCachePolicy class (Context.Response.Cache object's class), I found the following code:

Somehow, this._maxAge is getting set to zero and the check: "if (!this._isMaxAgeSet || (delta < this._maxAge))" is preventing it from getting set to a bigger value. Due to this problem, we need to bypass the SetMaxAge function and set the value of the _maxAge field directly, using Reflection.

[WebMethod][ScriptMethod(UseHttpGet=true)]
public string CachedGet2()
{
    TimeSpan cacheDuration = TimeSpan.FromMinutes(1);

    FieldInfo maxAge = Context.Response.Cache.GetType().GetField("_maxAge", 
        BindingFlags.Instance|BindingFlags.NonPublic);
    maxAge.SetValue(Context.Response.Cache, cacheDuration);

    Context.Response.Cache.SetCacheability(HttpCacheability.Public);
    Context.Response.Cache.SetExpires(DateTime.Now.Add(cacheDuration));
    Context.Response.Cache.AppendCacheExtension(
            "must-revalidate, proxy-revalidate");

    return DateTime.Now.ToString();
}

This will return the following headers:

Now max-age is set to 60 and thus the browser will cache the response for 60 seconds. If you make the same call again within 60 seconds, it will return the same response. Here's a test output which shows the date time returned from the server:

After 1 minute, the cache expires and the browser makes a call to the server again. The client side code is like this:

function testCache()
{
    TestService.CachedGet(function(result)
    {
        debug.trace(result);
    });
}

There's another problem to solve. In web.config, you will see ASP.NET Ajax will add:

        <system.web>
        <trust level="Medium"/>

This prevents us from setting _maxAge field of Response object because it requires Reflection. So, you will have to remove this trust level or put Full.

    <system.web> 
    <trust level="Full"/>

When 'this' is not really 'this'

Atlas callbacks are not executed on the same context where they are called. For example, if you are making a Web method call from a JavaScript class like this:

function SampleClass()
{
    this.id = 1;
    this.call = function()
    {
        TestService.DoSomething( "Hi", function(result)
        {
            debug.dump( this.id );
        } );
    }
}

What happens when you call the "call" method? Do you get "1" on the debug console? No, you get "null" on the debug console because "this" is no longer the instance of the class. This is a common mistake everyone makes. As this is not yet documented in Atlas documentations, I have seen many developers spend time finding out what's wrong.

Here's the reason. We know whenever JavaScript events are raised, "this" refers to the HTML element which produced the event. So, if you do this:

function SampleClass()
{
    this.id = 1;
    this.call = function()
    {
        TestService.DoSomething( "Hi", function(result)
        {
            debug.dump( this.id );
        } );
    }
}

<input type="button" id="ButtonID" onclick="o.onclick" />

If you click the button, you see "ButtonID" instead of "1". The reason is that, the button is making the call. So, the call is made within the button object's context and thus "this" maps to the button object.

Similarly, when XML HTTP raises the event onreadystatechanged which Atlas traps and fires the callback, the code execution is still on the XML HTTP's context. It's the XML HTTP object which raises the event. As a result, "this" refers to the XML HTTP object, not your own class where the callback is declared.

In order to make the callback fire on the context of the instance of the class so that "this" refers to the instance of the class, you need to make the following change:

function SampleClass()
{
    this.id = 1;
    this.call = function()
    {
        TestService.DoSomething( "Hi", 
            Function.createDelegate( this, function(result)
        {
            debug.dump( this.id );
        } ) );
    }
}

Here, the Function.createDelegate is used to create a delegate which calls the given function under the "this" context. Function.createDelegate is defined in AtlasRuntime:

Function.createDelegate = function(instance, method) {
    return function() {
        return method.apply(instance, arguments);
    }
}

HTTP POST is slower than HTTP GET but it is default in ASP.NET AJAX

ASP.NET AJAX, by default, makes HTTP POST for all web service calls. HTTP POST is more expensive than HTTP GET. It transmits more bytes over the wire, thus taking precious network time, and it also makes ASP.NET do extra processing on the server end. So, you should use HTTP GET as much as possible. However, HTTP GET does not allow you to pass objects as parameters. You can pass numerics, string, and date only. When you make an HTTP GET call, Atlas builds an encoded URL and makes a hit to that URL. So, you must not pass too much content which makes the URL become larger than 2048 chars. As far as I know, that's what is the max length of any URL.

In order to enable HTTP GET on a web service method, you need to decorate the method with the [ScriptMethod(UseHttpGet=true)] attribute:

[WebMethod] [ScriptMethod(UseHttpGet=true)] 
public string HelloWorld()
{
}

Another problem of POST vs. GET is, POST makes two network roundtrips. When you first make a POST, the web server sends an "HTTP 100 Continue" which means that the web server is ready to accept the content. After that, the browser sends the actual data. So, initiation of a POST request takes more time than GET. Network latency (roundtrip time between your computer and the server) is the biggest concern in AJAX applications because AJAX makes many small calls which needs to be done within milliseconds. Otherwise the application does not feel smooth and creates user annoyance.

Ethereal is a nice tool to see what happens under the hood on POST and GET:

From the above picture, you see that POST requires a confirmation from the web server: "HTTP/1.1 100 Continue" before sending the actual data. After that, it transmits the data. On the other hand, GET transmits the data without waiting for any confirmation.

So, you should use HTTP GET while downloading data from a server like parts of pages, contents in a grid, or a block of text etc. But you should not use HTTP GET to send data to a server like submission of web forms.

Conclusion

The above extreme hacks are already implemented in Pageflakes, not the exact way as mentioned here, but the principles are the same. So, you can happily rely on these techniques. These techniques will save you from many problems that you will probably never realize in your development environment, but people from all over the world will face these problems when you will go for large scale deployment. Having these tricks implemented right from the beginning will save you a lot of development and customer support effort. Keep both eyes on my blog for more tricks to come.

 

阅读(407) | 评论(0)编辑 | 举报

转自http://www.codeproject.com/vista/NetFw3.asp 

.NET Framework 3.0 Buffet

The Main Course

We are now getting closer to the meat of the matter. So stimulate your gustatory buds with slices of the following ingredient dishes of the new framework release:

Dish 1 - .NET Framework 2.0

Well, it’s the same old dish with some new toppings (quite literally). As mentioned earlier, the new .NET framework builds on the previous release. In fact, nothing in version 2.0 of the .NET Framework has been deprecated at all! So all the existing applications created (and of course, the valuable expertise gained) will remain worthwhile, at least for a while : )

While the .NET Framework 2.0 class library is partially superseded by the new components (WF, WCF, and WPF) added in version 3.0, many portions of the original class library are still crucial to developers. The technologies of version 2.0 (ASP.NET, WinForms, ADO.NET, XML etc.) largely remain the elementary part of the new release; however, .NET framework 3.0 developers may now prefer using WPF over Windows Forms for writing a native Windows GUI.

.NET Framework 3.0 components

Figure 1: .NET Framework 3.0 components

Dish 2 - Windows Workflow Foundation (WF)

In the traditional software development approach (excluding the likes of BizTalk), the business process was deeply engraved into the program's logic, thus making that process rather difficult to configure or change. A process-oriented design, driven by a workflow, can be the right approach for a significant pie of such Windows software.

A workflow is nothing but a sequence of activities performed in a specific order. WF provides such a common workflow technology for Windows, by virtue of which each step in a process can be explicitly defined (rather than intertwining its logic in code) and then executed by a workflow engine. Each activity can be represented by a class, and can per se contain any work that the workflow's creator wants. Activities can thus also be reused across different workflows, making it easier to create automated solutions to new problems.

WF broadly comprises of the following assorted components:

  1. Activity: A unit of work ranging from very simple to quite complex.
  2. Workflow: A group of activities that partially or completely implements a business process.
  3. WF Designers: The graphical tools to create and modify workflows and activities.
  4. WF Base Activity Library: A fundamental group of activities (IfElse, While, Listen etc. design constructs) used to create workflows. These are quite similar to the BizTalk Orchestration shapes.
  5. WF Runtime Engine: A library that executes workflows. It also provides other services, such as communicating with software outside the workflow.
  6. Host process: A Windows application that hosts the Windows Workflow Foundation runtime engine, workflows, and runtime services for persisting a workflow's state, handling transactions, etc.

WF provides the Workflow Designer, a Visual Studio-hosted graphical tool for creating workflows. The activities in a workflow can be drawn using the Base Activity Library (BAL) provided with WF.

Workflow Designer

Figure 2: Workflow Designer hosted in Visual Studio 2005

By providing such a simplified workflow technology for Windows, the .NET Framework 3.0 has mustered up a useful paradigm for building software. So as the process-oriented view of software will eventually gain popularity, the use of workflow will keep growing as well.

Dish 3 - Windows Communication Foundation (WCF)

However applications are built (using workflow or otherwise), most of them need to communicate with each other. This inter-application communication has taken a big leap forward in the last few years. After a perpetual era of disagreement, all of the major vendors agreed to support SOAP based Web services which makes interoperability between applications built on different technology platforms, such as J2EE and the .NET Framework, significantly simpler. So, this also makes the idea of service-oriented architecture much more plausible for most organizations.

A lot of communication approaches exist in the .NET Framework 2.0 such as ASP.NET Web Services, .NET Remoting, System.Messaging supporting queued messaging through MSMQ, Web Services Enhancements (WSE) - an extension to ASP.NET Web Services that supports WS-Security etc. However, instead of requiring developers to use a different technology with a different application programming interface for each kind of communication, WCF provides a common approach and API. "WCF is actually an old wine in new bottle", and was previously called as Indigo. In the .NET Framework 3.0 environment, most applications that might have used one of the communication technologies listed above will instead use WCF.

WCF provides strong support for interoperable communication through SOAP. This includes support for several specifications, including WS-Security, WS-ReliableMessaging, and WS-AtomicTransaction. WCF doesn't itself require SOAP, so other approaches can also be used, including optimized binary protocol and queued messaging using MSMQ. WCF also takes an explicit service-oriented approach to communication, and loosens some of the tight couplings that can exist in distributed object systems, making interaction less error-prone and easier to change. Thus, WCF addresses a range of communication problems for applications. Three of its most important aspects that clearly stand out are:

  1. Unification of Microsoft’s communication technologies.
  2. Support for cross-vendor interoperability, including reliability, security, and transactions.
  3. Rich support for service orientation development.

To sum up, communication between applications, whether within an organization or across, is a fundamental part of any modern software. The .NET Framework 3.0 attempts to address enduring communication challenges by using the service-oriented approach of WCF.

Dish 4 - Windows CardSpace (WCS)

Digital identities are the way how people electronically represent themselves today on the Internet. In the majority of cases, a person's digital identity is expressed as a simple username, and when its combined with a password, it is used to access web sites, email servers, e-merchants, online banks etc. Yet, despite their simplicity and popularity, usernames and passwords haunt people. Many of us have a hard time remembering all of the usernames and passwords of different sites. Thus, some people use the same values for different sites, easing the memory problem but increasing the security risk.

Usernames, passwords, and other personal information can be stolen by phishers. By sending delusory emails, phishers entice their victims to log in to their Web site that looks just like, say, the site of the victim's bank. So once the victim enters his username and password, the phisher can use this information to masquerade as the user on the real site.

Reducing occurrences and severity of these problems requires an entirely new approach to managing digital identities. WCS (originally called InfoCard) provides this. It helps people keep track of their digital identities as distinct information cards. If a Web site accepts WCS logins, users attempting to log in to that site will see a WCS selection. By choosing a card, users also choose a digital identity that will be used to access this site. Rather than remembering a plethora of usernames and passwords, users need only recognize the card they wish to use.

The identities represented by these cards are created by one or more identity providers. These identities will typically use stronger cryptographic mechanisms to allow users to prove their identity. WCS itself also includes a self-issued identity provider that runs on client machines. With this provider, users can create their own identities that don't rely on passwords for authentication.

So if passwords aren't used to log in to a site, phishers can inflict no harm either. Well, not really! Phishers, if somehow, can trick a user to log into a bogus site, might be still able to acquire personal information of the user, such as sensitive medical information etc. Preventing this requires that users be able to distinguish real sites from the look-alike fakes created by phishers. To allow this, the organization that owns a Web site can get a high-assurance certificate. Unlike today's simple SSL certificates, acquiring this new kind of certificate involves a much more rigorous process, including stronger proof that the organization applying for it actually is who it claims to be. A high-assurance certificate can also carry a company's logo and other information to help the user correctly determine whether a site using this certificate is legitimate. When a user accesses a new site, WCS always displays the information in that site's certificate using a standard screen. Based on the strength of the certificate received, this screen will indicate different levels of assurance of the site's identity.

Dish 5 - Windows Presentation Foundation (WPF)

User interfaces are an important part of most Windows applications. No matter how much software evolves, traditional menu-driven GUIs are here to stay for some more time. Similarly, the need to display video, run animations, use 2/3D graphics, and work with different document formats also cannot be superseded. And all of this must be possible whether the application is a stand-alone desktop client or is accessed through a Web browser.

So far, all of these aspects of the user interface have been provided in different ways on Windows. For example, a developer needs to use Windows Forms to build a Windows GUI, or HTML/ASPX/Applets/JavaScript etc. to build a web interface, Windows Media Player or software such as Adobe's Flash Player for displaying video etc. The challenge for developers is certainly clear: building a coherent user interface for different kinds of clients using diverse technologies isn't a simple job.

A primary goal of WPF (originally called Avalon) is to address this challenge! By offering a consistent platform for these entire user interface aspects, WPF makes life simpler for developers. By taking a more modern approach, including support for video, animation, 2/3D graphics, and various kinds of documents, WPF can let users work with information in new ways. And by providing a common foundation for desktop clients and browser clients, WPF makes it easier to build applications that address both.

Another challenge that has long faced the creators of user interfaces stems from the different roles required for building effective interfaces. Software developers are needed to create the logic behind the interface, and Designers are required to define the interface's look and feel. Yet older technologies such as Windows Forms are focused entirely on the developer. There's no truly effective way for developers and designers to collaborate. To address this issue, WPF relies on the eXtensible Application Markup Language (XAML). An XML-based language, XAML allows specifying a user interface declaratively rather than in code. This makes it much easier for user interface design tools like MS Expression Blend (originally branded as MS Expression Interactive Designer and code named as Sparkle) to generate and work with an interface specification based on the visual representation created by a designer. Designers will be able to use such tools to create the look of an interface and then have a XAML definition of that interface generated for them. The developer imports this definition into Visual Studio, then creates the logic the interface requires.

Developers can also build a XAML browser application (XBAP) to create a remote client that runs inside a Web browser. Built on the same foundation as a stand-alone WPF application, an XBAP allows presenting the same style of user interface within a downloadable browser application. The best part is that the same code can potentially be used for both kinds of applications, which means that developers no longer need different skill sets for desktop and browser clients. The downloaded XBAP from the Internet runs in a secure sandbox (like Java applets), and thus it limits what the downloaded application can do.

Burp, GUI is a complex but an important part of the modern applications. Through WPF, the .NET Framework 3.0 presents a more complete and consistent solution to the challenges these interfaces present. The goal is to let people who create user interfaces (both developers and designers) effectively collaborate and do their jobs more expeditiously. So beware, because when your boss hears all this, she/he will certainly start expecting more from you.. : ( But I guess, that is the flip side of adopting any new technology.

阅读(448) | 评论(0)编辑 | 举报

  一次就开启了FC6的3D桌面 真是幸运HOHO 。。

  发几个图来秀一下 !-_-

阅读(715) | 评论(2)编辑 | 举报

版权声明:天极是本Blog托管服务提供商。如本文牵涉版权问题,天极不承担相关责任,请版权拥有者直接与文章作者联系解决。
Powered by:

Copyright © 品雨凉秋