論壇收藏整理:ASP/ASP.NET

*********************************************************************
標題:
Web打印,簡單實現
來源:http://community.csdn.net/Expert/topic/2959/2959189.xml?temp=.9849207
*********************************************************************
<!--語言無關 保存成 .HTML 看看-->
<html>
<head>
<meta name=vs_targetSchema content="
http://schemas.microsoft.com/intellisense/ie5
">
<title>看看</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<!--media=print 這個屬性可以在打印時有效-->
<style media=print>
.Noprint{display:none;}
.PageNext{page-break-after: always;}
</style>

<style>
.tdp
{
    border-bottom: 1 solid #000000;
    border-left:  1 solid #000000;
    border-right:  0 solid #ffffff;
    border-top: 0 solid #ffffff;
}
.tabp
{
    border-color: #000000 #000000 #000000 #000000;
    border-style: solid;
    border-top-width: 2px;
    border-right-width: 2px;
    border-bottom-width: 1px;
    border-left-width: 1px;
}
.NOPRINT {
 font-family: "宋體";
 font-size: 9pt;
}

</style>

</head>

<body >
<center class="Noprint" >
  <p>
  <OBJECT  id=WebBrowser  classid=CLSID:8856F961-340A-11D0-A96B-00C04FD705A2  height=0  width=0>
  </OBJECT>
  <input  type=button  value=打印          onclick=document.all.WebBrowser.ExecWB(6,1)>
  <input  type=button  value=直接打印  onclick=document.all.WebBrowser.ExecWB(6,6)>
  <input  type=button  value=頁面設置  onclick=document.all.WebBrowser.ExecWB(8,1)>
</p>
  <p>    <input  type=button  value=打印預覽  onclick=document.all.WebBrowser.ExecWB(7,1)>
    <br/>
    </p>
  <hr align="center" width="90%" size="1" noshade>
</center>

<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0"  class="tabp">
 <tr>
  <td colspan="3" class="tdp">第1頁</td>
    </tr>
 <tr>
   <td width="29%" class="tdp">&nbsp;</td>
   <td width="28%" class="tdp">&nbsp;</td>
      <td width="43%" class="tdp">&nbsp;</td>
  </tr>
 <tr>
   <td colspan="3" class="tdp">&nbsp;</td>
  </tr>
 <tr>
   <td colspan="3" class="tdp"><table width="100%"  border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="50%" class="tdp"><p>這樣的報表</p>
          <p>對一般的要求就夠了。</p></td>
          <td>&nbsp;</td>
        </tr>
      </table></td>
  </tr>
</table>
<hr align="center" width="90%" size="1" noshade class="NOPRINT" >
<!--分頁-->
<div class="PageNext"></div>
<table width="90%" border="0" align="center" cellpadding="2" cellspacing="0"  class="tabp">
  <tr>
    <td class="tdp">第2頁</td>
  </tr>
  <tr>
    <td class="tdp">看到分頁了吧</td>
  </tr>
  <tr>
    <td class="tdp">&nbsp;</td>
  </tr>
  <tr>
    <td class="tdp">&nbsp;</td>
  </tr>
  <tr>
    <td class="tdp"><table width="100%"  border="0" cellspacing="0" cellpadding="0">
        <tr>
          <td width="50%" class="tdp"><p>這樣的報表</p>
              <p>對一般的要求就夠了。</p></td>
          <td>&nbsp;</td>
        </tr>
    </table></td>
  </tr>
</table>
</body>
</html>

