| ASP.NET是微软.NET宏大战略的一部分。我们不能仅仅将它看成是ASP语言的进化版本,它所能发挥的威力将使开发人员激动与惊喜,更快、更好地实现梦想!本文就介绍ASP.NET的几个常用实例,通过与ASP语言实现方式的对比,让我们对它的强大眼见为实!实例内容(包括下载代码)如下: |
| |
| 要运行这些例程,需要在Web服务器上安装Microsoft .NET Framework SDK。要理解代码的含义,需要对C# 编程语言有一定程度的了解。 |
| |
| 在用ASP语言编程的"美好旧时光"中,我们应该不会忘记FileSystemObject对象。它允许对文件系统进行读、写以及目录浏览。但是这个对象模型并不十分完善,比如对于二进制文件来说,还没有开始操作就已经到达范围的结尾了。另外,还有一些希望的函数和属性在ASP中也没有具备。 |
| 但是出现了ASP.NET,这些愿望就都能在System.IO 名称空间中被 .NET Framework 类所实现。你会发现,文件处理从没有这么容易过,而且最重要的是从没有这么强大过。 |
| 这里,我们将演示文件处理的一个部分:文件和目录列表。我们创建了一些脚本程序,你可以将其应用在自己的应用程序中。 |
| 首先,我们要知道在计算机上有哪些可浏览的驱动器,这些代码保存在文件listdrives.aspx中: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.IO" %> |
| string[] achDrives = Directory.GetLogicalDrives(); |
| int nNumOfDrives = achDrives.Length; |
| for (int i=0; i < nNumOfDrives; i++) |
| Response.Write("<li><a href=\"listdir.aspx?dir="); |
| Response.Write(Server.UrlEncode(achDrives[i])); |
| Response.Write("\">" + achDrives[i]); |
| Response.Write("</a><br>"); |
| 根据 @Import 名称空间标识,在System.IO 名空间中有一个类叫做Directory,它包含了一些可用于目录上的功能。这个类中还包含静态(不需要对象例示就能调用的)方法GetLogicalDrives,它提供了包含驱动器字母的一个字符串数列。 |
| 当然,不能只有一个从GetLogicalDrives 获取的驱动器简单列表,还需要增加了一个页面,在这个页面中提供有关驱动器根目录的信息。 |
| 有了目录,我们就可以进一步探索子目录、文件以及目录本身的属性(如创建的日期等)了。文件 listdir.aspx 演示了如何执行这些功能: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.IO" %> |
| string strDir2List = Request.QueryString.Get("dir"); |
| Directory thisOne = null; |
| thisOne = new Directory(strDir2List); |
| // Reading the directory properties |
| Response.Write("<p>Creation: " + |
| thisOne.CreationTime.ToString() + "</p>"); |
| Directory[] subDirectories = thisOne.GetDirectories(); |
| for (int i=0; i < subDirectories.Length; i++) |
| Response.Write("<li><a href=\"listdir.aspx?dir="); |
| Response.Write(Server.UrlEncode(subDirectories[i].FullName)); |
| Response.Write("\">" + subDirectories[i].Name); |
| Response.Write("</a><br>"); |
| File[] theFiles = thisOne.GetFiles(); |
| for (int i=0; i < theFiles.Length; i++) |
| Response.Write("<li><a href=\"showfile.aspx?file="); |
| Response.Write(Server.UrlEncode(theFiles[i].FullName)); |
| Response.Write("\">" + theFiles[i].Name); |
| Response.Write("</a><br>"); |
| Response.Write("Access not possible, error: <i>"); |
| Response.Write(e.ToString() + "</i>"); |
| 我们使用GetDirectories方法实现目录信息的读取。这个方法返回一个目录对象数组,我们可以用这个数组来建立想要的功能,比如说建立一个更深入的链接。这同样适用于GetFiles方法,它返回一个文件对象数组。 |
| 你可能注意到这里使用了try-catch语句。是的,这是为了防止例外情况的发生。比如,当用户试图访问一些不允许他访问的内容时。 |
| 现在到了文件这一级。一个文件有许多属性,为了缩短脚本,下面的例程(文件showfile.aspx)只显示了其中的一些: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.IO" %> |
| <head><title>File Info</title></head> |
| string strFile2Show = Request.QueryString.Get("file"); |
| File thisOne = new File(strFile2Show); |
| <tr><td>Name:</td><td><%=thisOne.Name%></td></tr> |
| <tr><td>Path:</td><td><%=thisOne.FullName%></td></tr> |
| <tr><td>Directory:</td><td><%=thisOne.DirectoryName%></td></tr> |
| <td><%=thisOne.CreationTime.ToString()%></td> |
| <td><%=thisOne.Length.ToString()%> Bytes</td> |
| <td><%=thisOne.LastAccessTime.ToString()%></td> |
| <td><%=thisOne.LastWriteTime.ToString()%></td> |
| <--下吧学习频道[http://123.xia8.com]--> |
| StreamReader theReader = thisOne.OpenText(); |
| char[] theBuffer = new char[255]; |
| int nRead = theReader.ReadBlock(theBuffer, 0, 255); |
| Response.Write(Server.HtmlEncode(new String(theBuffer,0,nRead))); |
| Response.Write("</pre>"); |
| 为了演示实现的简单性,在这段脚本代码的结尾处抄了个近路执行文件的读取。首先,打开一个 StreamReader 对象,创建一个缓冲器,用ReadBlock方法来填充缓冲器,并且将 HTML编码段传递给客户;然后很快地就形成了一个小型的"文件预览"。没有费多大周折,你看操作文件的内容是多么得简单 :-) |
| 最后,我们还要编写一个创建目录树的程序recursivelisting.aspx。在其中,我们使用函数RecursiveDump来生成目录树。请看具体代码: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.IO" %> |
| string strDir2List = Request.QueryString.Get("dir"); |
| Directory thisOne = new Directory(strDir2List); |
| RecursiveDump(thisOne, 0); |
| Response.Write("</pre>"); |
| <script language="C#" runat="server"> |
| void RecursiveDump(Directory theDir, int nLevel) |
| Directory[] subDirectories = theDir.GetDirectories(); |
| for (int i=0; i < subDirectories.Length; i++) |
| Response.Write(new String(' ',nLevel)); |
| Response.Write(subDirectories[i].Name + "\r\n"); |
| RecursiveDump(subDirectories[i], nLevel+1); |
| 为了简单起见,这里只使用了空格来生成目录树结构。为使空格在HTML中可以生效,我们必须使用<PRE>标记,否则这些空格就会被忽视。 |
| 函数本身有两个参数:一个是目录对象,一个是整数变量以指示当前级别。在当前级别中,用 GetDirectories读取子目录信息,然后在一个 for循环中显示它。对于每个Directory对象, 都调用 RecursiveDump函数,然后级别加1。 |
| 注意:列举整个驱动器会花费很多时间。最后,让我们来看看浏览器中的执行结果: |
|

