动态数据生成解决方案
实现原理:
网页:使用StreamReader读取模板,替换里面的关键词,用 StreamWriter生成新页。
程序:使用类Codedom生成程序文件。
实现:具体如下
输入数据库名,用户名和密码进入系统。程序使用Form验证,所有未经过验证转到此画面。
Web.config配置如下:
<authentication mode="Forms">
<forms loginUrl="conn.aspx"
protection="All"
timeout="30"
name=".ASPXAUTH"
path="/"
requireSSL="false"
slidingExpiration="true"
defaultUrl="Pages_Creator.aspx"
cookieless="UseDeviceProfile"
enableCrossAppRedirects="false" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
以下是数据库服务名,可以为IP地址。WUSF\DAT为我的数据库所在的服务器名称。
<appSettings>
<add key="Connecting" value="WUSF\DAT" />
</appSettings>
数据验证成功后转入程序生成画面,显示所有用户具有权限的数据库和对应的表,此部分功能涉及到相关SQL语句及程序如下。
SQL:
--Sql Server 关于获取数据库名,表名及字段名的几个语句。
所有的库名
select [name] from master.dbo.sysdatabases where dbid>6
--当前库下的所有表名
use hischeck
select[name]from sysobjects where xtype='U'
--当前表下的所有字段名
select column_name from information_schema.columns where table_name='hcempno'
select column_name from information_schema.columns where table_name='hcempno'
select [name] from syscolumns where id = object_id('hcempno')
C#:
CreatePage tmp = new CreatePage();//数据库操作类
this.lbdbname.DataSource = tmp.dbDataName(ConnectionString);
this.lbdbname.DataTextField = "name";
this.lbdbname.DataValueField = "name";
this.lbdbname.DataBind();
//得到第一个数据库名,用于初始化右边下拉列表。
this.ddlTable.DataSource = tmp.ddlDataTable(ConnectionString, lbdbname.Items[0].Value);
this.ddlTable.DataTextField = "name";
this.ddlTable.DataValueField = "name";
this.ddlTable.DataBind();
//选择事件,选择左边数据库名,右边得到对应的表名。
protected void lbdbname_SelectedIndexChanged(object sender, EventArgs e)
{
CreatePage tmp = new CreatePage();
this.ddlTable.DataSource = tmp.ddlDataTable(ConnectionString, this.lbdbname.SelectedItem.Value);
this.ddlTable.DataTextField = "name";
this.ddlTable.DataValueField = "name";
this.ddlTable.DataBind();
}
生成网页及对应程序代码如下:
范本页:
AddTemplet.config
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="FileStr.aspx.cs" Inherits="CodeAccrue.Web.FileStr" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>strTitle</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form id="form1" runat="server">
<div>
<table width="100%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="25" colspan="2" align="center">strTitle(Add) </td>
</tr>
strShowtd
<tr>
<td height="25" align="right"> </td>
<td> <asp:Button ID="btnAdd" OnClick="btnAdd_Click" runat="server" Text="Add" />
<input id="Button1" type="reset" value="Reset" /></td>
</tr>
</table>
</div>
</form>
</body>
</html>
生成檔C#代码:
1
2 protected void btnCreate_Click(object sender, EventArgs e)
3 {
4 string strlbname = lbdbname.SelectedValue;
5 string strddltable = ddlTable.SelectedValue;
6 string ConnectionString = "Data Source=" + Session["DbSour"] + ";uid=" + Session["Ud"] + ";pwd=" + Session["PW"] + ";database=" + Session["DbNM"] + ";";
7
8 CreatePage tmp = new CreatePage();
9 DataTable dt = tmp.GetAllFiles(ConnectionString, strddltable);
10 //生成詳細
11 string strtd = null;
12 for (int i = 0; i < dt.Rows.Count; i++)
13 {
14 strtd = strtd + "<tr>\r\n\t<td width=\"26%\" height=\"25\" align=\"right\">" + dt.Rows[i]["column_name"].ToString() + " </td>\r\n\t<td width=\"74%\"> <asp:TextBox ID=\"txt" + dt.Rows[i]["column_name"].ToString() + "\" runat=\"server\"></asp:TextBox></td>\r\n</tr>\r\n";
15 }
16
17 string path = HttpContext.Current.Server.MapPath("Templet/");
18 Encoding code = Encoding.GetEncoding("utf-8");
19
20 // 读取模板文件
21 string temp = HttpContext.Current.Server.MapPath("Templet/AddTemplet.config");
22 StreamReader sr = null;
23 StreamWriter sw = null;
24 string str = "";
25 try
26 {
27 sr = new StreamReader(temp, code);
28 str = sr.ReadToEnd(); // 读取文件
29 }
30 catch (Exception exp)
31 {
32 HttpContext.Current.Response.Write(exp.Message);
33 HttpContext.Current.Response.End();
34 sr.Close();
35 }
36
37 string htmlfilename = "Page_" + strddltable + "_Add" + ".aspx";
38 // 替换内容
39 // 这时,模板文件已经读入到名称为str的变量中了
40
41 str = str.Replace("strTitle", "Page_" + strddltable + "_Add"); //模板页中的strTitle
42 str = str.Replace("FileStr", "Page_" + strddltable + "_Add");
43 str = str.Replace("strShowtd", strtd);
44
45 if (!Directory.Exists(Server.MapPath(strddltable)))//判斷是否有目錄﹐如果沒有就創建
46 Directory.CreateDirectory(Server.MapPath(strddltable));
47
48 // 写文件
49 try
50 {
51 CreateCode(Server.MapPath(strddltable) + "\\" + "Page_" + strddltable + "_Add.aspx.cs", "Page_" + strddltable + "_Add", dt, ConnectionString, strddltable);
52 sw = new StreamWriter(Server.MapPath(strddltable) + "\\" + htmlfilename, false, code);
53 sw.Write(str);
54 sw.Flush();
55 }
56 catch (Exception ex)
57 {
58 HttpContext.Current.Response.Write(ex.Message);
59 HttpContext.Current.Response.End();
60 }
61 finally
62 {
63 sw.Close();
64 }
65
66 }
67
68 public void CreateCode(string strpath, string strclassNM, DataTable dt, string ConnectionString, string strddltable)
69 {
70 Stream codeStream = File.Open(strpath, FileMode.Create);
71 StreamWriter codeWriter = new StreamWriter(codeStream);
72 //创建一个代码生成器实例
73 CSharpCodeProvider provider = new CSharpCodeProvider();
74 ICodeGenerator codeGenerator = provider.CreateGenerator(codeWriter);
75 CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions();
76
77 //添加命名空间
78 CodeSnippetCompileUnit literal = new CodeSnippetCompileUnit
79 ("using System;\r\nusing System.Data;\r\nusing System.Data.SqlClient;\r\nusing System.Configuration;\r\nusing System.Collections;\r\nusing System.Web;\r\nusing System.Web.Security;\r\nusing System.Web.UI;\r\nusing System.Web.UI.WebControls;\r\nusing System.Web.UI.WebControls.WebParts;\r\nusing System.Web.UI.HtmlControls;\r\n");
80 codeGenerator.GenerateCodeFromCompileUnit(literal, codeWriter, codeGeneratorOptions);
81
82 //命名空间以及在此命名空间下面创建一个类
83 CodeNamespace codeNamespace = new CodeNamespace("CodeAccrue.Web");
84 CodeTypeDeclaration codeTypeDeclaration = new CodeTypeDeclaration();
85 codeTypeDeclaration.Name = strclassNM;//類名
86 codeTypeDeclaration.IsClass = true;
87 codeTypeDeclaration.TypeAttributes = TypeAttributes.Public;
88 codeTypeDeclaration.BaseTypes.Add("System.Web.UI.Page");
89 codeTypeDeclaration.IsPartial = true;
90 codeNamespace.Types.Add(codeTypeDeclaration);
91
92 //生成默認Page_Load事件
93 CodeMemberMethod CMethod = new CodeMemberMethod();
94 CMethod.Name = "Page_Load";
95 CMethod.Attributes = MemberAttributes.Private;
96 CMethod.ReturnType = new CodeTypeReference(typeof(void));
97 CMethod.Parameters.Add(new CodeParameterDeclarationExpression("object sender,", "EventArgs e"));
98 codeTypeDeclaration.Members.Add(CMethod);
99
100 //创建一个私有的字段
101 CodeMemberField codeMember = new CodeMemberField();
102 codeMember.Name = "strconn=@\"" + ConnectionString + "\"";
103 codeMember.Attributes = MemberAttributes.Private;
104 codeMember.Type = new CodeTypeReference(typeof(string));
105 codeTypeDeclaration.Members.Add(codeMember);
106
107 //生成btnCreate_Click事件
108 CodeMemberMethod CMethod2 = new CodeMemberMethod();
109 CMethod2.Name = "btnAdd_Click";
110 CMethod2.Attributes = MemberAttributes.Public;
111 CMethod2.ReturnType = new CodeTypeReference(typeof(void));
112 CMethod2.Parameters.Add(new CodeParameterDeclarationExpression("object sender,", "EventArgs e"));
113
114 string strsql = null;
115 string strFileNM=null;
116 for (int i = 0; i < dt.Rows.Count; i++)
117 {
118 strsql = strsql +"'\"+"+ dt.Rows[i]["column_name"].ToString()+"+\"'" + ",";
119 strFileNM = strFileNM +dt.Rows[i]["column_name"].ToString()+",";
120 CMethod2.Statements.Add(new CodeSnippetStatement("\t\t\t\tstring " + dt.Rows[i]["column_name"].ToString() + " = this.txt" + dt.Rows[i]["column_name"].ToString() + ".Text.Trim().ToString();"));
121 }
122
123 CMethod2.Statements.Add(new CodeSnippetStatement("\r\n\t\t\t\tstring strsql=\"" + strsql.Substring(0, strsql.Length - 1) + "\";"));
124 CMethod2.Statements.Add(new CodeSnippetStatement("\t\t\t\tstring strFileNM=\"" + strFileNM.Substring(0, strFileNM.Length - 1) + "\";"));
125
126 CMethod2.Statements.Add(new CodeSnippetStatement("\r\n\t\t\t\tCodeAccrue.WebClass.CreatePage tmp = new CodeAccrue.WebClass.CreatePage();"));
127 CMethod2.Statements.Add(new CodeSnippetStatement("\t\t\t\ttmp.ExecAdd(strconn,\"" + strddltable + "\",strFileNM,strsql);"));
128
129 codeTypeDeclaration.Members.Add(CMethod2);
130
131 //生成代码
132 codeGenerator.GenerateCodeFromNamespace(codeNamespace, codeWriter, codeGeneratorOptions);
133 codeWriter.Close();
134 codeStream.Close();
135 }
生成后档及代码:
Aspx:
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Page_hcempno_Add.aspx.cs" Inherits="CodeAccrue.Web.Page_hcempno_Add" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Page_hcempno_Add</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
<body>
<form id="form1" runat="server">
<div>
<table width="100%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td height="25" colspan="2" align="center">Page_hcempno_Add(Add) </td>
</tr>
<tr>
<td width="26%" height="25" align="right">id </td>
<td width="74%"> <asp:TextBox ID="txtid" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">strucode </td>
<td width="74%"> <asp:TextBox ID="txtstrucode" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">linecode </td>
<td width="74%"> <asp:TextBox ID="txtlinecode" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">empno </td>
<td width="74%"> <asp:TextBox ID="txtempno" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">cname </td>
<td width="74%"> <asp:TextBox ID="txtcname" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">sftype </td>
<td width="74%"> <asp:TextBox ID="txtsftype" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">sex </td>
<td width="74%"> <asp:TextBox ID="txtsex" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">age </td>
<td width="74%"> <asp:TextBox ID="txtage" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">hold_date </td>
<td width="74%"> <asp:TextBox ID="txthold_date" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">t_time </td>
<td width="74%"> <asp:TextBox ID="txtt_time" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">g_time </td>
<td width="74%"> <asp:TextBox ID="txtg_time" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td width="26%" height="25" align="right">add_time </td>
<td width="74%"> <asp:TextBox ID="txtadd_time" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td height="25" align="right"> </td>
<td> <asp:Button ID="btnAdd" OnClick="btnAdd_Click" runat="server" Text="Add" />
<input id="Button1" type="reset" value="Reset" /></td>
</tr>
</table>
</div>
</form>
</body>
</html>
CS:
using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace CodeAccrue.Web {
public partial class Page_hcempno_Add : System.Web.UI.Page {
private string strconn=@"Data Source=WUSF\DAT;uid=sa;pwd=055122;database=hischeck;";
private void Page_Load(object sender, EventArgs e) {
}
public virtual void btnAdd_Click(object sender, EventArgs e) {
string id = this.txtid.Text.Trim().ToString();
string strucode = this.txtstrucode.Text.Trim().ToString();
string linecode = this.txtlinecode.Text.Trim().ToString();
string empno = this.txtempno.Text.Trim().ToString();
string cname = this.txtcname.Text.Trim().ToString();
string sftype = this.txtsftype.Text.Trim().ToString();
string sex = this.txtsex.Text.Trim().ToString();
string age = this.txtage.Text.Trim().ToString();
string hold_date = this.txthold_date.Text.Trim().ToString();
string t_time = this.txtt_time.Text.Trim().ToString();
string g_time = this.txtg_time.Text.Trim().ToString();
string add_time = this.txtadd_time.Text.Trim().ToString();
string strsql="'"+id+"','"+strucode+"','"+linecode+"','"+empno+"','"+cname+"','"+sftype+"','"+sex+"','"+age+"','"+hold_date+"','"+t_time+"','"+g_time+"','"+add_time+"'";
string strFileNM="id,strucode,linecode,empno,cname,sftype,sex,age,hold_date,t_time,g_time,add_time";
CodeAccrue.WebClass.CreatePage tmp = new CodeAccrue.WebClass.CreatePage();
tmp.ExecAdd(strconn,"hcempno",strFileNM,strsql);
}
}
}
图片如下:
技术要点:生成网页文件很简单,关键是生成程序代码,Codedom的使用。
项目总结:实际上开发这样的程序并无实际上的意思(除非简单的数据操作),在实际的项目中,有很复杂的商务逻辑及页面布局。在代码生成方面比较有实际的意义,Codedom不仅可以生成代码,还可以动态编译成exe,dll/。网络上已经有很多代码生成工具,像CodeSmithStu就很不错。