*********************************************************************
標題:
session,viewstate,cookies的區別
來源:http://community.csdn.net/Expert/topic/3043/3043099.xml?temp=.2811701
*********************************************************************
ViewState是.Net中提出的狀態保存的一種新途徑(實際上也是老瓶裝新酒);我們知道,傳統的Web程序保存狀態的方式有這樣幾種:
  1、Application 這是Web應用程序生命期中的全局保存區,保存在Application中的數據是全局有效的;在Asp.Net中,有一個應用程序池,其中保存了數個(或數十個)應用程序實例,每一次請求都會從池中取一個實例來處理請求,在請求完畢之前,這個實例不會接受其他請求;這就出現一個問題,同一時間可能存在多個應用程序,也就是多個線程,這些線程都存在訪問Application的可能,所以在對Application中的對象進行處理的時候需要考慮線程同步的問題;實際上Application對象內部實現了一個線程鎖,調用它本身的Add、Remove等方法的時候會自動調用加鎖和解鎖的操作,但是出於性能考慮,對於直接通過索引器或其他方式得到其中的對象並進行操作的過程,Application並沒有自動處理線程同步,需要利用下列類似的代碼來處理:
        Application.Lock();
        ((int)Application["Count"])++;
        Application.Unlock();
    值得注意的是,調用了Lock之後,如果沒有顯示的調用Unlock,那麼在這個請求結束的時候,Application對象會自動解鎖,這樣防止了造成死鎖的問題,但是爲了代碼的健壯性,調用完Lock並且修改完畢應該立即的調用Unlock方法。
Application對象本質上就是一個Hash表,按照鍵值存放了對象,由於對象是全局並且存放在服務器,並且存在多線程同時訪問,所以,Application裏面存放的應該是訪問較多,修改較少並且是全局至少大部分功能會使用的數據,例如計數器或者數據庫連接串等。

  2、Session  在Asp.Net內部,有一個StateApplication來管理Session,實際上就是一個輔助進程,處理Session到期、創建的特殊請求,在收到每一次請求的時候,輔助進程就會調用狀態服務器(可以通過Web.config設置不同的狀態服務器)來獲取Session,如果沒有對應該SessionId的Session,則會新建一個,然後綁定到上下文中(HttpContext);與Asp不同的是,Session的狀態服務器有多種,目前在Asp.Net內部實現了三種:
      1) InProcStateClientManager 這是傳統的Session保存方式,但是還是有些細微差別
      2) SqlStateClientManager 這是將Session保存到數據庫方式
      3) OutOfProcStateClientManager 這是將Session保存到進程外的方式
    Asp.Net的Session機制有一個特點,就是處理Session的輔助進程與保存Session的狀態服務器是分開的,按照MSDN的說法,有下列好處:
      “因爲用於會話狀態的內存不在 ASP.NET 輔助進程中,所以可以實現從應用程序故障的恢復。”
      “因爲所有狀態與輔助進程不存儲在一起,您可以乾淨地跨多個進程對應用程序進行分區。這種分區可以顯著地提高多個進程的計算機上應用程序的可用性和可縮放性。”
      “因爲所有狀態與輔助進程不存儲在一起,所以您可以跨運行於多個計算機上的多個輔助進程對應用程序進行分區。”
