简介
ASP.NET 是 Microsoft 新推出的强大的 Web 中间件平台,它同时支持 VB.NET 和 C#.NET 这两种语言。本文展示如何使用 ASP.NET 并通过 IBM 的 RedBack 中间件以一种简单、优雅的方式访问 UniData 或 UniVerse 数据库。
为什么在 ASP.NET 中使用 RedBack 和 RedBack 对象?RedBack 不但有超过 6 年的优异表现,全世界安装了数千个 RedBack,而且,除了在中间层使用 ASP.NET/VB 或 C# 以及在数据库端使用 Basic 以外,RedBack 使您无需使用任何其他语言就可以访问 UniData 或 UniVerse。此外,RedBack 对象具有 Virtural 属性,是可重用的 —— 如果将来您决定使用 PHP 或 JSP 或 XML/Soap,不使用 ASP.NET 或者结合使用 ASP.NET,那么您无需对 RedBack 对象作任何更改。
RedBack 对象
通过 RedBack Designer 工具可以设计带有属性和方法的 RedBack 对象。属性通常是表示数据的占位符(类似于变量),而方法通常是指向 UniBasic 子例程的指针。您可以使用一些主要的 RedBack 对象作为创建自己的对象的模板,这些 RedBack 对象包括:
SLRBO —— 最快的 RedBack 对象,这种非常灵活的、无状态的对象很适合读取单个的记录(或以某种方式界定的多个记录),或者将数据写入到一个或多个文件。它要求您编写执行读或写的方法/子例程。在应用程序中应该尽可能使用这种对象,因为它给系统带来的负载是最轻的。
uQuery —— 有状态的报告对象,对于给定的一个 U2 select 语句,它返回一个记录集。对于这种对象,通常不编写 Basic 代码。当您以一种有状态的方式使用 uQuery 时,可以在中间件中保留对象的一个句柄,然后用它来在多个页上分页显示数据,而不必重做 select 查询。
RedBack 安装
RedBack 文档描述了其在数据库服务器和 Web 服务器上的安装(请参阅 参考资料)。在安装过程中,会安装一个名为 rbexamples 的测试数据库,并配有供访问的数据和 RedBack 对象。本文后面给出的示例代码将使用这些对象来访问 rbexamples。
由于我们要在 Windows 中从 ASP.NET 调用 RedBack 对象,所以我们将在 Web 服务器上使用 RedBack ADO/OLEDB 组件 RedPages.dll 和 rgw.ini 文件来访问 rbexamples 数据库。或者,也可以使用 XML/Soap 请求,但本文对此不予讨论。
RedPages.dll —— 这个 DLL 包含 RedObject 类,通过这个类可以使用 RedBack 对象。示例项目在 Visual Studio 中包含了对这个 dll 的库引用。
rgw.ini —— 这个文件指定 RedBack Responder 的数据库和服务器。将该文件放在根文档目录(wwwroot)或者 WINDOWS 或 WINNT 目录中。该文件包括数据库名,后面是一个空格,再后面是数据库服务器的机器名或 IP 地址,接着是一个冒号和一个端口号,RedBack Responder 在这个端口侦听对数据库的请求。例如: rbexamples my2000:8444
在 Visual Studio.Net 中建立项目
RedPages.dll 是一种 COM 对象,目前支持 ADO/OLEDB (可以从 ASP.NET 调用)。您需要设置 Visual Studio.NET,以便使用一个 ADO.NET 包装器,从而可以使用 RedObject 或 RedField,或者使用 ADO Recordset(例如从一个 uQuery 查询返回的)。
要建立使用 RedBack 的一个 ASP.NET 项目:
打开 Visual Studio.NET 并选择 New Project。
为 Visual Basic/ASP.NET Web Application 输入 Location 和 Name,然后单击 OK。Visual Studio.NET 将在 IIS 中为您的页面创建一个虚拟目录。
图 1. 新建项目
在项目中创建对 RedPages.dll 的一个引用。为此:
在 Solution Explorer 中,右键单击项目下的 References 条目,并选择 Add Reference。这将打开 Add Reference Window。
选择 COM 标签页,向下滚动到 RedPages 1.0 Type Library。双击这个选择项,然后单击 OK。在 Solution Explorer 中,您将看到新添加的引用 REDPAGESlib。
图 2. 添加 IBM U2 RedPages 引用
如果您想使用 Microsoft 的 Recordset,那么创建对它的一个引用。(这是必需的,因为 Recordset 也是一种 ADO COM 对象。)为此:
在 Solution Explorer 中,右键单击项目下的 References 条目,并选择 Add Reference。这将打开 Add Reference Window。
选择 COM 标签页,向下滚动到 Microsoft ActiveX Data Objects Recordset 2.7 Library。双击这个选择项,然后单击 OK。在 Solution Explorer 中,您将看到新添加的引用 ADOR。
图 3. 可选地添加 Microsoft Recordset 引用
用于显示数据库数据的示例表单 —— 使用 VB.NET
下面的 ASP.NET/VB 页面,以及它的 code-behind 页面,建立一个数据库连接,创建一个对象,设置一个关键属性,调用 RedBack 对象的数据库读方法,然后显示返回的属性值。
注意:这个无状态的例子将使用 SLRBO、RBO 或 uObject,但不使用 uQuery (后者返回一个记录集)。要了解关于这些对象之间的不同之处的更多信息,请参考 RedBack 文档(参阅 参考资料)。
清单 1. 表示页面
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="DisplayData1.aspx.vb"
Inherits="rb4nettrain.DisplayData1" ASPCompat="true"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>DisplayData1</title>
<meta name="GENERATOR" content="Microsoft Visual Studio.NET 7.0">
<meta name="CODE_LANGUAGE" content="Visual Basic 7.0">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<H3>DisplayData1.aspx - Sample Form to Display Database Data</H3>
<P>
<asp:Label id="Mess" runat="server"></asp:Label></P>
<P><STRONG><FONT face="Arial">Data Read with Key:
</FONT></STRONG>
<asp:Label id="Label1" runat="server"></asp:Label>
</P>
<P>
First Name:
<asp:Label id="FirstName" runat="server"></asp:Label><br>
Last Name:
<asp:Label id="LastName" runat="server"></asp:Label><br>
</P>
</form>
</body>
</HTML>
清单 2. Code-behind 页面
Public Class DisplayData1
Inherits System.Web.UI.Page
Protected WithEvents Label1 As System.Web.UI.WebControls.Label
Protected WithEvents Label3 As System.Web.UI.WebControls.Label
Protected WithEvents Mess As System.Web.UI.WebControls.Label
Protected WithEvents FirstName As System.Web.UI.WebControls.Label
Protected WithEvents LastName As System.Web.UI.WebControls.Label
Protected WithEvents Label2 As System.Web.UI.WebControls.Label
#Region " Web Form Designer Generated Code "
This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
End Sub
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Init
CODEGEN: This method call is required by the Web Form Designer
Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Dim Id As String
Dim ro As New REDPAGESLib.RedObject
Dim prop As New REDPAGESLib.RedProperty
hardcode the Id for now
Id = "1016"
do RedBack Database Access using pre-defined RedBack objects
Try
Make Connection to rbexamples database
using EmpReader object definition from Module EXMOD
Note - Open3 in RB 4.2.6 is faster; here we use older Open2
ro.Open2("rbexamples", "EXMOD:EmpReader", "", "", "")
Set Id into Object Property
prop = ro.Property("EmpId")
prop.Value = Id
Call Method to Read
ro.CallMethod("DoRead")
If RBO or SLRBO we would check some status property
to see if Read Okay,
if uObject we can check new_item = 1 to see if record did not exist
Get Values from Properties and put in Text of Labels
prop = ro.Property("FirstName")
FirstName.Text = prop.Value
prop = ro.Property("LastName")
LastName.Text = prop.Value
Catch ex As Exception
Set Message label with error message
Mess.Text = "Exception occurred: " & ex.Message
Finally
If IsReference(ro) Then
Close Object
ro.Close()
End If
End Try
Set Value of Id into Label Text
Label1.Text = Id
End Sub
End Class
图 4. 浏览器中的结果
用于显示数据库数据的示例表单 —— 使用 C#.NET
下面的 ASP.NET/C# 页面,以及它的 code-behind 页面,建立一个数据库连接,创建一个对象,设置一个关键属性,调用 RedBack 对象的数据库读方法,然后显示返回的属性值。
注意:这个无状态的例子将使用 SLRBO、RBO 或 uObject,但不使用 uQuery (后者返回一个记录集)。要了解关于这些对象之间的不同之处的更多信息,请参考 RedBack 文档(参阅 参考资料)。
清单 3. 表示页面
<%@ Page language="c#" Codebehind="CSharpData1.aspx.cs"
AutoEventWireup="false" Inherits="rb4CSharpnettrain.CSharpData1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>CSharpData1</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="Form1" method="post" runat="server">
<P>CSharpData1.aspx - Shows RedBack Database Access</P>
<P>Enter Employee Id (1001 - 1020):
<asp:TextBox id="EmpId" runat="server" Width="74px">
</asp:TextBox></P>
<P>
<asp:Button id="Button1" runat="server" Text="Read">
</asp:Button></P>
<P>
<asp:Label id="Label1" runat="server"></asp:Label></P>
</form>
</body>
</HTML>
清单 4. Code-behind 页面
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace rb4CSharpnettrain
{
/// <summary>
/// Summary description for CSharpData1.
/// </summary>
public class CSharpData1 : System.Web.UI.Page
{
protected System.Web.UI.WebControls.Button Button1;
protected System.Web.UI.WebControls.TextBox EmpId;
protected System.Web.UI.WebControls.Label Label1;
private void Page_Load(object sender, System.EventArgs e)
{
if (IsPostBack) {
// do same action as button click
Button1_Click(sender,e);
}
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
private void Button1_Click(object sender, System.EventArgs e)
{
//Simple example
string firstname;
string lastname;
REDPAGESLib.RedObject myrbo = new REDPAGESLib.RedObject ();
REDPAGESLib.RedProperty myprop;
// Note - Open3 in RB 4.2.6 is faster; here we use older Open2
myrbo.Open2 ("rbexamples", "EXMOD:EmpReader","","","");
myprop = (REDPAGESLib.RedProperty)myrbo.Property ("EmpId");
myprop.Value = EmpId.Text;
myrbo.CallMethod("DoRead");
myprop = (REDPAGESLib.RedProperty)myrbo.Property ("FirstName");
firstname = myprop.Value ;
myprop = (REDPAGESLib.RedProperty)myrbo.Property ("LastName");
lastname = myprop.Value ;
Label1.Text = firstname + " " + lastname;
}
}
}
图 5. 浏览器中的结果
使用 uQuery 和 ADO 记录集的示例报告 —— 使用 VB.NET
如果仅通过一个 select 语句就可以收集到一个报告所需的记录,那么 uQuery 对象是用于从数据库获得数据的理想的 RedBack 对象。这个对象返回一个 ADO Recordset,您可以迭代这个 Recordset,以显示每个记录中的字段。还可以迭代这个 Recordset,并将一个 DataTable 填充到一个 DataSet 中,以绑定到一个 DataGrid。
图 6. Input 表单,显示在 Visual Studio.NET 中
清单 5. 表示页面
<%@ Page Language="vb" AutoEventWireup="false" Codebehind="ReportData1.aspx.vb"
Inherits="testvb.ReportData1"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<title>ReportData1</title>
<meta content="Microsoft Visual Studio.NET 7.0" name="GENERATOR">
<meta content="Visual Basic 7.0" name="CODE_LANGUAGE">
<meta content="JavaScript" name="vs_defaultClientScript">
<meta content="http://schemas.microsoft.com/intellisense/ie5" name="vs_targetSchema">
</HEAD>
<body>
<form id="Form1" method="post" runat="server">
<H3>ReportData1.aspx - Sample Report using uQuery with ADO Recordset</H3>
<P><asp:label id="Mess" runat="server"></asp:label></P>
<P><STRONG><FONT face="Arial">Please Input Department Code (1 to 5):
<asp:textbox id="DeptId" runat="server" Width="100px"></asp:textbox>
<INPUT type="submit" value="Submit">
</FONT></STRONG>
</P>
<center>
<asp:Panel id="Panel1" runat="server" Width="453px" Height="109px"
BorderStyle="Outset" HorizontalAlign="Center">
<P>
<%
If IsPostBack Then
Icnt = CInt(ro.Property("MaxRows").Value)
%>
<B>Records Found: <%= Icnt %></B>
<TABLE cellPadding="3">
<%
For i = 1 To Icnt %>
<TR>
<TD><%= rs.Fields("EMP.ID").Value %></TD>
<TD><%= rs.Fields("FIRST.NAME").Value %></TD>
<TD><%= rs.Fields("LAST.NAME").Value %></TD>
</TR>
<%rs.MoveNext()
Next i
ro.close()
rs.close()
End If %>
</TABLE>
<P></P>
</asp:Panel></center>
</form>
</body>
</HTML>
清单 6. Code-behind 页面
Public Class ReportData1
Inherits System.Web.UI.Page
Public Icnt, i As Integer
Public ro As New REDPAGESLib.RedObject
Public prop As New REDPAGESLib.RedProperty
Public rs As ADOR.Recordset
Protected WithEvents Label1 As System.Web.UI.WebControls.Label
Protected WithEvents Mess As System.Web.UI.WebControls.Label
Protected WithEvents DeptId As System.Web.UI.WebControls.TextBox
Protected WithEvents Panel1 As System.Web.UI.WebControls.Panel
#Region " Web Form Designer Generated Code "
This call is required by the Web Form Designer.
<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
Me.ID = "Form1"
End Sub
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Init
CODEGEN: This method call is required by the Web Form Designer
Do not modify it using the code editor.
InitializeComponent()
End Sub
#End Region
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)
Handles MyBase.Load
Hide results panel in case we dont need to show
Panel1.Visible = False
Mess.Text = ""
If Page.IsPostBack Then
Dim ErrMsg As String
Dim DatabaseName As String
Dim Id As String
Dim i As Integer
get Id from Form field called DeptId
Id = Trim(DeptId.Text)
If Id = "" Then
Set Message label with validation message
Mess.Text = "Validation failed: Please enter Id"
Else
do RedBack Database Access using pre-defined RedBack Object
Try
Make Connection to rbexamples database using object definition
from Module EXMOD
DatabaseName = GetDatabaseName()
note – use Open3 in RedBack 4.2.6 as it is faster;
here we use the older Open2
ro.Open2(DatabaseName, "EXMOD:EmployeeList", "", "", "")
Set Id into Object Property
prop = ro.Property("select_criteria")
prop.Value = "SELECT EMPLOYEES WITH DEPT = """ & Id &
""" BY LAST.NAME BY FIRST.NAME"
Call Method to Read
rs = ro.CallMethod("Select")
Catch ex As Exception
Set Message label with error message
Mess.Text = "Exception occurred: " & ex.Message
End Try
Make Panel with results visible
Panel1.Visible = True
End If
End If
End Sub
Function GetDatabaseName()
Dim DatabaseName As String
DatabaseName = "rbexamples"
Return DatabaseName
End Function
End Class
图 7. 浏览器中的结果
使用 uQuery 和 ADO 记录集的示例报告 —— 使用 C#.NET
这个例子和上面的 VB.NET 例子是一样的。注意,这两个报告都不分页显示数据。要做到分页显示,可以在中间件中保留该对象的一个句柄,然后在请求下一页数据的时候刷新该对象。在官方的 RedBack 文档中可以找到关于如何做到这一点的解释,并且在 RedBack 附带的 rbexamples ASP 页面中还有一个 ASP 例子。
清单 7. 表示页面
<%@ Page language="c#" Codebehind="CSharpReport1.aspx.cs" AutoEventWireup="false"
Inherits="rb4CSharpnettrain.CSharpReport1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>CSharpReport1</title>
<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">
<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="Form1" method="post" runat="server">
<H3>CSharpReport1.aspx - Sample Report using uQuery with ADO Recordset</H3>
<P><asp:label id="Mess" runat="server"></asp:label></P>
<P><STRONG><FONT face="Arial">Please Input Department Code (1 to 5):
<asp:textbox id="DeptId" runat="server" Width="100px"></asp:textbox>
<INPUT type="submit" value="Submit">
</FONT></STRONG>
</P>
<center>
<asp:Panel id="Panel1" runat="server" Width="453px" Height="109px"
BorderStyle="Outset" HorizontalAlign="Center">
<P> </P>
<%
REDPAGESLib.RedProperty myprop;
if (IsPostBack) {
myprop = (REDPAGESLib.RedProperty)ro.Property ("MaxRows");
Icnt = Convert.ToInt16(myprop.Value);
%>
<B>Records Found: <%= Icnt %></B>
<TABLE cellPadding="3">
<%
string id = "";
string fldname = "";
string fname = "";
string lname = "";
string fval = "";
for (int i = 1; i <= Icnt;i++) {
id = rs.Fields["EMP.ID"].Value.ToString();
fname = rs.Fields["FIRST.NAME"].Value.ToString();
lname = rs.Fields["LAST.NAME"].Value.ToString();
%>
<TR>
<TD>&, lt;%= id %></TD>
<TD><%= fname %></TD>
<TD><%= lname %></TD>
</TR>
<% rs.MoveNext();
}
if (ro != null) { ro.Close(); }
if (rs != null) { rs.Close(); }
} %>
</TABLE>
<P> </P>
</asp:Panel></center>
</form>
</body>
</HTML>
清单 8. Code-behind 页面
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace rb4CSharpnettrain
{
/// <summary>
/// Summary description for CSharpReport1.
/// </summary>
public class CSharpReport1 : System.Web.UI.Page
{
public REDPAGESLib.RedObject ro;
public ADOR.Recordset rs;
public REDPAGESLib.RedProperty myprop;
public int Icnt;
protected System.Web.UI.WebControls.Label Mess;
protected System.Web.UI.WebControls.TextBox DeptId;
protected System.Web.UI.WebControls.Panel Panel1;
private void Page_Load(object sender, System.EventArgs e)
{
//Hide results panel in case we dont need to show
Panel1.Visible = false;
Mess.Text = "";
if (Page.IsPostBack) {
string DatabaseName;
string Id;
// get Id from Form field called DeptId
Id = (DeptId.Text).Trim();
if (Id == "") {
//Set Message label with validation message
Mess.Text = "Validation failed: Please enter Id";
} else {
// do RedBack Database Access using pre-defined RedBack Object
try {
// Make Connection to rbexamples database
// using object definition from Module EXMOD
DatabaseName = GetDatabaseName();
ro = new REDPAGESLib.RedObject ();
// note – use Open3 in RedBack 4.2.6 as it is faster;
// here we use the older Open2
ro.Open2 (DatabaseName, "EXMOD:EmployeeList","","","");
//Set Department Id into Object Property as select statement
myprop = (REDPAGESLib.RedProperty)ro.Property ("select_criteria");
myprop.Value = "SELECT EMPLOYEES WITH DEPT = \"" + Id + "\" BY LAST.NAME BY FIRST.NAME";
//Call Method to Read
rs = (ADOR.Recordset)ro.CallMethod("Select");
} catch (Exception ex) {
//Set Message label with error message
Mess.Text = "Exception occurred: " + ex.Message;
}
//Make Panel with results visible
Panel1.Visible = true;
}
}
}
private string GetDatabaseName()
{
string DatabaseName;
DatabaseName = "rbexamples";
return DatabaseName;
}
#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
图 8. 浏览器中的结果
结束语
本文中的例子演示了如何使用 RedBack 对象编写 ASP.NET Web Application 来访问 UniVerse 或 UniData 数据库。