using System; using System.Configuration; using System.Collections.Generic; using System.Collections.Concurrent; using System.Reflection; using System.Linq; using System.Text; using System.Xml; using System.Net; using System.Data; using System.IO; using System.Diagnostics; using System.Threading; using System.Data.SqlClient; using Foresight.Security; using Foresight.Data; using Foresight.ServiceModel; using Foresight.Fleet.Services; using Foresight.Fleet.Services.Customer; using Foresight.Fleet.Services.Asset; using Foresight.Fleet.Services.Styles; using Foresight.Fleet.Services.Style; using IronIntel.Contractor.Users; using Foresight.Fleet.Services.User; using Foresight.Fleet.Services.SystemOption; using Foresight; using DocumentFormat.OpenXml.Presentation; namespace IronIntel.Contractor { public static class SystemParams { private static Dictionary _CompanyDbString = new Dictionary(StringComparer.OrdinalIgnoreCase); private static ConcurrentDictionary _Params = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); private static readonly byte[] KEY = new byte[] { 134, 109, 104, 92, 86, 241, 196, 160, 203, 10, 175, 253, 14, 48, 138, 42, 131, 123, 238, 226, 146, 45, 125, 185, 217, 119, 183, 64, 16, 113, 37, 62 }; private static readonly byte[] IV = new byte[] { 178, 198, 121, 147, 158, 41, 192, 222, 198, 61, 142, 50, 24, 111, 158, 169 }; private static string _ContractorVersion = ""; private static string _FICVersion = ""; public const string ICONCOLOR = "?typeid={0}&bkcolor=FF000000&dotcolor=FF69D850&sn={1}"; public const string WOSMSFootnotes = "WOSMSFootnotes"; public const string EstimateMessage = "EstimateMessage"; public const string DefaultPORequired = "DefaultPORequired"; public const string InvoiceMessage = "InvoiceMessage"; private static string EncryptString(string s) { byte[] buf = Encoding.UTF8.GetBytes(s); byte[] tmp = SecurityHelper.AesEncrypt(buf, KEY, IV); return Convert.ToBase64String(tmp); } private static string GetAssemblyFileVersion() { try { string filename = Assembly.GetExecutingAssembly().GetName().Name + ".dll"; string fn = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin\\" + filename); FileVersionInfo fv = FileVersionInfo.GetVersionInfo(fn); return fv.FileVersion.ToString(); } catch { return string.Empty; } } public static void CreateDbObjects() { try { FI.FIC.Database.FIC.FICDbInitializer ficdb = new FI.FIC.Database.FIC.FICDbInitializer(FICDbConnectionString); ficdb.RunIronIntel(); } catch { } } public static string AppVersion { get { return GetVersion(); } } internal static string GetCompanyDbString(string companyid) { string rst = null; if (_CompanyDbString.TryGetValue(companyid, out rst)) { return rst; } try { CustomerDetail cust = FleetServiceClientHelper.CreateClient(companyid, string.Empty).GetCustomerDetail(companyid); string dbstr = cust.MasterDataDbString; if (!string.IsNullOrWhiteSpace(dbstr)) { _CompanyDbString[companyid] = dbstr; return dbstr; } } catch { return string.Empty; } return string.Empty; } internal static FISqlConnection GetCompanyDbConnection(string companyid) { if (string.IsNullOrWhiteSpace(companyid) || string.Compare(companyid, CompanyID, true) == 0) { return GetDbInstance(); } string s = GetCompanyDbString(companyid); if (string.IsNullOrWhiteSpace(s)) { return null; } else { return new FISqlConnection(s); } } private static string DecryptString(string s) { if (string.IsNullOrWhiteSpace(s)) { return string.Empty; } byte[] tmp = Convert.FromBase64String(s); byte[] buf = SecurityHelper.AesDecrypt(tmp, KEY, IV); return Encoding.UTF8.GetString(buf); } private static string _HostName = null; public static string HostName { get { if (_HostName == null) { try { _HostName = Dns.GetHostName(); } catch { _HostName = string.Empty; } } return _HostName; } } private static string _DataDbConnectionString = null; /// /// 获取主数据库连接字符串 /// /// 获取主数据库连接字符串 public static string DataDbConnectionString { get { if (_DataDbConnectionString == null) { SqlConnectionStringBuilder sb = new SqlConnectionStringBuilder(ConfigurationManager.AppSettings["DbConntionString"]); try { sb.Password = DecryptString(sb.Password); } catch { } _DataDbConnectionString = sb.ToString(); } return _DataDbConnectionString; } } private static string _ficdbstr = null; public static string FICDbConnectionString { get { if (_ficdbstr == null) { string db = GetStringParam("FICSysDBName"); if (string.IsNullOrWhiteSpace(db)) { _ficdbstr = string.Empty; } else { SqlConnectionStringBuilder sc = new SqlConnectionStringBuilder(DataDbConnectionString); sc.InitialCatalog = db; _ficdbstr = sc.ToString(); } } return _ficdbstr; } } public static FISqlConnection GetDbInstance() { return new FISqlConnection(DataDbConnectionString); } public static FISqlConnection FICDBInstance { get { return new FISqlConnection(FICDbConnectionString); } } private static string _WebSocketURL = null; public static string WebSocketURL { get { if (_WebSocketURL == null) { string url = GetStringParam("WebSocketURL"); if (string.IsNullOrEmpty(url)) url = FleetServiceClientHelper.CreateClient().GetMasterSysParam("WebSocketURL"); if (!string.IsNullOrEmpty(url)) _WebSocketURL = string.Format("{0}?custid={1}", url, SystemParams.CompanyID); else _WebSocketURL = ""; } return _WebSocketURL; } } public static void SetStringParam(string paramname, string value) { FleetServiceClientHelper.CreateClient().SetSystemParams(CompanyID, paramname, value); _Params[paramname] = value; } /// /// 根据参数名称获取参数值 /// /// 参数名称 /// 参数值 public static string GetStringParam(string paramname, bool useCache = true, FISqlConnection db = null) { const string SQL = "select PARAMVALUE from SYSPARAMS where PARAMNAME={0}"; string v = null; if (useCache && _Params.TryGetValue(paramname, out v)) { return v; } if (db == null) db = GetDbInstance(); object obj = db.GetRC1BySQL(SQL, paramname); v = FIDbAccess.GetFieldString(obj, string.Empty); _Params[paramname] = v; return v; } public static string GetFICStringParam(string paramcode) { const string SQL = "select PARAMVALUE from SystemParams where PARAMCODE={0}"; if (string.IsNullOrWhiteSpace(FICDbConnectionString)) { return string.Empty; } object obj = FICDBInstance.GetRC1BySQL(SQL, paramcode); return FIDbAccess.GetFieldString(obj, string.Empty); } public static void SetFICStringParameter(string paramname, string value) { const string SQL = "if exists(select 1 from SYSTEMPARAMS where PARAMCODE={0}) " + " update SYSTEMPARAMS set PARAMVALUE={1} where PARAMCODE={0} " + " else insert into SYSTEMPARAMS(IID,PARAMTYPE,PARAMCODE,PARAMNAME,PARAMVALUE,PARAMMEMO) values(newid(),1,{0},{0},{1},{0}) "; FICDBInstance.ExecSQL(SQL, paramname, value); } private static CustomerInfo _Company = null; public static string CompanyID { get { return GetStringParam("CompanyID"); } } private static CustomerDetail _Customer = null; private static object _syccust = new object(); public static CustomerDetail CustomerDetail { get { if (_Customer == null) { lock (_syccust) { if (_Customer == null) { _Customer = FleetServiceClientHelper.CreateClient().GetCustomerDetail(CompanyID); } } } return _Customer; } } private static CustomerDetail _ForesightCustomer = null; private static object _sycfcust = new object(); public static CustomerDetail ForesightCustomerDetail { get { if (_ForesightCustomer == null) { lock (_sycfcust) { if (_ForesightCustomer == null) { _ForesightCustomer = FleetServiceClientHelper.CreateClient().GetCustomerDetail("Foresight"); } } } return _ForesightCustomer; } } public static CustomerDetail GetCustomerDetail(string cid) { return FleetServiceClientHelper.CreateClient().GetCustomerDetail(cid); } public static LicenseInfo GetLicense() { CustomerProvider ic = FleetServiceClientHelper.CreateClient(); return ic.GetLicenseInfo(CompanyID); } public static bool HasLicense(string itemName) { bool result = false; var license = GetLicense(); if (license != null && license.Items.Count > 0) { var item = license.Items.FirstOrDefault(m => m.Key.Equals(itemName, StringComparison.OrdinalIgnoreCase)); if (item != null && Helper.IsTrue(item.Value)) result = true; } return result; } public static string GetVersion() { if (string.IsNullOrEmpty(_ContractorVersion)) { _ContractorVersion = GetAssemblyFileVersion(); } return _ContractorVersion; } public static string GetFICVersion() { if (string.IsNullOrEmpty(_FICVersion)) { string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "bin\\FICBLC.dll"); if (File.Exists(path)) { FileVersionInfo fv = FileVersionInfo.GetVersionInfo(path); _FICVersion = fv.FileVersion.ToString(); } } return _FICVersion; } private static string _ReportDbString = string.Empty; public static string GetIronIntelReportDataDbString(string companyid = null) { if (string.IsNullOrEmpty(companyid)) companyid = CompanyID; if (!string.IsNullOrWhiteSpace(_ReportDbString)) { return _ReportDbString; } CustomerDetail cust = FleetServiceClientHelper.CreateClient(companyid, string.Empty).GetCustomerDetail(companyid); string dbstring = cust.ReportDataDbString; if (!string.IsNullOrEmpty(dbstring)) { _ReportDbString = dbstring; return _ReportDbString; } return string.Empty; } static Dictionary _CompanyDBStrings = new Dictionary(StringComparer.OrdinalIgnoreCase); public static string GetDbStringByCompany(string companyid) { return GetCustomerDbString(companyid, "MASTER_DATA_DB"); } public static string[] GetMonitorServiceAddresses() { SystemOptionProvider sp = FleetServiceClientHelper.CreateClient(); string xml = sp.GetMasterSysParam("ForesightPublicService"); if (string.IsNullOrWhiteSpace(xml)) { return null; } XmlDocument doc = new XmlDocument(); doc.LoadXml(xml); foreach (XmlNode node in doc.DocumentElement.ChildNodes) { if (string.Compare(node.Name, "MonitorServiceAddress", true) == 0) { if (!string.IsNullOrWhiteSpace(node.InnerText)) { return node.InnerText.Split(new char[] { ';' }, StringSplitOptions.RemoveEmptyEntries); } } } return null; } public static string GetCustomerDbString(string companyid, string dbtype) { string key = companyid + dbtype; if (_CompanyDBStrings.ContainsKey(key)) return _CompanyDBStrings[key]; CustomerDetail cust = FleetServiceClientHelper.CreateClient(companyid, string.Empty).GetCustomerDetail(companyid); string dbstring = cust.MasterDataDbString; _CompanyDBStrings[key] = dbstring; return dbstring; } public static CustomerInfo GetCompanyInfo() { if (_Company == null) { var ic = FleetServiceClientHelper.CreateClient(CompanyID); _Company = ic.GetCustomerByID(CompanyID); } return _Company; } public static MainStyle GetMainStyle() { var sp = FleetServiceClientHelper.CreateClient(); return sp.GetMainStyle(CompanyID); } public static bool IsDealer { get { return CustomerDetail.IsDealer; } } public static CustomerInfo[] GetContractors() { if (IsDealer) { var ic = FleetServiceClientHelper.CreateClient(CompanyID); return ic.GetContractors(CompanyID); } else { return new CustomerInfo[0]; } } public static byte[] GetCompanyLOGO(string companyid) { return FleetServiceClientHelper.CreateClient(companyid, string.Empty).GetCustomerLOGO(companyid); } public static byte[] GetForesightLOGOInMainStyle() { var sp = FleetServiceClientHelper.CreateClient(); return sp.GetLogoInMainStyle(CompanyID, 1); } public static byte[] GetCompanyLocationLOGO(string companyid) { byte[] buffer = FleetServiceClientHelper.CreateClient(companyid, string.Empty).GetDefaultLocationLOGO(companyid); if ((buffer == null) || (buffer.Length == 0)) { return GetCompanyLOGO(companyid); } else { return buffer; } } public static CustomerInfo GetFirstDealerInfo() { if (IsDealer) { return GetCompanyInfo(); } else { var cust = FleetServiceClientHelper.CreateClient(CompanyID); var cmps = cust.GetDealers(CompanyID); if ((cmps != null) && (cmps.Length > 0)) { return cmps[0]; } } return null; } private static Dictionary _DealerConttactors = new Dictionary(); public static CustomerInfo GetCustomerInfo(string id) { if (string.IsNullOrWhiteSpace(id)) return null; if (!_DealerConttactors.ContainsKey(id)) { var ic = FleetServiceClientHelper.CreateClient(id); var c = ic.GetCustomerByID(id); _DealerConttactors[id] = c; } return _DealerConttactors[id]; } public static bool HasLOGO(string companyid) { CustomerProvider ic = FleetServiceClientHelper.CreateClient(); return ic.HasLOGO(companyid); } public static void ExecSQL(FIDbAccess db, int retrytimes, string sql, params object[] values) { int n = 0; while (true) { n++; try { db.ExecSQL(sql, values); return; } catch { if (n >= retrytimes) { throw; } } System.Threading.Thread.Sleep(100); } } /**Fleet Service***/ public static string[] FleetAssetServiceAddresses { get { string addresses = ConfigurationManager.AppSettings["FleetAssetServiceAddress"]; if (!string.IsNullOrWhiteSpace(addresses)) return addresses.Split(';'); return new string[0]; } } //public static T GetFleetServiceClient() where T : Foresight.Fleet.Services.RemoteClientBase, new() //{ // T rst = (T)System.Activator.CreateInstance(typeof(T), new object[] { FleetAssetServiceAddresses }); // return rst; //} //public static T GetFleetServiceClient(string sessionid, string workingCompanyID) where T : Foresight.Fleet.Services.RemoteClientBase, new() //{ // T rst = (T)System.Activator.CreateInstance(typeof(T), new object[] { FleetAssetServiceAddresses }); // rst.SessionID = sessionid; // rst.WorkingCompanyID = sessionid; // return rst; //} private static string _MachineTypeMapViewIconUrl = string.Empty; public static string MachineTypeMapViewIconUrl { get { if (string.IsNullOrWhiteSpace(_MachineTypeMapViewIconUrl)) { var client = FleetServiceClientHelper.CreateClient(); _MachineTypeMapViewIconUrl = client.GetMachineTypeIconUrl(); } return _MachineTypeMapViewIconUrl; } } public static CustUIStyle GetUIStyle(string useriid) { //var up = UserParams.GetUserParams(useriid); string sid = UserParams.GetStringParameter(useriid, UserParams._SystemStyleID); int styleID = -1; if (string.IsNullOrEmpty(sid) || !int.TryParse(sid, out styleID)) styleID = -1; var sp = FleetServiceClientHelper.CreateClient(); CustUIStyle style = sp.GetDefaultUIStyle(CompanyID, styleID); return style; } public static TimeZoneInfo GetTimeZoneInfo(string custid) { string tzName = FleetServiceClientHelper.CreateClient(custid, string.Empty).GetCustomerTimeZoneName(custid); var tz = TimeZoneInfo.FindSystemTimeZoneById(tzName.Trim()); return tz; } public static StringKeyValue[] GetTimeZones() { var tzs = TimeZoneInfo.GetSystemTimeZones(); List result = new List(); foreach (TimeZoneInfo tz in tzs) { StringKeyValue skv = new StringKeyValue(); skv.Key = tz.Id; TimeSpan offset = tz.GetUtcOffset(DateTime.UtcNow); skv.Value = string.Format("{0}{1}:{2}", offset.Hours >= 0 ? "+" : "", offset.Hours.ToString("00"), Math.Abs(offset.Minutes).ToString("00")); skv.Tag1 = offset.TotalMinutes.ToString(); result.Add(skv); } return result.OrderBy(tz => double.Parse(tz.Tag1)).ThenBy(tz => tz.Key).ToArray(); } public static DateTime ConvertToUserTimeFromUtc(Foresight.Fleet.Services.User.UserInfo ui, DateTime utctime) { TimeZoneInfo timeZone = null; if (!string.IsNullOrWhiteSpace(ui.TimeZone)) { timeZone = TimeZoneInfo.FindSystemTimeZoneById(ui.TimeZone); } if (timeZone == null) { if (ui.IsForesightUser) timeZone = ForesightCustomerDetail.TimeZone; else timeZone = CustomerDetail.TimeZone; } return TimeZoneInfo.ConvertTimeFromUtc(new DateTime(utctime.Ticks), timeZone); } public const string APPNAME = "IronIntelCustomerSite"; private const string WORKING_COMPANY_HEADER = "WorkingCompanyID"; public static void SendMail(System.Net.Mail.MailMessage msg) { SendMail(APPNAME, msg); } public static void SendMail(string appname, System.Net.Mail.MailMessage msg) { FleetServiceClientHelper.CreateClient().SendMail(CompanyID, appname, msg); } public static void WriteLog(string logType, string source, string message, string detail) { try { FleetServiceClientHelper.CreateClient().WriteLog(CompanyID, APPNAME, logType, source, message, detail, string.Empty); } catch { } } public static void WriteLog(string logType, string category, string source, string message, string detail) { try { FleetServiceClientHelper.CreateClient().WriteLog(CompanyID, category, logType, source, message, detail, string.Empty); } catch { } } public static void WriteLog_Ext(string logType, string source, string message, string detail, string extmsg) { try { FleetServiceClientHelper.CreateClient().WriteLog(CompanyID, APPNAME, logType, source, message, detail, extmsg); } catch { } } public static void WriteRefreshLog(string useriid, string userhost, string objname, string refreshtype) { ThreadPool.QueueUserWorkItem(new WaitCallback((e) => { _WriteRefreshLog(useriid, userhost, objname, refreshtype); }), null); } private static void _WriteRefreshLog(string useriid, string userhost, string objname, string refreshtype) { const string SQL = "insert into REFRESHLOG(USERIID,HOSTADDRESS,OBJNAME,REFRESHTYPE,REFRESHTIME_UTC) values({0},{1},{2},{3},GETUTCDATE())"; try { FIDbAccess db = GetDbInstance(); db.ExecSQL(SQL, useriid, userhost, objname, refreshtype); } catch { } } public static string GetResourceLock(string resourceid, int locksecond) { try { return FleetServiceClientHelper.CreateClient().GetResourceLock(CompanyID, resourceid, locksecond); } catch { return ""; } } public static void ReleaseResourceLock(string lockid) { try { FleetServiceClientHelper.CreateClient().ReleaseResourceLock(lockid); } catch { } } public static string ConnectorToken { get { return GetFICStringParam("ConnectorToken"); } } public static string ConnectorServer { get { return GetFICStringParam("ConnectorServer"); } } public static string LdapAgentID { get { return GetFICStringParam("LdapAgentID"); } } public static string LdapAgentToken { get { return GetFICStringParam("LdapAgentToken"); } } public static bool CanUseConnectorLDAP { get { return GetFICStringParam("CanUseConnectorLDAP") == "1"; } } public static bool RedisEnabled { get { return string.Equals(GetFICStringParam("RedisEnabled"), "Yes", StringComparison.OrdinalIgnoreCase); } } public static string RedisToken { get { return GetFICStringParam("RedisToken"); } } public static Dictionary GetAdditionalParameter() { StringKeyValue connector = new StringKeyValue(); string connectorxml = GetStringParam("Connector"); StringKeyValue[] connectors = ConnectorHelper.FromXML(connectorxml); if (connectors != null && connectors.Length > 0) connector = connectors[0]; var dict = new Dictionary { { "ConnectorServer", connector.Key }, { "ConnectorToken", connector.Value }, { "LdapAgentID", LdapAgentID }, { "LdapAgentToken", LdapAgentToken }, { "CanUseConnectorLDAP", CanUseConnectorLDAP ? "1" : "0" } }; return dict; } private static ConcurrentDictionary> _Languages = new ConcurrentDictionary>(StringComparer.OrdinalIgnoreCase); private static Dictionary GetLanguage(string lang) { if (!_Languages.ContainsKey(lang)) { var ldata = LoadLanguage(lang); if (ldata != null) { _Languages[lang] = ldata; return ldata; } } else return _Languages[lang]; return null; } public static Dictionary LoadLanguage(string lang) { try { if (string.IsNullOrEmpty(lang)) lang = "en-us"; string filename = lang + ".json"; string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Languages\\" + filename); TextReader tr = File.OpenText(path); Newtonsoft.Json.JsonTextReader jtr = new Newtonsoft.Json.JsonTextReader(tr); Newtonsoft.Json.Linq.JObject obj = Newtonsoft.Json.Linq.JObject.Load(jtr); System.Web.Script.Serialization.JavaScriptSerializer js = new System.Web.Script.Serialization.JavaScriptSerializer(); Dictionary dic = (Dictionary)js.DeserializeObject(obj["Values"].ToString()); return dic; } catch { return null; } } public static string GetTextByKey(string lang, string key, string defaultValue) { try { Dictionary dic = GetLanguage(lang); if (dic == null || !dic.ContainsKey(key)) return defaultValue; return dic[key].ToString(); } catch { return defaultValue; } } public static string _TimeZoneAbbreviation = ""; public static string TimeZoneAbbreviation { get { if (string.IsNullOrEmpty(_TimeZoneAbbreviation)) { _TimeZoneAbbreviation = GetUpperTimeZone(CustomerDetail.TimeZone.Id); //Dictionary dic = GetTimeZoneAbbreviations(); //if (dic.ContainsKey(CustomerDetail.TimeZone.Id)) // _TimeZoneAbbreviation = dic[CustomerDetail.TimeZone.Id]; //else // _TimeZoneAbbreviation = CustomerDetail.TimeZone.Id; } return _TimeZoneAbbreviation; } } private static string GetUpperTimeZone(string tzid) { tzid = System.Text.RegularExpressions.Regex.Replace(tzid, @"\(.*\)", ""); return System.Text.RegularExpressions.Regex.Replace(tzid, @"[a-z ]*", ""); } public static bool ShowForesightLogo() { string temp = GetStringParam("ShowForesightLogo"); if (string.IsNullOrEmpty(temp)) return true; return Helper.IsTrue(temp); } public static string GetUserLanguage(string useriid) { var uc = FleetServiceClientHelper.CreateClient(); string language = uc.GetUserPreferredLanguageByIID(useriid); if (string.IsNullOrEmpty(language)) { var ic = FleetServiceClientHelper.CreateClient(CompanyID); var cust = ic.GetCustomerByID(CompanyID); language = cust.LanguageId; } return string.IsNullOrEmpty(language) ? "en-us" : language; } public static bool CheckRight(string custid, Foresight.Fleet.Services.User.UserInfo user, int featureid, Permissions per = Permissions.ReadOnly) { if (user == null) return false; if (user.UserType == Foresight.Fleet.Services.User.UserTypes.SupperAdmin) return true; if (user.UserType == Foresight.Fleet.Services.User.UserTypes.Common || user.UserType == Foresight.Fleet.Services.User.UserTypes.Admin) { var client = FleetServiceClientHelper.CreateClient(); Tuple[] pmss = client.GetUserPermissions(custid, user.UID); if (pmss.Length > 0) { Tuple permission = pmss.FirstOrDefault(m => m.Item1.Id == featureid); if (permission != null && permission.Item2 >= per) return true; } } return false; } } public class ConnectorHelper { public static StringKeyValue[] FromXML(string xmlstr) { List ls = new List(); if (!string.IsNullOrEmpty(xmlstr)) { XmlDocument doc = new XmlDocument(); doc.LoadXml(xmlstr); XmlNode ch = doc.DocumentElement.FirstChild; if (string.Compare(ch.Name, "Connectors", true) == 0) { foreach (XmlNode node in ch.ChildNodes) { ls.Add(FromXml(node)); } } } return ls.ToArray(); } private static StringKeyValue FromXml(XmlNode node) { StringKeyValue kv = new StringKeyValue(); foreach (XmlNode ch in node.ChildNodes) { if (string.Compare(ch.Name, "Server", true) == 0) kv.Key = ch.InnerText; else if (string.Compare(ch.Name, "Token", true) == 0) kv.Value = ch.InnerText; } return kv; } public static XmlDocument ToXml(StringKeyValue[] kvs) { XmlDocument doc = XmlHelper.CreateXmlDocument(); XmlNode node = XmlHelper.AppendChildNode(doc.DocumentElement, "Connectors", ""); if (kvs != null && kvs.Length > 0) { foreach (var kv in kvs) { var sn = AddSubNode(node, "Connector", ""); AddSubNode(sn, "Server", kv.Key); AddSubNode(sn, "Token", kv.Value); } } return doc; } private static XmlNode AddSubNode(XmlNode parent, string nodename, string innertext) { XmlNode node = parent.OwnerDocument.CreateNode(XmlNodeType.Element, nodename, string.Empty); if (!string.IsNullOrEmpty(innertext)) { node.InnerText = innertext; } parent.AppendChild(node); return node; } } }