Asp.Net的Session機制個人觀點,感覺靈活性比較好,內部實現也比較巧妙,但是實際上因爲沒有做過多的測試,所以應用上會不會像它說的那麼美好,不敢打包票。有機會,我會單獨寫篇文章來深入的探討Asp.Net 內部的Session機制。

  3、Cookie  這個沒甚麼好說,實際上Asp.Net與Asp的Cookie沒甚麼分別,也許這項技術譭譽參半,而且比較依賴客戶機實現,MS也沒什麼改進的。

  4、ViewState 這是我們今天重點討論的;實際上ViewState並不神祕,就是一個Hidden字段,但是它是服務器控件狀態保存的基礎;不熟悉的朋友可以用IE查看Html源碼,找到一個名爲"__VIEWSTATE"的Hidden字段,其中有一大堆亂七八糟的字符,這就是頁面的ViewState。

     做過Web程序的人可能都有這種痛苦的體會,有時候爲了處理頁面上面比較複雜的功能,常常會加很多Hidden,然後在服務器端用一大堆判斷來分析目前的狀態,寫起來煩人,寫完了代碼更是難看;實際上,ViewState就是幫我們系統的實現了保存控件狀態的功能,服務器端控件能夠在多次請求間保存狀態也全靠它。

   好,介紹就到這裏,今天我們不是討論ViewState的使用,而是從內部來探探這個東西的本質。
  我們首先建一個測試的頁面:
  <%@ Page language="c#" Codebehind="ViewStateTest.aspx.cs" AutoEventWireup="false" Inherits="CsdnTest.ViewStateTest" %>
  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
  <html>
    <head>
  <title>ViewStateTest</title>
  <meta name="GENERATOR" Content="Microsoft Visual Studio 7.0">
  <meta name="CODE_LANGUAGE" Content="C#">
  <meta name="vs_defaultClientScript" content="JavaScript">
  <meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
    </head>
 <body>
  <form id="ViewStateTest" method="post" runat="server">
  <asp:Button ID="btnPostBack" Runat="server" Text="Post Back" Width="85px"></asp:Button>
  <br/>
  <asp:CheckBox ID="chkTest" Runat="server" Text="This is a check box"></asp:CheckBox>
  </form>
 </body>
  </html>

   這是用Vs.Net設計出來的一個簡單的頁面,裏面包含了一個服務器端的按鈕和一個CheckBox,然後我們在服務器端響應按鈕的事件:

   private void btnPostBack_Click(object sender, System.EventArgs e)
   {
 [1] Response.Write( "ViewState :"+Request.Params["__VIEWSTATE"]+"<br/>" );
  
 [2] string decodeValue = Encoding.UTF8.GetString( Convert.FromBase64String( Request.Params["__VIEWSTATE"] ) );
    
 [3] Response.Write( "ViewState decode :"+decodeValue+"<br/>" );

 [4] object viewstate = (new LosFormatter()).Deserialize( Request.Params["__VIEWSTATE"] );
 
 [5] Response.Write( "ViewState Object :"+viewstate.GetType().Name );
   }

   爲了方便看,我加上了行號;第一行我們把ViewState的值打出來,第二行是什麼呢?實際上ViewState保存到客戶端的一串字符串就是內部的ViewState通過某種方式序列化之後再經過Base64編碼得來的,所以我們把Base64編碼的字符串反編碼一次再打出來;至於第四行,我先不說,先看執行結果:
   運行之後,頁面上什麼都沒有,除了按鈕和CheckBox(廢話 :)),我們點擊按鈕,然後結果如下:

  [A]   ViewState :dDwxMjU2MDI5MTA3OztsPGNoa1Rlc3Q7Pj6Gg0Qzm+7gacYWcy0hnRCT9toOdA==
  [B]   ViewState decode:t<1256029107;;l>D3i s-! t
  [C]   ViewState Object :Triplet

   然後我們來分析這個結果,A中顯示的就是ViewState傳到客戶端的值,B中顯示的是通過Base64反編碼之後的值,從這裏面好像還是看不出什麼,C中出現了一個:Triplet ?這是什麼呢,我們回到上面的代碼:
      object viewstate = (new LosFormatter()).Deserialize( Request.Params["__VIEWSTATE"] );

   注意我們使用了一個LosFormatter類,實際上這個類就是Asp.Net內部爲ViewState提供序列化的類,它有兩個方法,一個是Serialize,就是序列化一個對象,一個是Deserialize,是反序列化,我們這裏使用了反序列化的方法來把ViewState直接反序列化成一個對象,然後把這個對象的類型打出來,這個對象就是:Triplet類型,實際上Asp.Net中頁面保存的ViewState就是這個類型,我們先分析一下LosFormater,再來細說.
   我們再回來看打出來的結果B:t<1256029107;;l>D3i s-! 
