項目告一段落,快到一年時間開發了兩個系統,一個客戶已經在試用,一個進入客戶測試階段,中間突然被項目經理(更喜歡叫他W工)分派一個每隔兩小時用windows服務去抓取客戶提供的外網xml,解析該xml,然後將截取的節點字段值插入到已經建好相應結構的表中。並記錄日志。
xml結構概要如下:
<?xml version="1.0" encoding="UTF-8"?> <list> <info> <id>93ef7c7cccd2ecb13ed01dd6e30020b4136</id> <title>剔骨刀一握六年練過硬本領 女庖丁解牛割肉有拿手好戲</title> <posttime class="sql-timestamp">2015-05-25 06:38:20.0</posttime> <institution>浙江省物價局</institution> <url>http://dsb.66wz.com/html/2015-05/25/content_1822593.htm</url> <webName>溫州都市報數字版</webName> <infotype>新聞</infotype> <summary>內容</summary> <fl>其他類</fl> </info> <info> ... </info> <info> ... </info> 。。。 </list>
1.首先,讓我們新建一個解決方案,該解決方案中包含9個項目:
(1)由於需要操作的是Oracle數據庫系統,所以在MSDN上找了個Oracle數據操作類庫DatabaseLib和DatabaseLink直接拿來用,一個是數據庫連接類,一個是數據庫操作類,裡面包含各種對數據庫的操作;
其中,DatabaseLink主要包括以下三個文件:
DbLink.cs
using System.Data; namespace DataBaseLink { /// <summary> /// DATA :2010-07-01 /// Author :虞健超(James.Yu) /// Describe :數據庫連接對象 /// </summary> public class DbLink : IDbLink { public string ConnectionStr { get; set; } public DbLink(string connectStr) { ConnectionStr = connectStr; } #if MSSQL public IDbConnection CreateConnection() { return new System.Data.SqlClient.SqlConnection(ConnectionStr); } public IDataAdapter CreateAdapter(IDbCommand cmd) { return new System.Data.SqlClient.SqlDataAdapter((System.Data.SqlClient.SqlCommand)cmd); } #endif } }
IDbLink.cs
using System.Data; namespace DataBaseLink { /// <summary> /// DATA :2010-07-01 /// Author :虞健超(James.Yu) /// Describe :連接創建對象借口 /// </summary> public interface IDbLink { /// <summary> /// 連接字符串 /// </summary> string ConnectionStr { get; set; } /// <summary> /// 創建連接 /// </summary> /// <returns>連接</returns> IDbConnection CreateConnection(); /// <summary> /// 創建Adapter /// </summary> /// <param name="cmd">cmd</param> /// <returns></returns> IDataAdapter CreateAdapter(IDbCommand cmd); } }
以及存儲過程映射類DBStoreProcedureManager.cs
namespace DataBaseLink { /// <summary> /// DATA :2010-07-01 /// Author :虞健超(James.Yu) /// Describe :存儲過程接口,裡面存儲存儲過程名,以及參數列表方便調用時反射 /// </summary> public interface IDbStoreProcedureManager { //存儲過程映射,這裡是名為SP_TestApply的存儲過程 void SP_TestApply(string c1, int? c2); } }
在這個程序中主要用到前兩個類;
而對於數據庫操作主要用到以下代碼:
OracleDBHelper.cs中的
public static int ExecuteNonQuery(string sql, OracleParameter[] para, CommandType cmdType) { int rows = -1; using (OracleConnection conn = new OracleConnection(ConnectionString)) { OracleCommand cmd = new OracleCommand(sql, conn); if (para != null) { cmd.Parameters.AddRange(para); } cmd.CommandType = cmdType; conn.Open(); rows = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); conn.Close(); } return rows; }
public override unsafe int ExecuteNonQuery() { string[] ppOpoPrmRefCtx = null; IntPtr[] pOpoPrmValCtx = null; OracleParameter parameter; int num7; int num8; IntPtr zero = IntPtr.Zero; IntPtr opsSubscrCtx = IntPtr.Zero; int isSubscrRegistered = 0; OracleDependency dep = null; int bQueryBasedNTFNRegistration = 0; int bchgNTFNExcludeRowidInfo = 0; long num4 = 0L; int errCode = 0; int prmCnt = 0; bool flag = false; int bFromPool = 0; CmdTimeoutCtx state = null; Timer timer = null; if (OraTrace.m_TraceLevel != 0) { OraTrace.Trace(1, new string[] { " (ENTRY) OracleCommand::ExecuteNonQuery()\n" }); } if (this.m_connection == null) { throw new InvalidOperationException(); } if (this.m_cmdTxtModified && ((this.m_commandText == null) || (this.m_commandText.Length == 0))) { throw new InvalidOperationException(OpoErrResManager.GetErrorMesg(ErrRes.ODP_INVALID_VALUE, new string[] { "OracleCommand.CommandText" })); } if (this.m_xmlCommandType != OracleXmlCommandType.None) { if (OracleXmlCommandType.Query == this.m_xmlCommandType) { this.ExecuteXmlQuery(false); return -1; } return this.ExecuteXmlSave(); } this.CheckConStatus(); if (this.m_cmdTxtModified || (this.m_commandType == System.Data.CommandType.StoredProcedure)) { if (this.m_commandType == System.Data.CommandType.Text) { this.m_selectStmt = isSelectStatement(this.m_commandText); this.m_pooledCmdText = this.m_commandText; } else if (this.m_commandType == System.Data.CommandType.TableDirect) { this.m_selectStmt = true; this.m_pooledCmdText = "Select * from " + this.m_commandText; } else if (this.m_commandType == System.Data.CommandType.StoredProcedure) { this.BuildCommandText(); this.m_selectStmt = false; this.m_utf8CmdText = null; this.m_addParam = true; } UTF8CommandText text = UTF8CommandText.m_pooler.Get(this.m_connection.m_internalConStr, this.m_pooledCmdText) as UTF8CommandText; if ((text != null) && (text.m_utf8CmdText != IntPtr.Zero)) { this.m_utf8CmdText = text; this.m_addParam = this.m_utf8CmdText.m_addParam; this.m_parsed = this.m_utf8CmdText.m_parsed; bFromPool = 1; } if (!this.m_parsed && (this.m_commandType == System.Data.CommandType.Text)) { this.ParseCommandText(); } this.m_cmdTxtModified = false; } if (this.m_bindByName && (this.m_commandType != System.Data.CommandType.StoredProcedure)) { flag = true; } if (((this.m_NTFNReq != null) && this.m_NTFNAutoEnlist) && (!this.m_connection.m_contextConnection && (OracleNotificationRequest.s_idTable[this.m_NTFNReq.Id] != null))) { opsSubscrCtx = OracleNotificationRequest.PopulateChgNTFNSubscrCtx(this, this.m_addRowid, out dep); if ((dep != null) && dep.m_bIsRegistered) { isSubscrRegistered = 1; } if (dep != null) { if (dep.m_OracleRowidInfo == OracleRowidInfo.Exclude) { bchgNTFNExcludeRowidInfo = 1; } if (dep.QueryBasedNotification && this.m_connection.IsDBVer11gR1OrHigher) { bQueryBasedNTFNRegistration = 1; } } } this.SetSqlValCtx(false); if ((this.m_connection.m_opoConCtx.m_bSelfTuning && !OracleTuningAgent.bHighMemoryAlertFlag) && (1 == this.m_pOpoSqlValCtx.AddToStmtCache)) { this.m_connection.AcceptStatementData(this.m_pooledCmdText); } OpoMetValCtx* pOpoMetValCtx = null; try { if (this.m_utf8CmdText != null) { zero = this.m_utf8CmdText.m_utf8CmdText; if (zero != IntPtr.Zero) { bFromPool = 1; } } if ((this.m_parameters != null) && this.m_addParam) { prmCnt = this.m_parameters.Count; if ((prmCnt > 0) && ((this.m_addToStmtCache || (this.m_pOpoPrmCtx == null)) || (this.m_pOpoPrmCtx.NumValCtxElems < prmCnt))) { try { errCode = OpsSql.Prepare2(this.m_opsConCtx, ref this.m_opsErrCtx, ref this.m_opsSqlCtx, ref this.m_opsDacCtx, ref this.m_pOpoSqlValCtx, (zero == IntPtr.Zero) ? this.m_pooledCmdText : null, ref zero, ref pOpoMetValCtx, prmCnt); } catch (Exception exception) { if (OraTrace.m_TraceLevel != 0) { OraTrace.TraceExceptionInfo(exception); } errCode = ErrRes.INT_ERR; throw; } finally { if (errCode != 0) { if (!this.m_addToStmtCache && (this.m_pOpoSqlValCtx.pOpoPrmCtx == null)) { this.m_pOpoPrmCtx = null; } if (errCode != ErrRes.INT_ERR) { string commandText; if (this.m_commandType == System.Data.CommandType.StoredProcedure) { commandText = this.m_commandText; } else { commandText = string.Empty; } OracleException.HandleError(errCode, this.m_connection, commandText, this.m_opsErrCtx, this.m_pOpoSqlValCtx, this); } } } if (!this.m_addToStmtCache && (this.m_pOpoPrmCtx == null)) { this.m_pOpoPrmCtx = this.m_pOpoSqlValCtx.pOpoPrmCtx; } } if (flag) { ppOpoPrmRefCtx = new string[prmCnt]; } pOpoPrmValCtx = new IntPtr[prmCnt]; for (num7 = 0; num7 < prmCnt; num7++) { parameter = this.m_parameters[num7]; parameter.m_pOpoPrmValCtx = this.m_pOpoSqlValCtx.pOpoPrmCtx.pOpoPrmValCtx + num7; try { parameter.PreBind(this.m_connection, this.m_opsErrCtx, this.m_arrayBindCount, this.m_isFromEF, this.m_selectStmt); } catch (Exception) { num8 = 0; while (num8 < num7) { parameter = this.m_parameters[num8]; parameter.PreBindFree(this.m_connection, this.m_arrayBindCount); num8++; } throw; } if (flag) { ppOpoPrmRefCtx[num7] = parameter.m_paramName; } pOpoPrmValCtx[num7] = (IntPtr) parameter.m_pOpoPrmValCtx; } } try { if (this.m_commandTimeout > 0) { state = new CmdTimeoutCtx(this.m_opsConCtx, this.m_commandTimeout); TimerCallback callback = new TimerCallback(state.TimeoutNew); long dueTime = this.m_commandTimeout * 0x3e8L; if (dueTime > 0xf7314000L) { dueTime = 0xf7314000L; } timer = new Timer(callback, state, dueTime, -1L); if (state.m_bDoneOCIBreak) { string procedure = null; if (this.m_commandType == System.Data.CommandType.StoredProcedure) { procedure = this.m_commandText; } else { procedure = string.Empty; } errCode = 0x3f5; OracleException.HandleError(errCode, this.m_connection, procedure, this.m_opsErrCtx, this.m_pOpoSqlValCtx, this); } } errCode = 0; if (this.m_connection.m_opoConCtx.m_bSelfTuning && (this.m_connection.m_opoConCtx.pOpoConValCtx.StmtCacheSize > OraTrace.MaxStatementCacheSize)) { this.m_connection.m_opoConCtx.pOpoConValCtx.StmtCacheSize = OraTrace.MaxStatementCacheSize; errCode = OpsCon.SetStatementCacheSize(this.m_opsConCtx, ref this.m_opsErrCtx, this.m_connection.m_opoConCtx.pOpoConValCtx); if (this.m_connection.m_opoConCtx.m_conPooler != null) { this.m_connection.m_opoConCtx.m_conPooler.ModifyConPoolerSize(this.m_connection.m_opoConCtx.pOpoConValCtx.StmtCacheSize); } } if (errCode == 0) { this.m_opsDacCtx = IntPtr.Zero; errCode = OpsSql.ExecuteNonQuery(this.m_opsConCtx, ref this.m_opsErrCtx, ref this.m_opsSqlCtx, ref this.m_opsDacCtx, opsSubscrCtx, ref isSubscrRegistered, bchgNTFNExcludeRowidInfo, bQueryBasedNTFNRegistration, ref num4, ref this.m_pOpoSqlValCtx, ((zero == IntPtr.Zero) || this.m_selectStmt) ? this.m_pooledCmdText : null, ref zero, pOpoPrmValCtx, ppOpoPrmRefCtx, ref pOpoMetValCtx, prmCnt, bFromPool); } } catch (Exception exception2) { if (OraTrace.m_TraceLevel != 0) { OraTrace.TraceExceptionInfo(exception2); } errCode = ErrRes.INT_ERR; throw; } } finally { if ((this.m_commandTimeout > 0) && (state != null)) { state.m_bDoneExecution = true; if (!state.m_hWaitForOciBreakEvent.WaitOne(0x1388, false) && (OraTrace.m_TraceLevel != 0)) { OraTrace.Trace(1, new string[] { " (WARN) OracleCommand::ExecuteNonQuery() WaitOne() timed out \n" }); } timer.Dispose(); state.Dispose(); } if (((dep != null) && (isSubscrRegistered == 1)) && !this.m_connection.m_contextConnection) { dep.SetRegisterInfo(this.m_connection.m_opoConCtx.opoConRefCtx.userID, this.m_connection.DataSource, this.m_NTFNReq.IsNotifiedOnce, this.m_NTFNReq.IsPersistent, this.m_NTFNReq.Timeout); } if ((this.m_connection.m_contextConnection && (pOpoMetValCtx != null)) && (pOpoMetValCtx->bHasUdtType == 1)) { errCode = ErrRes.CLR_UDT_NOTSUPPORTED_CTX_CONN; } if (zero != IntPtr.Zero) { if (!(UTF8CommandText.m_pooler.Get(this.m_connection.m_internalConStr, this.m_pooledCmdText) is UTF8CommandText)) { if (this.m_utf8CmdText == null) { this.m_utf8CmdText = new UTF8CommandText(zero); } this.m_utf8CmdText.m_parsed = this.m_parsed; this.m_utf8CmdText.m_addParam = this.m_addParam; UTF8CommandText.m_pooler.Put(this.m_connection.m_internalConStr, this.m_pooledCmdText, this.m_utf8CmdText); } else if (this.m_utf8CmdText == null) { this.m_utf8CmdText = new UTF8CommandText(zero); } } if (errCode != 0) { for (num7 = 0; num7 < prmCnt; num7++) { parameter = this.m_parameters[num7]; parameter.PreBindFree(this.m_connection, this.m_arrayBindCount); } this.FreeNonCachedOpoPrmCtx(); if (errCode != ErrRes.INT_ERR) { string str3; if (this.m_commandType == System.Data.CommandType.StoredProcedure) { str3 = this.m_commandText; } else { str3 = string.Empty; } OracleException.HandleError(errCode, this.m_connection, str3, this.m_opsErrCtx, this.m_pOpoSqlValCtx, this, true); } } } if ((dep != null) && !this.m_connection.m_contextConnection) { dep.m_bIsEnabled = true; if (!dep.m_regList.Contains(this.m_commandText)) { dep.m_regList.Add(this.m_commandText); } if ((bQueryBasedNTFNRegistration == 1) && !dep.m_queryIDList.Contains(num4)) { dep.m_queryIDList.Add(num4); } } if (((this.m_pOpoSqlValCtx.CommandType == 4) || (this.m_pOpoSqlValCtx.CommandType == 2)) || (this.m_pOpoSqlValCtx.CommandType == 3)) { this.m_rowsAffected = this.m_pOpoSqlValCtx.RowsAffected; } else { this.m_rowsAffected = -1; } for (num7 = 0; num7 < prmCnt; num7++) { parameter = this.m_parameters[num7]; if (parameter.m_bOracleDbTypeExSet) { parameter.m_enumType = PrmEnumType.DBTYPE; } if (parameter.m_oraDbType == OracleDbType.RefCursor) { parameter.m_commandText = this.m_commandText; if (this.m_bindByName) { parameter.m_paramPosOrName = parameter.ParameterName; } else { parameter.m_paramPosOrName = num7.ToString(); } } parameter.m_pOpoPrmValCtx = (OpoPrmValCtx*) pOpoPrmValCtx[num7]; try { if (parameter.m_direction == ParameterDirection.Input) { OracleDbType oraDbType = parameter.m_oraDbType; switch (oraDbType) { case OracleDbType.Varchar2: parameter.FreeDataBuffer(); goto Label_0AA3; case OracleDbType.Date: parameter.m_saveValue = null; goto Label_0AA3; } if (oraDbType != OracleDbType.Decimal) { parameter.PostBind(this.m_connection, this.m_pOpoSqlValCtx, this.m_arrayBindCount); } } else { parameter.PostBind(this.m_connection, this.m_pOpoSqlValCtx, this.m_arrayBindCount); } } catch (Exception) { for (num8 = num7 + 1; num8 < prmCnt; num8++) { parameter = this.m_parameters[num8]; parameter.PreBindFree(this.m_connection, this.m_arrayBindCount); } this.FreeNonCachedOpoPrmCtx(); throw; } Label_0AA3: if (parameter.m_bOracleDbTypeExSet) { parameter.m_enumType = PrmEnumType.ORADBTYPE; } } this.FreeNonCachedOpoPrmCtx(); if (OraTrace.m_TraceLevel != 0) { OraTrace.Trace(1, new string[] { " (EXIT) OracleCommand::ExecuteNonQuery()\n" }); } return this.m_rowsAffected; } OracleCommand.cs中的ExecuteNonQuery
(2)由於從xml解析出來的數據結構字段不一樣,有時是8個,有時是9個,所以采用包含9個字段的實體方式來序列化xml的結構,對於那個時有時無的字段就允許存空字符串處理,所以需要一個實體類Model;
info.cs(注:類名需要保證和xml解析出來的表結構根節點一樣,不然會取不到數據):
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; namespace Model { public class info { private string _id; //主鍵 private string _title; //標題 private string _posttime; //時間 private string _institution; //公共機構 private string _author; //作者 private string _url; //文章域名地址 private string _webname; //文章域名標題 private string _infotype; //信息類型 private string _summary; //文章內容 private string _fl; //文章分類 private string _grabtime;//抓取時間 /// <summary> /// 必須有默認的構造函數 /// </summary> public info() { } public info(string id, string title, string posttime, string institution, string author, string url, string webname, string infotype, string summary, string fl,string grabtime) { this._id = id; this._title = title; this._posttime = posttime; this._institution = institution; this._author = author; this._url = url; this._webname = webname; this._infotype = infotype; this._summary = summary; this._fl = fl; this._grabtime = grabtime; } public String id { get { return _id; } set { _id = value; } } public String title { get { return _title; } set { _title = value; } } public String posttime { get { return _posttime; } set { _posttime = value; } } public String institution { get { return _institution; } set { _institution = value; } } public String author { get { return _author; } set { _author = value; } } public String url { get { return _url; } set { _url = value; } } public String webname { get { return _webname; } set { _webname = value; } } public String infotype { get { return _infotype; } set { _infotype = value; } } public String summary { get { return _summary; } set { _summary = value; } } public String fl { get { return _fl; } set { _fl = value; } } public String grabtime { get { return _grabtime; } set { _grabtime = value; } } } }
list.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Xml.Serialization; namespace Model { public class list { List<info> infoList = new List<info>(); [XmlElement(ElementName = "info")] public List<info> InfoList { get { return infoList; } set { infoList = value; } } } }
(3)還需要一個數據庫訪問類庫DAL:
OracleDBHelper.cs
using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using DatabaseLib; using DataBaseLink; using Model; using Oracle.DataAccess.Client; namespace DAL { public static class OracleDBHelper { //public static string ConnectionString = ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString; //public static string ConnectionString = ReadingConfig.XmlValue("Config", "basic.config", "/Basic/defaultConnectionString", ""); //public static string ConnectionString = "Data Source=orcl;User ID=LZF;Password=easyman"; public static string ConnectionString = "DATA SOURCE=172.18.1.153/ORCL;PERSIST SECURITY INFO=True;USER ID=WJ_BASE;PASSWORD=WJ_BASE;POOLING=TRUE;MIN POOL SIZE=10;"; #region 對於所有表 ExecuteNonQuery() 直接對數據進行更新操作 public static int ExecuteNonQuery(string sql) { return ExecuteNonQuery(sql, null, CommandType.Text); } public static int ExecuteNonQuery(string sql, OracleParameter[] para) { return ExecuteNonQuery(sql, para, CommandType.Text); } public static int ExecuteNonQuery(string sql, CommandType cmdType) { return ExecuteNonQuery(sql, null, cmdType); } public static int ExecuteNonQuery(string sql, OracleParameter[] para, CommandType cmdType) { int rows = -1; using (OracleConnection conn = new OracleConnection(ConnectionString)) { OracleCommand cmd = new OracleCommand(sql, conn); if (para != null) { cmd.Parameters.AddRange(para); } cmd.CommandType = cmdType; conn.Open(); rows = cmd.ExecuteNonQuery(); cmd.Parameters.Clear(); conn.Close(); } return rows; } #endregion #region 對於所有表 ExecuteReader 返回結果集 public static OracleDataReader ExecuteReader(string sql) { return ExecuteReader(sql, null, CommandType.Text); } public static OracleDataReader ExecuteReader(string sql, OracleParameter[] para) { return ExecuteReader(sql, para, CommandType.Text); } public static OracleDataReader ExecuteReader(string sql, CommandType cmdType) { return ExecuteReader(sql, null, cmdType); } public static OracleDataReader ExecuteReader(string sql, OracleParameter[] para, CommandType cmdType) { OracleCommand cmd = null; OracleConnection conn = new OracleConnection(ConnectionString); ; cmd = new OracleCommand(sql, conn); if (para != null) { cmd.Parameters.AddRange(para); } cmd.CommandType = cmdType; conn.Open(); return cmd.ExecuteReader(CommandBehavior.CloseConnection); } #endregion #region 對於所有表 ExecuteDataTable 返回數據表 public static DataTable ExecuteDataTable(string sql) { return ExecuteDataTable(sql, null, CommandType.Text); } public static DataTable ExecuteDataTable(string sql, OracleParameter[] para) { return ExecuteDataTable(sql, para, CommandType.Text); } public static DataTable ExecuteDataTable(string sql, CommandType cmdType) { return ExecuteDataTable(sql, null, cmdType); } public static DataTable ExecuteDataTable(string sql, OracleParameter[] para, CommandType cmdType) { try { DataTable myTable = new DataTable(); using (OracleConnection conn = new OracleConnection(ConnectionString)) { OracleCommand cmd = new OracleCommand(sql, conn); if (para != null) { cmd.Parameters.Add(para); } cmd.CommandType = cmdType; OracleDataAdapter da = new OracleDataAdapter(cmd); da.Fill(myTable); } return myTable; } catch (Exception ex) { throw ex; } } /// <summary> /// 插入數據 /// </summary> /// <param name="ag"></param> /// <returns></returns> public static int Insert(info ag ) { ////讀連接字符串 //string connectStr = ConnectionString; //DbLink link = new DbLink(connectStr); ////將存儲過程接口傳入 //DbEntityOperate dbOpt = new DbEntityOperate(typeof(IDbStoreProcedureManager), link); ////保存這條記錄,返回影響的行數 //return dbOpt.InsertItem(ag).Count; //讀連接字符串 string connectStr = ConnectionString; DbLink link = new DbLink(connectStr); //將存儲過程接口傳入 DbEntityOperate dbOpt = new DbEntityOperate(typeof(IDbStoreProcedureManager), link); //創建一個用於查詢的實體,數據庫應該已經有一條記錄並且字段C1的值為“abc” info entity = new info(); //entity.ID = ag.ID; ////調用查詢返回結果 //List<AeGISSMSInfo> items = dbOpt.GetDataByPageSelect<AeGISSMSInfo>(entity, null, null); //將返回的實體記錄中C2字段改值並存入數據庫 entity.author = ag.author; entity.fl = ag.fl; entity.id = ag.id; entity.infotype = ag.infotype; entity.institution = ag.institution; entity.posttime = ag.posttime; entity.summary = ag.summary; entity.title = ag.title; entity.url = ag.url; entity.webname = ag.webname; entity.grabtime = ag.grabtime; //保存這條記錄 return dbOpt.ApplyItem<Model.info>(entity).Count; } #endregion /* #region 對於所有表 ExecuteScalar 返回數據表 public static object ExecuteScalar(string sql) { return ExecuteScalar(sql, null, CommandType.Text); } public static object ExecuteScalar(string sql, SqlParameter[] para) { return ExecuteScalar(sql, para, CommandType.Text); } public static object ExecuteScalar(string sql, CommandType cmdType) { return ExecuteScalar(sql, null, cmdType); } public static object ExecuteScalar(string sql, SqlParameter[] para, CommandType cmdType) { object res = null; using (SqlConnection conn = new SqlConnection(ConnectionString)) { SqlCommand cmd = new SqlCommand(sql, conn); if (para != null) { cmd.Parameters.AddRange(para); } cmd.CommandType = cmdType; conn.Open(); res = cmd.ExecuteScalar(); cmd.Parameters.Clear(); conn.Close(); } return res; } #endregion */ } }
ConnectionString 為數據庫連接字符串,該DAL需要引用DataBaseLink和DatabaseLib類庫;
(4)Bll層:
AeGISSMSInfoService.cs
using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.IO; using System.Linq; using System.Net.Configuration; using System.Text; using System.Transactions; using Model; using DAL; using Oracle.DataAccess.Client; namespace BLL { public class AeGISSMSInfoService { /// <summary> /// 輿情數據插入 /// </summary> /// <param name="infoList">抓取的xml數據</param> /// <returns></returns> public Boolean Insert(List<info> infoList) { int m = 0; int n = 0; bool IsSucess = false; using (TransactionScope tsCope = new TransactionScope()) { foreach (info info in infoList) { string sqlQuery = string.Format(" select ID from AEGISSMSINFO where ID='{0}'", info.id); DataTable dtCount = DAL.OracleDBHelper.ExecuteDataTable(sqlQuery); int rows = null != dtCount ? dtCount.Rows.Count : 0; //過濾重復數據 if (rows > 0) continue; n++; string sqlInsert = " insert into AEGISSMSINFO(ID,AUTHOR,FL,INFOTYPE,INSTITUTION,POSTTIME,SUMMARY,TITLE,URL,WEBNAME,GRABTIME)" + " values(:ID,:AUTHOR,:FL,:INFOTYPE,:INSTITUTION,:POSTTIME,:SUMMARY,:TITLE,:URL,:WEBNAME,:GRABTIME)"; OracleParameter p1 = new OracleParameter("ID", OracleDbType.NVarchar2); OracleParameter p2 = new OracleParameter("AUTHOR", OracleDbType.Varchar2); OracleParameter p3 = new OracleParameter("FL", OracleDbType.Varchar2); OracleParameter p4 = new OracleParameter("INFOTYPE", OracleDbType.Varchar2); OracleParameter p5 = new OracleParameter("INSTITUTION", OracleDbType.Varchar2); OracleParameter p6 = new OracleParameter("POSTTIME", OracleDbType.Varchar2); OracleParameter p7 = new OracleParameter("SUMMARY", OracleDbType.Clob); OracleParameter p8 = new OracleParameter("TITLE", OracleDbType.Varchar2); OracleParameter p9 = new OracleParameter("URL", OracleDbType.Varchar2); OracleParameter p10 = new OracleParameter("WEBNAME", OracleDbType.Varchar2); OracleParameter p11 = new OracleParameter("GRABTIME", OracleDbType.Varchar2); p1.Value = info.id; p2.Value = info.author; p3.Value = info.fl; p4.Value = info.infotype; p5.Value = info.institution; p6.Value = info.posttime; p7.Value = info.summary; p8.Value = info.title; p9.Value = info.url; p10.Value = info.webname; p11.Value = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"); OracleParameter[] ops = new OracleParameter[11]; ops[0] = p1; ops[1] = p2; ops[2] = p3; ops[3] = p4; ops[4] = p5; ops[5] = p6; ops[6] = p7; ops[7] = p8; ops[8] = p9; ops[9] = p10; ops[10] = p11; int agcount = DAL.OracleDBHelper.ExecuteNonQuery(sqlInsert, ops); if (agcount > 0) { m++; WriteLog(string.Format( " \r\n" + "=====================================→數據插入成功({0}),當前第 [{1}] 條←=====================================\r\n", p11.Value, n)); WriteLog(string.Format("插入成功,sql為:'{0}'\r\n,參數值依次為:\r\n{1}\r\n", sqlInsert, p1.Value + ",\r\n" + p2.Value + ",\r\n" + p3.Value + ",\r\n" + p4.Value + ",\r\n" + p5.Value + ",\r\n" + p6.Value + ",\r\n" + p7.Value + ",\r\n" + p8.Value + ",\r\n" + p9.Value + ",\r\n" + p10.Value)); } else { WriteLog(string.Format( " \r\n" + "=====================================→數據插入失敗({0}),當前第 [{1}] 條←=====================================\r\n", p11.Value, n)); WriteLog(string.Format("插入失敗,sql為:'{0}'\r\n,參數值依次為:\r\n{1}\r\n", sqlInsert, p1.Value + ",\r\n" + p2.Value + ",\r\n" + p3.Value + ",\r\n" + p4.Value + ",\r\n" + p5.Value + ",\r\n" + p6.Value + ",\r\n" + p7.Value + ",\r\n" + p8.Value + ",\r\n" + p9.Value + ",\r\n" + p10.Value)); } } if (m == n) { tsCope.Complete(); WriteLog(string.Format( " \r\n" + "=====================================→數據抓取成功({0})←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); WriteLog(string.Format("數據抓取成功,共抓取:{0}條數據.\r\n", m)); Console.ReadLine(); IsSucess = true; } else { tsCope.Dispose(); WriteLog(string.Format( " \r\n" + "=====================================→數據抓取失敗({0})←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); WriteLog(string.Format("數據抓取失敗,共抓取:{0}條數據,成功{1}條,失敗{2}條。\r\n", n, m, n - m)); } } return IsSucess; } /// <summary> /// 寫入日志 /// </summary> /// <param name="logMsg"></param> private void WriteLog(string logMsg) { string pathLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); string path = string.Format(pathLogs + "\\AeGISSMSInfoLog{0}.txt", DateTime.Now.ToString("yyyy-MM-dd")); if (!Directory.Exists(pathLogs)) Directory.CreateDirectory(pathLogs); if (!File.Exists(path)) File.Create(path); FileInfo finfo = new FileInfo(path); if (finfo.Exists) { using (FileStream fs = finfo.OpenWrite()) { //根據上面創建的文件流創建寫數據流 StreamWriter w = new StreamWriter(fs); //設置寫數據流的起始位置為文件流的末尾 w.BaseStream.Seek(0, SeekOrigin.End); w.Write(logMsg); //清空緩沖區內容,並把緩沖區內容寫入基礎流 w.Flush(); //關閉寫數據流 w.Close(); } } } } } AeGISSMSInfoService.cs(5)建一個Windows服務類庫項目:
Program.cs是服務程序入口,用於實例化服務對象並執行服務程序:
using System; using System.Collections.Generic; using System.Linq; using System.ServiceProcess; using System.Text; namespace AeGISSMSInfo { static class Program { /// <summary> /// 應用程序的主入口點。 /// </summary> static void Main() { ServiceBase[] ServicesToRun; ServicesToRun = new ServiceBase[] { new Service1() }; ServiceBase.Run(ServicesToRun); } } }
Service1.cs是Windows服務執行相關操作的核心類:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.SqlClient; using Oracle.DataAccess.Client; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Security.Policy; using System.ServiceProcess; using System.Text; using System.Threading; using System.Timers; using System.Xml; using System.IO; using System.Windows.Forms; using System.Xml.Serialization; using Model; namespace AeGISSMSInfo { public partial class Service1 : ServiceBase { private System.Timers.Timer timer; //計時器 private string IsStart = "0"; //服務啟動開關,默認為關;0:關;1:開; public Service1() { InitializeComponent(); } protected override void OnStart(string[] args) { IsStart = "1"; // TODO: 在此處添加代碼以啟動服務。 timer = new System.Timers.Timer(); //間隔10秒 timer.AutoReset = true; timer.Interval = 2*3600*1000; //10000; // //24*3600*1000; //設置計時器事件間隔執行時間為2小時 timer.Enabled = false; //執行一次 timer.Elapsed += new ElapsedEventHandler(GrabXMLData); timer.Start(); WriteLog(string.Format( "=====================================→啟動輿情系統xml接口數據抓取服務({0})←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); } protected override void OnStop() { // TODO: 在此處添加代碼以執行停止服務所需的關閉操作。 this.timer1.Enabled = false; WriteLog(string.Format( "=====================================→關閉輿情系統xml接口數據抓取服務({0})←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); } protected override void OnPause() { //服務暫停執行代碼 base.OnPause(); } protected override void OnContinue() { //服務恢復執行代碼 base.OnContinue(); } protected override void OnShutdown() { //系統即將關閉執行代碼 base.OnShutdown(); } /// <summary> /// 抓取xml數據按其格式寫入數據庫 /// </summary> /// <param name="source"></param> /// <param name="e"></param> private void GrabXMLData(object source, System.Timers.ElapsedEventArgs e) { //每晚21點執行該服務,讀取xml寫入數據庫 //if (DateTime.Now.Hour == 21 && DateTime.Now.Minute == 0 && DateTime.Now.Second== 0) //{ try { string strXMLURL = "http://218.108.28.100/aegis/smsInfoXml/zjwjj/Infos.xml"; HttpWebResponse rsp = null; HttpWebRequest req = null; req = (HttpWebRequest) WebRequest.Create(new Uri(strXMLURL)); req.ContentType = "multipart/form-data"; req.Accept = "*/*"; req.Timeout = 30000; //30秒連接不成功就中斷 req.Method = "GET"; rsp = (HttpWebResponse) req.GetResponse(); StreamReader sr = new StreamReader(rsp.GetResponseStream(), Encoding.Default); String result = sr.ReadToEnd(); //過濾非法字符 StringBuilder infos = new StringBuilder(); foreach (char cc in result) { int ss = (int) cc; if (((ss >= 0) && (ss <= 8)) || ((ss >= 11) && (ss <= 12)) || ((ss >= 14) && (ss <= 32))) infos.AppendFormat(" ", ss); //&#x{0:X}; else infos.Append(cc); } using ( StringReader rdr = new StringReader(@"<?xml version='1.0' encoding='utf-8'?>" + infos.ToString().Trim())) { //聲明序列化對象實例serializer XmlSerializer serializer = new XmlSerializer(typeof (Model.list)); //反序列化,並將反序列化結果值賦給變量i Model.list AeGISSMSInfo = (Model.list) serializer.Deserialize(rdr); List<info> infoList = AeGISSMSInfo.InfoList; //輸出反序列化結果 bool IsInsert = new BLL.AeGISSMSInfoService().Insert(infoList); IsStart = IsInsert ? "0" : "1"; sr.Close(); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex.Message); WriteLog(string.Format( " \r\n" + "=====================================→數據抓取失敗({0})←=====================================\r\n" + "異常信息:{1}\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), ex.Message )); } //} } /// <summary> /// 寫入日志 /// </summary> /// <param name="logMsg"></param> private void WriteLog(string logMsg) { string pathLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); string path = string.Format(pathLogs + "\\AeGISSMSInfoLog{0}.txt", DateTime.Now.ToString("yyyy-MM-dd")); if (!Directory.Exists(pathLogs)) Directory.CreateDirectory(pathLogs); if (!File.Exists(path)) File.Create(path); FileInfo finfo = new FileInfo(path); if (finfo.Exists) { using (FileStream fs = finfo.OpenWrite()) { //根據上面創建的文件流創建寫數據流 StreamWriter w = new StreamWriter(fs); //設置寫數據流的起始位置為文件流的末尾 w.BaseStream.Seek(0, SeekOrigin.End); w.Write(logMsg); //清空緩沖區內容,並把緩沖區內容寫入基礎流 w.Flush(); //關閉寫數據流 w.Close(); } } } } } Service1.cs
ProjectInstaller.cs的ProjectInstaller.Designer
namespace AeGISSMSInfo { partial class ProjectInstaller { /// <summary> /// 必需的設計器變量。 /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// 清理所有正在使用的資源。 /// </summary> /// <param name="disposing">如果應釋放托管資源,為 true;否則為 false。</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region 組件設計器生成的代碼 /// <summary> /// 設計器支持所需的方法 - 不要 /// 使用代碼編輯器修改此方法的內容。 /// </summary> private void InitializeComponent() { this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller(); this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller(); // // serviceProcessInstaller1 // this.serviceProcessInstaller1.Account = System.ServiceProcess.ServiceAccount.LocalSystem; this.serviceProcessInstaller1.Password = null; this.serviceProcessInstaller1.Username = null; this.serviceProcessInstaller1.AfterInstall += new System.Configuration.Install.InstallEventHandler(this.serviceProcessInstaller1_AfterInstall); // // serviceInstaller1 // this.serviceInstaller1.Description = "抓取xml數據,按其格式導入到數據庫表,每隔2小時抓取一次記錄抓取時間,若失敗則重試3次,逾次則棄"; this.serviceInstaller1.ServiceName = "AeGISSMSInfoService"; this.serviceInstaller1.StartType = System.ServiceProcess.ServiceStartMode.Automatic; this.serviceInstaller1.AfterInstall += new System.Configuration.Install.InstallEventHandler(this.serviceInstaller1_AfterInstall); // // ProjectInstaller // this.Installers.AddRange(new System.Configuration.Install.Installer[] { this.serviceProcessInstaller1, this.serviceInstaller1}); } #endregion private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1; private System.ServiceProcess.ServiceInstaller serviceInstaller1; } }
(6)建一個安裝項目:
添加項目輸出:
在項目庫上右擊,
點擊“確定”,AeGISSMSInfoService的主輸出的項目項被添加到安裝項目中。
添加自定義操作:
雙擊“應用程序文件夾”,點擊“添加文件”將項目打包後要安裝的項目添加到該列表中,
設置用戶界面:
設置文件系統,
注意:在這個“文件系統”中如果要添加卸載程序需要到C:/windows/system32中找到一個msiexec.exe,選擇後加入,然後右擊該文件,創建快捷方式:
單擊該快捷方式,然後選擇面板上的“屬性”或右擊該快捷方式→“屬性”:
對於這裡面的Arguments的設置方法,單擊解決方案管理器中的安裝項目,選擇面板中的屬性(注意:這裡不是右擊選擇“屬性”,右擊選擇屬性會出現:
)找到ProductCode:
復制後在上面提到的Arguments中鍵入:/x (此處粘貼剛才復制的ProductCode)
例:/x {9FCDEEEB-F6FC-4B84-B95D-C1B113F7CB28}
這個設置主要用來觸發卸載操作;
2.安裝服務:
編譯運行該安裝項目後會在其bin目錄下生成一個AeGISSMSInfo.exe文件,然後
“開始”→“運行”→鍵入“cmd”命令出現dos操作窗口:
Microsoft Windows [版本 6.1.7601]
版權所有 (c) 2009 Microsoft Corporation。保留所有權利。
C:\Users\ld>cd C:\Windows\Microsoft.NET\Framework\v4.0.30319\InstallUtil.exe
目錄名稱無效。
C:\Users\ld>cd C:\Windows\Microsoft.NET\Framework\v4.0.30319
C:\Windows\Microsoft.NET\Framework\v4.0.30319>InstallUtil D:\gawking\projects\Ae
GISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMSInfo.exe
Microsoft (R) .NET Framework 安裝實用工具版本 4.0.30319.18408
版權所有 (C) Microsoft Corporation。保留所有權利。
正在運行事務處理安裝。
正在開始安裝的“安裝”階段。
查看日志文件的內容以獲得 D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug
\AeGISSMSInfo.exe 程序集的進度。
該文件位於 D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMSInfo.
InstallLog。
正在安裝程序集“D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMS
Info.exe”。
受影響的參數是:
logtoconsole =
logfile = D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMSInf
o.InstallLog
assemblypath = D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISS
MSInfo.exe
正在安裝服務 AeGISSMSInfoService...
已成功安裝服務 AeGISSMSInfoService。
正在日志 Application 中創建 EventLog 源 AeGISSMSInfoService...
“安裝”階段已成功完成,正在開始“提交”階段。
查看日志文件的內容以獲得 D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug
\AeGISSMSInfo.exe 程序集的進度。
該文件位於 D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMSInfo.
InstallLog。
正在提交程序集“D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMS
Info.exe”。
受影響的參數是:
logtoconsole =
logfile = D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISSMSInf
o.InstallLog
assemblypath = D:\gawking\projects\AeGISSMSInfo\AeGISSMSInfo\bin\Debug\AeGISS
MSInfo.exe
“提交”階段已成功完成。
已完成事務處理安裝。
C:\Windows\Microsoft.NET\Framework\v4.0.30319>
3.可以建兩個服務啟動和中止的批處理文件用來啟動和中止服務:
或者新建一個Winform程序在界面按鈕操作中實現開啟和關閉服務的功能:
Form1.cs
using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration.Install; using System.Data; using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using System.Text; using System.Windows.Forms; using System.ServiceProcess; namespace AeGISSMSInfoForms { public partial class Form1 : Form { //建立服務對象 private ServiceController sc = new ServiceController("AeGISSMSInfoService"); public Form1() { InitializeComponent(); } private void btnStartOrStop_Click(object sender, EventArgs e) { bool IsStart = false; //服務運行則停止服務 if (sc.Status.Equals(ServiceControllerStatus.Running)) { this.btnStart.Text = "啟動服務"; sc.Stop(); WriteLog(string.Format( " \r\n" + "=====================================→停止服務成功 {0}←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); MessageBox.Show("服務停止成功!"); } //服務停止則啟動服務 if ((sc.Status.Equals(ServiceControllerStatus.Stopped)) || (sc.Status.Equals(ServiceControllerStatus.StopPending))) { this.btnStart.Text = "停止服務"; sc.Start(); WriteLog(string.Format( " \r\n" + "=====================================→啟動服務成功 {0}←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); MessageBox.Show("服務啟動成功!"); } ////服務停止則啟動服務 //if (this.btnStart.Text == "啟動服務") //{ // this.btnStart.Text = "停止服務"; // sc.Start(); // WriteLog(string.Format( // " \r\n" + // "=====================================→啟動服務成功 {0}←=====================================\r\n", // DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); //} ////服務運行則停止服務 //else if (this.btnStart.Text == "停止服務") //{ // this.btnStart.Text = "啟動服務"; // sc.Stop(); // WriteLog(string.Format( // " \r\n" + // "=====================================→停止服務成功 {0}←=====================================\r\n", // DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); //} sc.Refresh(); } private void btnUninstall_Click(object sender, EventArgs e) { //ProcessStartInfo a = // new ProcessStartInfo( // string.Format(@"{0}\\AeGISSMSInfo.exe", Path.Combine(AppDomain.CurrentDomain.BaseDirectory)), // "-remove"); //a.WindowStyle = ProcessWindowStyle.Hidden; //a.UseShellExecute = false; //WriteLog(string.Format( // " \r\n" + // "=====================================→卸載服務成功 {0}←=====================================\r\n", // DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); ////MessageBox.Show("服務卸載成功!"); ////Process process = Process.Start(a); ////UnInstallService(); //string pathLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory); //System.Diagnostics.Process.Start(pathLogs + "\\卸載該服務程序.exe"); if (ServiceIsExisted(sc.ServiceName)) { try { string CurrentDirectory = System.Environment.CurrentDirectory; System.Environment.CurrentDirectory = CurrentDirectory + "\\Service"; ManagedInstallerClass.InstallHelper(new string[] { "/u", "AeGISSMSInfo.exe" }); System.Environment.CurrentDirectory = CurrentDirectory; WriteLog(string.Format( " \r\n" + "=====================================→服務卸載成功 {0}←=====================================\r\n", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"))); MessageBox.Show("服務卸載成功!"); } catch (Exception ex) { MessageBox.Show("服務卸載出錯:" + ex.Message); } } else { MessageBox.Show("您要卸載的服務不存在!"); } } private bool ServiceIsExisted(string svcName) { ServiceController[] services = ServiceController.GetServices(); foreach (ServiceController s in services) { if (s.ServiceName == svcName) { return true; } } return false; } /// <summary> /// 寫入日志 /// </summary> /// <param name="logMsg"></param> public void WriteLog(string logMsg) { string pathLogs = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"); string path = string.Format(pathLogs + "\\AeGISSMSInfoLog{0}.txt", DateTime.Now.ToString("yyyy-MM-dd")); if (!Directory.Exists(pathLogs)) Directory.CreateDirectory(pathLogs); if (!File.Exists(path)) File.Create(path); FileInfo finfo = new FileInfo(path); if (finfo.Exists) { using (FileStream fs = finfo.OpenWrite()) { //根據上面創建的文件流創建寫數據流 StreamWriter w = new StreamWriter(fs); //設置寫數據流的起始位置為文件流的末尾 w.BaseStream.Seek(0, SeekOrigin.End); w.Write(logMsg); //清空緩沖區內容,並把緩沖區內容寫入基礎流 w.Flush(); //關閉寫數據流 w.Close(); } } } } } Form1.cs這只是個簡單的操作,默認加載時判斷服務如果是開啟的,則按鈕文字顯示“停止服務”,反之顯示“開啟服務”,交替操作;
這樣,一個解析xml抓取數據並插入數據庫的Windows服務就寫好了,每次電腦開啟的時候就會自動啟動該服務,每隔兩小時就會抓取數據存入數據庫。
記錄的日志結果: