Microsoft Office Groove 2007 提供點對點加密同步的協作工作區,解決移動團隊離線收集資料、自動同步上傳的難題。本文示範:建立含自訂表單的 Groove 工作區 → 現場人員離線填寫 → 協調員透過 Groove Web Services API 讀取資料 → 自動寫入 SQL Server 分析,完整端到端解決方案。
雖為用戶端應用,但程式模型為 **本地 Web Services** (Groove Client 代管服務端點)。
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Office\12.0\Groove")) {
string grooveHost = $"https://localhost:{key.GetValue("GrooveLocalHTTPPort", 9080)}";
string requestKey = (string)key.OpenSubKey("WebServices").GetValue("LocalRequestKey");
// 每次呼叫前重讀,因 RequestKey 會隨 Groove 重啟變更
}
從 Groove SDK 取得 WSDL,加入專案參考:GrooveAccounts、GrooveForms2、GrooveSpaces、GrooveTools。
// 帳戶與身分
var accountsSvc = new GrooveAccounts.GrooveAccounts { Url = grooveHost + "/GWS/Groove/2.0/Accounts/" };
accountsSvc.GrooveRequestHeaderValue = new GrooveAccounts.GrooveRequestHeader { GrooveRequestKey = requestKey };
var accounts = accountsSvc.Read2(); // Account2[],含 Identities 集合
// 工作區
var spacesSvc = new GrooveSpaces.GrooveSpaces { Url = grooveHost + identity.Spaces };
spacesSvc.GrooveRequestHeaderValue.GrooveIdentityURL = identity.URI;
var spaces = spacesSvc.Read(""); // Space2[]
// 工具 (尋找表單工具)
var toolsSvc = new GrooveTools.GrooveTools { Url = grooveHost + space.Tools };
var tools = toolsSvc.Read(""); // 找 Name="表單" 的 Tool2
var formsSvc = new GrooveForms2.GrooveForms2 { Url = grooveHost + tool.Url };
formsSvc.GrooveRequestHeaderValue.GrooveRequestKey = requestKey;
var query = new GrooveForms2.RecordQuery {
ViewURI = "", UnreadRecordsOnly = false, QueryMetadataOnly = false, IncludeFileAttachmentContent = false
};
var recordDataSet = formsSvc.QueryRecords(query); // Forms2RecordDataSet (XML 結構)
// 轉換為 .NET DataSet
var ds = new DataSet();
using (var schemaReader = new StringReader(recordDataSet.SchemaXml)) ds.ReadXmlSchema(schemaReader);
// 修正 DateTimeMode = Utc 避免時區偏移
foreach (DataTable dt in ds.Tables) foreach (DataColumn dc in dt.Columns) if (dc.DataType == typeof(DateTime)) dc.DateTimeMode = DataSetDateTime.Utc;
using (var dataReader = new StringReader(recordDataSet.DataXml)) ds.ReadXml(dataReader);
foreach (DataRow row in ds.Tables["Records"].Rows) {
string recordId = row["_RecordID"].ToString(); // 系統產生唯一鍵
using (var cmd = new SqlCommand("MERGE INTO SurveyData USING (SELECT @Id AS RecordID) AS src ON SurveyData.RecordID = src.RecordID WHEN MATCHED THEN UPDATE SET ... WHEN NOT MATCHED THEN INSERT ...", conn)) {
cmd.Parameters.AddWithValue("@Id", recordId);
// 映射其他欄位...
cmd.ExecuteNonQuery();
}
}
使用 _RecordID 確保冪等性:重複執行只更新不重複插入。
QueryRecords 分頁或篩選未讀記錄