t,實際上通過查看LosFormatter反編譯後的代碼,大致上可以看出它序列化的方式是很簡單的,就是判斷要序列化對象的類型,如果不是直接序列化的類型,則把它的類型記錄下來,然後在遞歸序列化它的屬性,我們看B中的"t"就是表示Triplet這個類型,這個類型有三個屬性,這三個屬性包含在"<"和">"之間,用";"分割,而最後面的D3i s-! 
t據我分析應該是一個防止ViewState被改變的Hash值,這個不是很確定,因爲反編譯的代碼實在是很難看,我只是瞭解之後就沒仔細看了。

   我們剛剛分析出來Page中的ViewState反序列化之後是Triplet這個類型,實際上這個類在MSDN中就查得到,它就是一個包含了三個對象的對象,說簡單點,它就是一個能放三個箱子的大箱子(好像還是說的比較糊塗,呵呵),它有三個屬性:First、Second、Thrid :),分別代表三個對象。
   對應到Page當中,First是Page.GetTypeHashCode()的返回值,這個方法是System.Web.UI.Page定義的一個保護的虛擬方法,返回一個整型,由Aspx文件生成的類來實現的,因爲這個類是有Asp.Net負責在運行期生成源代碼並編譯,它會計算出一個大常量作爲返回值,這個返回值在整個Web應用程序所有的Page中是唯一的。(提一句題外話,Asp.Net自動產生的源代碼可以到 系統盤:/WINDOWS/Microsoft.NET/Framework/v1.0.3705/Temporary ASP.NET Files下面去找),這個唯一的Hash值是爲了在ViewState中產生一個標記,使這個ViewState只適用與對應的頁面。
   Second則是通Control.SaveViewStateRecursive方法遞歸保存頁面控件樹的ViewState返回的對象,也就是真正的ViewState的數據。
   Third中保存的是當前頁面需要PostBack的控件名的列表。

分析了頁面的ViewState的構成,我們再來看Control的ViewState的實現。ViewState是System.Web.UI.Control類實現的一個屬性,這個屬性的類型是System.Web.UI.StateBag,這個類就包含了ViewState數據結構的實現,實際上它的內部也就是個Hash表,通過Key值來保存和檢索數據。
  那麼服務器控件是怎麼實現保存狀態的呢?
  我們知道,所有的服務器控件都是從System.Web.UI.Control派生的,所以都擁有ViewState這個屬性,在Control內部,定義了兩個Protected的虛擬方法:
    protected virtual object SaveViewState()
  和
protected virtual void LoadViewState(object savedState)

  這兩個方法是給子控件派生用來保存和讀取自己的ViewState的,比如我們有一個自己寫的控件,往ViewState中保存了一個字符串,那麼我們的方法大致像這樣:
    protected virtual object SaveViewState()
    {
       object[] states = new object[2];
       states[0] = base.SaveViewState();      //記得保存父控件的ViewState
       states[1] = "Hello,I'm timmy!";        //這裏保存我們自己的
     
       return states; //返回重新包裝後的保存對象
    }
    獲取的時候:
    protected override void LoadViewState(object savedState)  //這裏的savedState就是我們Save的時候return 的object數組
    {
       object[] states = (object[])savedState;
       base.LoadViewState( states[0] );   //把父類的數據給他自己去解析
       string myData = (string)states[1];  //獲取我們自己的數據
    }
   我們可以按照自己的方式來保存,不一定非要像上面這樣用數組,實際上我們可以用任何支持序列化的對象都可以,父類並不關心子類如何保存,我們只要在Save和Load的時候使用同樣的方式,並且把正確的數據傳遞給父類方法就可以了。
  
   另外,還有一個問題就是我們使用的Control的ViewState是Key-Value這樣的鍵值對,那它是怎麼保存的呢?
   實際上很簡單,System.UI.Web下面有一個類叫Pair,呵呵,這個和Triplet差不多,只是它裏面只有兩個對象。StateBag保存的時候,First會存放所有Key值的數組,Second則存放所有Value的數組。

   到現在,我們瞭解了ViewState是如何序列化並且保存到客戶端,也瞭解了控件怎麼保存自己的ViewState,那麼這二者是怎麼結合的呢?