|
| 本文介绍了System.IO 名称空间中的两个对象:Directory和 File。虽然"只"用它们简单显示了目录和文件信息,但我们要知道:这两个对象是执行文件处理的基础。 |
=================================================================
| 如果没有一个外部组件的支持,在ASP中是不能动态创建图形的,不管它是一个图表,一个横幅或仅仅是一个图形计数器。可喜的是,这一点在ASP.NET中改变了。现在,我们只需要使用内置功能,就能够很容易动态创建图形,并向客户端发送具有最佳配置的图形。 |
| 在讨论一大堆ASP.NET代码之前,我们先执行一个简单的命令行程序做一个测试,然后使用这些源代码作为 ASP.NET 脚本的基础。实际上,两者的区别在于:命令行程序将图形保存在一个文件中,而ASP.NET 脚本将图形直接发送到客户端。 |
| 举例的程序做什么呢?按照惯例,我们从众所周知的"Hello World" 程序开始,把这个文本信息输出到一个图形文件中,这个图形的大小要与当前选中的 "Hello World" 文本的字体和字号完全相同。 |
| 下面的脚本pagecounter.cs是一个典型的简单命令行程序:如果忽略包围在其周围的必须的类代码,就只剩下程序运行时要调用的主函数了,这也正是生成图形的代码所在处: |
| using System.Drawing.Imaging; |
| public class CTestBitmapFunctionality |
| public static void Main() |
| Font fontCounter = new Font("Lucida Sans Unicode", 12); |
| // calculate size of the string. |
| newBitmap = new Bitmap(1,1,PixelFormat.Format32bppARGB); |
| g = Graphics.FromImage(newBitmap); |
| SizeF stringSize = g.MeasureString("Hello World", fontCounter); |
| int nWidth = (int)stringSize.Width; |
| int nHeight = (int)stringSize.Height; |
| newBitmap = new Bitmap(nWidth,nHeight,PixelFormat.Format32bppARGB); |
| g = Graphics.FromImage(newBitmap); |
| g.FillRectangle(new SolidBrush(Color.White), |
| new Rectangle(0,0,nWidth,nHeight)); |
| g.DrawString("Hello World", fontCounter, |
| new SolidBrush(Color.Black), 0, 0); |
| newBitmap.Save("c:\\test.png", ImageFormat.PNG); |
| Console.WriteLine(e.ToString()); |
| if (null != g) g.Dispose(); |
| if (null != newBitmap) newBitmap.Dispose(); |
| 在任何情况下,执行上面代码后,就会生成下面的图形test.png,它将存放在C驱动器上: |
| 我们来仔细研究一下源代码,看看这个图形是如何创建的。关键一点是生成的图形必须与文本 "Hello World" 的字体和字号相同。因此,首先要计算文本的尺寸,为此我们使用了一个尺寸为1 x 1的虚拟图形。计算结束之后,再废弃这个虚拟图形并生成一个适当尺寸的图形。 |
| 源代码中有一点很有趣,这就是 Graphics 对象。要创建一个位图时,用这个对象做什么呢?奥妙在于:这是可以向其中绘图的上下文环境。我们可以在屏幕上、打印机上和内存中使用一个图形上下文环境,准确地说就是一个位图。图形的上下文环境使我们能够在任何设备上进行绘图操作,甚至是在虚拟设备上。 |
| 接着,用DrawString将文本 "Hello World"按照规格输出到一个白色背景的矩形(用 FillRectangle创建的)中。图形完成后,将其保存在磁盘上。凡是亲自研究过图形文件格式的人都知道这有多困难,但是使用 GDI+ (图形设备接口)就不那么困难了,这只需要下面的简单命令就可以: |
| newBitmap.Save("c:\\test.png", ImageFormat.PNG); |
| 如果用ImageFormat.JPEG替换ImageFormat.PNG,就可以得到一个 jpeg文件。这正是我们所期待的操作图形的最简单用法。 |
| 例外处理代码也很有必要,因为有些函数会造成例外,比如没有足够的内存用来创建位图。而且,不要忘记释放图形和位图,这是编程的良好习惯,有始有终吗!最后,程序结束。 |
| 好了,现在请使用下面的命令将源代码进行编译,生成EXE文件pagecounter.exe,然后在安装了Microsoft .NET框架的系统上测试运行: |
| csc /R:System.DLL /R:System.Drawing.DLL pagecounter.cs |
| 上面的代码作为一个命令行应用程序已经足够了,但是要编写相应的 ASP.NET 脚本,就必须再添加几个功能: |
| 如果你认为这些太难做到了,那么就请先看看相关的ASP.NET 脚本源代码pagecounter.aspx。要提醒的是:增加任意数量的错误处理代码以查看所传递参数的有效性,这是所必须做的修改中最大的一部分。 |
| 另一个需要修改的地方是将图形发送给客户端而不是将它写入一个文件中。这个新部分的代码是这样的: |
| MemoryStream tempStream = new MemoryStream(); |
| newBitmap.Save(tempStream,ImageFormat.PNG); |
| Response.ContentType = "image/png"; |
| Response.BinaryWrite(tempStream.ToArray()); |
| 这里只是将图形"缓存"到内存中,然后将其作为一个字节数组传递给BinaryWrite函数。 |
| 仔细研究了源代码的人会注意到这里将所有可选择参数都作为查询字符串进行了传递,这可能会成为一个很长的尾巴。为了简洁起见,我们建立了一个如下所示的表单,这样就可以测试不同的值: |
| ASP.NET文件pagecountertest.aspx处理比较好的一点是我们可以在同一页面上立刻接收到图形。表单源代码包含了服务器端的ASP.NET控件。 |
| 以上我们快速涵盖了ASP.NET中的图形编程功能,了解到ASP.NET为Web开发人员实现Windows图形编程提供了全套指导。 |
============================================================
| 在Windows 2000 或 NT中,事件日志对于管理员来说几乎是最重要的信息来源,因为所有发生的事件都在那里进行记录,无论是成功的操作,还是灾难性的失败。既然如此,你是否想过让这些信息在Web上呈现出来? 是的,这是很有意义的事情。 |
| 我们都应该很熟悉下面的事件阅读器了,下面就示范如何使用AP.NET和.NET Framework SDK来美观、清晰地模仿其条目列表。我还给读者留下一个练习题,为一个条目的完整细节构造一个页面。 |
| 如果必须又快又粗略地完成任务,那么完全可以利用ASP语言的相关技术来生成一个事件列表(甚至可以用表格,但是这个例子没有那样做)。程序的名字是 simple.aspx,代码如下: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.Diagnostics" %> |
| EventLog aLog = new EventLog(); |
| aLog.MachineName = "."; // Lokale Maschine |
| string strImage = ""; // Icon für das Event |
| Response.Write("<p>There are " + aLog.Entries.Count + |
| " entries in the System event log.</p>"); |
| foreach (EventLogEntry entry in aLog.Entries) |
| case EventLogEntryType.Warning: |
| strImage = "warning.png"; |
| case EventLogEntryType.Error: |
| Response.Write("<img src=\"" + strImage + "\"> | "); |
| Response.Write(entry.TimeGenerated.ToString() + " | "); |
| Response.Write(entry.Source + " | "); |
| Response.Write(entry.EventID.ToString() + "<br>\r\n"); |
| 事件日志类可以在名称空间System.Diagnostics(系统诊断)中找到,这一部分在页面的开始定义。打开日志本身很直观:创建一个新EventLog对象,指定Log 和 MachineName ("." 是本地机器的意思)。到此我们可以读取事件日志的内容了。 |
| 这将在一个 foreach循环中完成。我们在每个条目之前都放置一个图标,这样列表看起来就不至于那么平淡。另外,条目的列表顺序与通常的事件阅读器顺序相反:在这里,最老的条目列在最前面。 |
| ASP.NET带来了许多创新功能,尤其是在显示数据方面。比如,要显示的数据并不总是必须出自数据库。DataGrid Web Control 也是如此,正如其名称所示,它可以创建一个来自数据的表格或者栅格。唯一的前提是数据源要支持Icollection接口,而EventLog (事件日志)的Entries Collection(条目集合 )正是满足这一要求的。 |
| 以下的文件datagrid.aspx演示了使用DataGrid是如何得简单: |
| <% @Page Language="C#" %> |
| <% @Import Namespace="System.Diagnostics" %> |
| <script language="C#" runat="server"> |
| void Page_Load(Object sender, EventArgs e) |
| EventLog aLog = new EventLog(); |
| LogGrid.DataSource = aLog.Entries; |
| <h3>System Event Log</h3> |
| <ASP:DataGrid id="LogGrid" runat="server" |
| HeaderStyle-BackColor="#aaaadd" |
| DataGrid 控件 除了包含格式化指令外,什么也没有。Grid通过Page_Load 事件来填充,它打开事件日志,然后将DataGrid的DataSource属性指定为Entries(条目)。接着调用 DataBind方法,所有的数据就被填入到表格中。 |
| 数据量确实不小,因为 EventLogEntry 类有许多属性,而我们只想要一个简洁的概括。下一部分就将对此进行限定。 |
| 接着的目的是要显示某些特定的字段。在讨论代码前,我们先快速看一下执行后的结果: |
| 从原则上说,这个结果与前面的例子非常相似,唯一的不同就是显示的栏数。这种限定是靠 DataGrid 标记本身进行的,文件speccolsonly.aspx 包含了全部实现代码: |
| <asp:DataGrid id="LogGrid" runat="server" |
| HeaderStyle-BackColor="#aaaadd" |
| AutoGenerateColumns="false"> |
| <property name="Columns"> |
| <asp:BoundColumn HeaderText="TOF" DataField="EntryType" /> |
| <asp:BoundColumn HeaderText="Date/Time" DataField="TimeGenerated"/> |
| <asp:BoundColumn HeaderText="Source" DataField="Source"/> |
| <asp:BoundColumn HeaderText="Event ID" DataField="EventID"/> |
| 第一个重要步骤是将AutoGenerateColumns 属性设置为假,这样就可以防止显示所有属性。接着指定想要显示的栏目,在这里,我们指定了4个栏目。HeaderText显示在顶部行中,DataField给出填充这个栏目所要读取的属性。 |
| 在结束之前,我们还要使用 DataGrid 的另一个功能,也就是 数据库程序员的老相识-"分页"处理。DataGrid的优势在于处理分页几乎不需要代码。还是请先看一下执行后的结果: |
| <% @Page Language="C#" %> |
| <% @Assembly Name="System.Diagnostics" %> |
| <% @Import Namespace="System.Diagnostics" %> |
| <script language="C#" runat="server"> |
| void Page_Load(Object sender, EventArgs e) |
| void LogGrid_Page(Object sender, DataGridPageChangedEventArgs e) |
| EventLog aLog = new EventLog(); |
| LogGrid.DataSource = aLog.Entries; |
| <h3>System Event Log</h3> |
| <asp:DataGrid id="LogGrid" runat="server" |
| PagerStyle-Mode="NumericPages" |
| PagerStyle-HorizontalAlign="Right" |
| PagerStyle-NextPageText="Next" |
| PagerStyle-PrevPageText="Prev" |
| OnPageIndexChanged="LogGrid_Page" |
| HeaderStyle-BackColor="#aaaadd" |
| AutoGenerateColumns="false"> |
| <property name="Columns"> |
| <asp:BoundColumn HeaderText="TOF" DataField="EntryType" /> |
| <asp:BoundColumn HeaderText="Date/Time" DataField="TimeGenerated"/> |
| <asp:BoundColumn HeaderText="Source" DataField="Source"/> |
| <asp:BoundColumn HeaderText="Event ID" DataField="EventID"/> |
| 我们可以看到,第一个变化在 DataGrid控件中: |
| PagerStyle-Mode="NumericPages" |
| PagerStyle-HorizontalAlign="Right" |
| PagerStyle-NextPageText="Next" |
| PagerStyle-PrevPageText="Prev" |
| OnPageIndexChanged="LogGrid_Page" |
| 其中的两个最重要的属性是第一个和最后一个:AllowPaging和 OnPageIndexChanged。第一个激活分页功能,第二个指明当页面变化时所引起事件对应的方法。剩下的属性都是装饰性的。 |
| 当我们使用的是一个数据集合而不是数据库时,可以通过将数据重新捆绑在栅格上而使处理工作变得很容易。 |
| 以上介绍了在ASP.NET中如何阅读事件日志,但这不是主要目的,我们的意图是要说明DataGrid的使用是多么得广泛,这已经超出了数据库编程的主要应用领域。 |
| 以上通过3个实例的实现思路、原理以及具体代码示范了ASP.NET的实际应用。这3个例子都非常典型并且实用,我希望从这里起步,开始你的ASP.NET之神奇、强大的编程旅程。 |

发表评论