也就是整個頁面的控件樹的ViewState是怎麼保存和讀取的呢?

   在Control內部有兩個internal的方法:
   internal object SaveViewStateRecursive();
   internal void LoadRecursive();
   這兩個方法由System.Web.UI.Page來調用,Page在Render結束後就會調用SavePageViewState方法,SavePageViewState方法會調用Control的SaveViewStateRecursive()方法,這個方法就是通過遞歸調用每一個Control.Controls的SaveViewStateRecursive方法來保存控件樹中所有控件的ViewState。到這裏,可能聰明的朋友要問了,既然SaveViewStateRecursive是遞歸調用保存的方法,那麼我們上面寫的SaveViewState()方法又有什麼用呢?
   我們知道,Control.Controls可能會有很多個,而且我們的SaveViewState()只保存了當前控件的數據,而沒有記錄控件樹的結構,那麼如果我們遞歸SaveViewState()方法來保存數據的話,那麼控件樹的結構就會丟失,那麼Load的時候就沒辦法還原了,實際上在SaveViewStateRecursive方法中大致的代碼是這樣:
    [1] 獲取控件自己的ViewState(調用SaveViewState方法)
    [2] 循環子控件
     {
         定義兩個動態數組,一個保存控件的索引,一個保存遞歸調用子控件SaveViewStateRecursive方法返回的值
     }
    [3] 定義一個Triplet(呵呵,這個東西又出現了)
    [4] First保存本控件的ViewState
    [5] Second保存子控件的索引
    [6] Third保存遞歸子控件SaveViewStateRecursive方法的返回值
    [7] 返回Triplet
   這樣就保存了整個控件樹的ViewState和控件樹的結構

   Load的方式與Save差不多,只是Load的時候會從savedState中獲取子控件的索引來依次遞歸子控件的LoadRecursive()方法,這樣才能保證正確的把保存的數據傳給子控件。


   到這裏,ViewState的實現我們大致瞭解了一下,最後得出一些結論:
   1、ViewState是存放在客戶端,因此會減輕服務器的負擔,是一種比較好的保存數據的方式。
   2、因爲ViewState本身的限制,只能保存可以序列化的對象,而且最好不要放太多東西,能省則省,以免在減慢傳輸的速度,以及加重服務器解析的負擔。
   3、我們通過很簡單的方式就可以把ViewState裏面的值獲取出來,我們上面討論了一些,雖然沒有把解析的代碼寫出來,但是利用LosFormatter可以得到ViewState反序列化後的對象,那麼要解析出來簡直是易如反掌;所以ViewState在安全性上面還是比較差,建議不要
存放比較機密和敏感的信息,儘管ViewState可以加密,但是由於ViewState要保存在客戶端,天生就有安全性的隱患。
   4、實際從技術角度,ViewState沒有任何新意,但是結合服務器控件的設計還是很巧妙的。
  
   最後,以我個人的觀點,我覺得ViewState的出現很大程度上減輕了程序員的負擔,但是要看清的是ViewState的本質,合理的應用它。

*********************************************************************
標題:
不是縮略圖,但可以按比例縮小,在產品列表中很實用。
來源:http://community.csdn.net/Expert/topic/3111/3111151.xml?temp=.9140741
*********************************************************************
<%
Class possible
 dim aso
 Private Sub Class_Initialize
  set aso=CreateObject("Adodb.Stream")
  aso.Mode=3
  aso.Type=1
  aso.Open
 End Sub
 Private Sub Class_Terminate
  set aso=nothing
 End Sub

 Private Function Bin2Str(Bin)
  Dim I, Str
  For I=1 to LenB(Bin)
   clow=MidB(Bin,I,1)
   if ASCB(clow)<128 then
    Str = Str & Chr(ASCB(clow))
   else
    I=I+1
    if I <= LenB(Bin) then Str = Str & Chr(ASCW(MidB(Bin,I,1)&clow))
   end if
  Next
  Bin2Str = Str
 End Function
 
 Private Function Num2Str(num,base,lens)
  dim ret
  ret = ""
  while(num>=base)
   ret = (num mod base) & ret
   num = (num - num mod base)/base
  wend
  Num2Str = right(string(lens,"0") & num & ret,lens)
 End Function
 
 Private Function Str2Num(str,base)
  dim ret
  ret = 0
  for i=1 to len(str)
   ret = ret *base + cint(mid(str,i,1))
  next
  Str2Num=ret
 End Function
 
 Private Function BinVal(bin)
  dim ret
  ret = 0
  for i = lenb(bin) to 1 step -1
   ret = ret *256 + ascb(midb(bin,i,1))
  next
  BinVal=ret
 End Function
 
 Private Function BinVal2(bin)
  dim ret
  ret = 0
  for i = 1 to lenb(bin)
   ret = ret *256 + ascb(midb(bin,i,1))
  next
  BinVal2=ret
 End Function
 
 Private Function getImageSize(filespec)
  dim ret(3)
  aso.LoadFromFile(filespec)
  bFlag=aso.read(3)
  select case hex(binVal(bFlag))
  case "4E5089":
   aso.read(15)
   ret(0)="PNG"
   ret(1)=BinVal2(aso.read(2))
   aso.read(2)
   ret(2)=BinVal2(aso.read(2))
  case "464947":
   aso.read(3)
   ret(0)="GIF"
   ret(1)=BinVal(aso.read(2))
   ret(2)=BinVal(aso.read(2))
  case "535746":
   aso.read(5)
   binData=aso.Read(1)
   sConv=Num2Str(ascb(binData),2 ,8)
   nBits=Str2Num(left(sConv,5),2)
   sConv=mid(sConv,6)
   while(len(sConv)<nBits*4)
    binData=aso.Read(1)
    sConv=sConv&Num2Str(ascb(binData),2 ,8)
   wend
   ret(0)="SWF"
   ret(1)=int(abs(Str2Num(mid(sConv,1*nBits+1,nBits),2)-Str2Num(mid(sConv,0*nBits+1,nBits),2))/20)
   ret(2)=int(abs(Str2Num(mid(sConv,3*nBits+1,nBits),2)-Str2Num(mid(sConv,2*nBits+1,nBits),2))/20)
  case "FFD8FF":
   do
    do: p1=binVal(aso.Read(1)): loop while p1=255 and not aso.EOS
    if p1>191 and p1<196 then exit do else aso.read(binval2(aso.Read(2))-2)
    do:p1=binVal(aso.Read(1)):loop while p1<255 and not aso.EOS
   loop while true
   aso.Read(3)
   ret(0)="JPG"
   ret(2)=binval2(aso.Read(2))
   ret(1)=binval2(aso.Read(2))
  case else:
   if left(Bin2Str(bFlag),2)="BM" then
    aso.Read(15)
    ret(0)="BMP"
    ret(1)=binval(aso.Read(4))
    ret(2)=binval(aso.Read(4))
   else
    ret(0)=""
   end if
  end select
  ret(3)="width=""" & ret(1) &""" height=""" & ret(2) &""""
  getimagesize=ret
 End Function
 
 Function readX(pic_path)
   Set fso1 = server.CreateObject("Scripting.FileSystemObject")
   Set f1 = fso1.GetFile(pic_path)
   ext=fso1.GetExtensionName(pic_path)
   select case ext
     case "gif","bmp","jpg","png":
    arr=getImageSize(f1.path)
    Response.Write arr(1)
     case "swf"
    arr=pp.getimagesize(f1.path)
    Response.Write arr(1)
   end select
   Set f1=nothing
   Set fso1=nothing
 End Function

 Function readY(pic_path)
   Set fso1 = server.CreateObject("Scripting.FileSystemObject")
   Set f1 = fso1.GetFile(pic_path)
   ext=fso1.GetExtensionName(pic_path)
   select case ext
     case "gif","bmp","jpg","png":
    arr=getImageSize(f1.path)
    Response.Write arr(2)
     case "swf"
    arr=pp.getimagesize(f1.path)
    Response.Write arr(2)
   end select
   Set f1=nothing
   Set fso1=nothing
 End Function
End Class
%>

例子:

<!--#include file="picXY.asp"-->
<%
 set pp=new possible
 pp.readX("E:/work/bg.jpg")
 pp.readY("E:/work/bg.jpg")
%>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章