1 /// <summary>
2 /// DnsPod DDNS工具类
3 /// </summary>
4 public class DDNSToolkit
5 {
6 private static string userName = ConfigurationManager.AppSettings["DNSUserName"];
7 private static string password = ConfigurationManager.AppSettings["DNSPassword"];
8 /// <summary>
9 /// 公共参数
10 /// </summary>
11 private object baseParam = new
12 {
13 login_email = userName,//用户帐号,必选
14 login_password = password,//用户密码,必选
15 format = "json",//返回的数据格式,可选,默认为xml,建议用json
16 lang = "cn",//返回的错误语言,可选,默认为en,建议用cn
17 error_on_empty = "no"//没有数据时是否返回错误,可选,默认为yes,建议用no
18 };
19
20 #region 域名相关
21
22 /// <summary>
23 /// Return the domain_Id,when the domains contains more then one entity,returns the first one!
24 /// </summary>
25 /// <returns></returns>
26 public int DomainGetId(string keyword)//获取域名ID
27 {
28 var domainId = -1;
29 if (!string.IsNullOrWhiteSpace(keyword))
30 keyword = "keyword=" + keyword;
31 /*api说明 https://www.dnspod.cn/docs/domains.html#domain-list
32 公共参数
33 type 域名权限种类,可选参数,默认为’all’。包含以下类型:
34 all:所有域名
35 mine:我的域名
36 share:共享给我的域名
37 ismark:星标域名
38 pause:暂停域名
39 vip:VIP域名
40 recent:最近操作过的域名
41 share_out:我共享出去的域名
42 offset 记录开始的偏移,第一条记录为 0,依次类推,可选参数
43 length 共要获取的记录的数量,比如获取20条,则为20,可选参数
44 group_id 分组ID,获取指定分组的域名,可选参数
45 keyword,搜索的关键字,如果指定则只返回符合该关键字的域名,可选参数*/
46 var dataBaseObj = GetDNSApi("https://dnsapi.cn/Domain.List", keyword);
47 if (dataBaseObj != null)
48 {
49 if (dataBaseObj["status"]["code"] == "1")
50 {
51 if (dataBaseObj["domains"].Length > 0)
52 {
53 domainId = Convert.ToInt32(dataBaseObj["domains"][0]["id"]);
54 }
55 }
56 else
57 {
58 throw new ArgumentException(string.Format("DNSPod API:Domain.List调用异常,说明:{0}", dataBaseObj["status"]["message"]));
59 }
60 }
61 return domainId;
62 }
63
64 #endregion
65
66 #region 记录相关
67 /// <summary>
68 /// Get the recordId
69 /// </summary>
70 /// <param name="domainId">domainId</param>
71 /// <param name="subDomain">The name for subDomain</param>
72 /// <returns></returns>
73 public int RecordGetIdBySubdomain(int domainId, string subDomain)//获取记录ID
74 {
75 var recordId = -1;
76 /*api说明 https://www.dnspod.cn/docs/records.html#record-list
77 公共参数
78 domain_id 域名ID,必选
79 offset 记录开始的偏移,第一条记录为 0,依次类推,可选
80 length 共要获取的记录的数量,比如获取20条,则为20,可选
81 sub_domain 子域名,如果指定则只返回此子域名的记录,可选
82 keyword,搜索的关键字,如果指定则只返回符合该关键字的记录,可选*/
83 var dataBaseObj = GetDNSApi("https://dnsapi.cn/Record.List", new { domain_id = domainId, sub_domain = subDomain });
84 if (dataBaseObj != null)
85 {
86 if (dataBaseObj["status"]["code"] == "1")
87 {
88 if (dataBaseObj["records"].Length > 0)
89 {
90 domainId = Convert.ToInt32(dataBaseObj["records"][0]["id"]);
91 }
92 }
93 else
94 {
95 throw new ArgumentException(string.Format("DNSPod API:Record.List调用异常,说明:{0}", dataBaseObj["status"]["message"]));
96 }
97 }
98
99 return recordId;
100 }
101
102 /// <summary>
103 /// Create subdomain record
104 /// </summary>
105 /// <param name="domainId">domainId</param>
106 /// <param name="value">value:IP、CNAME、MX</param>
107 /// <param name="subDomain">subdomain name,like "www",defalut is "@"</param>
108 /// <param name="recordId"></param>
109 /// <returns></returns>
110 public bool RecordCreate(int domainId, string value, string subDomain, out int recordId)//创建记录
111 {
112 recordId = -1;
113 bool flag = false;
114 /*api说明 https://www.dnspod.cn/docs/records.html#record-create
115 公共参数
116 domain_id 域名ID, 必选
117 sub_domain 主机记录, 如 www, 默认@,可选
118 record_type 记录类型,通过API记录类型获得,大写英文,比如:A, 必选
119 record_line 记录线路,通过API记录线路获得,中文,比如:默认, 必选
120 value 记录值, 如 IP:200.200.200.200, CNAME: cname.dnspod.com., MX: mail.dnspod.com., 必选
121 mx {1-20} MX优先级, 当记录类型是 MX 时有效,范围1-20, MX记录必选
122 ttl {1-604800} TTL,范围1-604800,不同等级域名最小值不同, 可选*/
123 var dataBaseObj = GetDNSApi("https://dnsapi.cn/Record.Create", new
124 {
125 domain_id = domainId,
126 sub_domain = subDomain,
127 value = value,
128 record_type = "A",
129 record_line = "默认"
130 });
131 if (dataBaseObj != null)
132 {
133 if (dataBaseObj["status"]["code"] == "1")
134 {
135 flag = true;
136 recordId = Convert.ToInt32(dataBaseObj["record"]["id"]);
137 }
138 else
139 {
140 throw new ArgumentException(string.Format("DNSPod API:Record.Create调用异常,说明:{0}", dataBaseObj["status"]["message"]));
141 }
142 }
143 return flag;
144 }
145 /// <summary>
146 /// 修改记录
147 /// </summary>
148 /// <param name="domainId"></param>
149 /// <param name="recordId"></param>
150 /// <param name="subdomain"></param>
151 /// <param name="value"></param>
152 /// <param name="message"></param>
153 /// <returns></returns>
154 public bool RecordUpdate(int domainId, int recordId, string subdomain, string value, out string message)//修改记录
155 {
156 message = string.Empty;
157 bool flag = false;
158 /*api说明 https://www.dnspod.cn/docs/records.html#record-modify
159 公共参数
160 domain_id 域名ID,必选
161 record_id 记录ID,必选
162 sub_domain 主机记录,默认@,如 www,可选
163 record_type 记录类型,通过API记录类型获得,大写英文,比如:A,必选
164 record_line 记录线路,通过API记录线路获得,中文,比如:默认,必选
165 value 记录值, 如 IP:200.200.200.200, CNAME: cname.dnspod.com., MX: mail.dnspod.com.,必选
166 mx {1-20} MX优先级, 当记录类型是 MX 时有效,范围1-20, mx记录必选
167 ttl {1-604800} TTL,范围1-604800,不同等级域名最小值不同,可选*/
168 var resObj = GetDNSApi("https://dnsapi.cn/Record.Modify", new
169 {
170 domain_id = domainId,
171 record_id = recordId,
172 value = value,
173 sub_domain = subdomain,
174 record_type = "A",
175 record_line = "默认"
176 });
177 if (resObj != null)
178 {
179 if (resObj["status"]["code"] == "1")
180 {
181 /*更新成功,返回记录详情(记录中的各参数)
182 * "record": {
183 * "id":16894439,
184 * "name":"@",
185 * "value":"3.2.2.2",
186 * "status":"enable"
187 * }
188 */
189 message = GetObjectPropertiesString(resObj["record"]);
190 flag = true;
191 }
192 else
193 {
194 message = resObj["status"]["message"];
195 throw new ArgumentException(string.Format("DNSPod API:Record.Modify调用异常,说明:{0}", resObj["status"]["message"]));
196 }
197 }
198 return flag;
199 }
200 /// <summary>
201 /// 设置记录备注
202 /// </summary>
203 /// <param name="domainId">域名ID</param>
204 /// <param name="recordId">记录ID</param>
205 /// <param name="remark">备注信息</param>
206 /// <returns></returns>
207 public bool RecordRemark(int domainId, int recordId, string remark = "")//设置记录备注
208 {
209 bool flag = false;
210 var resObj = GetDNSApi("https://dnsapi.cn/Record.Remark", new
211 {
212 domain_id = domainId,
213 record_id = recordId,
214 remark = remark
215 });
216 if (resObj != null && resObj["status"]["code"] == "1")
217 flag = true;
218 return flag;
219 }
220
221 #endregion
222
223 #region 辅助方法
224
225 /// <summary>
226 /// Send the webrequest to the api,and get the data of JSON!
227 /// </summary>
228 /// <param name="apiAddress">The API address for DNSPod</param>
229 /// <param name="data">The object type parameter with key/value pairs,like{type:"POST"}</param>
230 /// <returns></returns>
231 private dynamic GetDNSApi(string apiAddress, object data)
232 {
233 return GetDNSApi(apiAddress, GetApiParamDataString(data));
234 }
235 /// <summary>
236 /// Send the webrequest to the api,and get the data of JSON!
237 /// </summary>
238 /// <param name="apiAddress">The API address for DNSPod</param>
239 /// <param name="data">The data that will send to the api,like "type=post",split with "&" for more parameters!</param>
240 /// <returns>The returned data object</returns>
241 private dynamic GetDNSApi(string apiAddress, string data)
242 {
243
244 //若有额外参数,则将公共参数添加至参数请求中
245 if (!string.IsNullOrWhiteSpace(data))
246 {
247 data = string.Format("{0}&{1}", GetApiParamDataString(baseParam), data);
248 }
249 else
250 {
251 data = GetApiParamDataString(baseParam);//若无额外参数,只提交公共参数
252 }
253 HttpWebRequest request = (HttpWebRequest)WebRequest.Create(apiAddress);
254 request.Method = "POST";
255 request.Headers.Add("content", "text/html; charset=UTF-8");
256 request.ContentType = "application/x-www-form-urlencoded";
257 request.UserAgent = "ROS DDNS/V1";
258 byte[] postData = Encoding.UTF8.GetBytes(data);
259 request.ContentLength = postData.Length;
260 Stream smp = request.GetRequestStream();//得到请求流
261 smp.Write(postData, 0, postData.Length);//写入请求流
262 smp.Close();//关闭流
263
264
265 HttpWebResponse response = (HttpWebResponse)request.GetResponse();
266 StreamReader stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
267 string responseString = stream.ReadToEnd();//得到返回数据
268 stream.Close();
269 response.Close();
270 request = null;
271 dynamic obj = null;
272 if (!string.IsNullOrWhiteSpace(responseString))
273 {
274 obj = new JavaScriptSerializer().Deserialize(responseString, typeof(object) as dynamic);
275 }
276 return obj;
277 }
278 /// <summary>
279 ///
280 /// </summary>
281 /// <param name="data"></param>
282 /// <returns>The returned data of JSON</returns>
283 private string GetApiParamDataString(object data)
284 {
285 var dataString = string.Empty;
286 if (data != null)
287 {
288 //利用反复取可读属性或实例,返回属性集合
289 var objProperties = (from x in data.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance) where x.CanRead select x).ToList();
290 //将属性名与值拼接,返回string类型的数组
291 var arrProValue = (from y in objProperties select string.Format("{0}={1}", y.Name, y.GetValue(data, new object[0]))).ToList().ToArray();
292 //将数组以“&”连接
293 dataString = string.Join("&", arrProValue);
294 }
295 return dataString;
296 }
297 private string GetObjectPropertiesString(object obj)
298 {
299 var dataStr = new StringBuilder();
300 if (obj != null)
301 {
302 var d = obj as Dictionary<string, object>;
303 foreach (var item in d)
304 {
305 dataStr.AppendLine(string.Format("{0} - {1}", item.Key, item.Value));
306 }
307 }
308 return dataStr.ToString();
309 }
310
311 #endregion
312 }
313
314 #region 辅助类,用于返回dynamic类型对象
315
316 public class JsonParser
317 {
318 /// <summary>
319 /// 从json字符串到对象。
320 /// </summary>
321 /// <param name="jsonStr"></param>
322 /// <returns></returns>
323 public static dynamic FromJson(string jsonStr)
324 {
325 JavaScriptSerializer jss = new JavaScriptSerializer();
326 jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });
327
328 dynamic glossaryEntry = jss.Deserialize(jsonStr, typeof(object)) as dynamic;
329 return glossaryEntry;
330 }
331 }
332 public class DynamicJsonConverter : JavaScriptConverter
333 {
334 public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
335 {
336 if (dictionary == null)
337 throw new ArgumentNullException("dictionary");
338
339 if (type == typeof(object))
340 {
341 return new DynamicJsonObject(dictionary);
342 }
343
344 return null;
345 }
346
347 public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
348 {
349 throw new NotImplementedException();
350 }
351
352 public override IEnumerable<Type> SupportedTypes
353 {
354 get { return new ReadOnlyCollection<Type>(new List<Type>(new Type[] { typeof(object) })); }
355 }
356 }
357
358 public class DynamicJsonObject : DynamicObject
359 {
360 private IDictionary<string, object> Dictionary { get; set; }
361
362 public DynamicJsonObject(IDictionary<string, object> dictionary)
363 {
364 this.Dictionary = dictionary;
365 }
366
367 public override bool TryGetMember(GetMemberBinder binder, out object result)
368 {
369 result = this.Dictionary[binder.Name];
370
371 if (result is IDictionary<string, object>)
372 {
373 result = new DynamicJsonObject(result as IDictionary<string, object>);
374 }
375 else if (result is ArrayList)
376 {
377 result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
378 }
379 //else if (result is ArrayList && (result as ArrayList) is IDictionary<string, object>)
380 //{
381 // result = new List<DynamicJsonObject>((result as ArrayList).ToArray().Select(x => new DynamicJsonObject(x as IDictionary<string, object>)));
382 //}
383 //else if (result is ArrayList)
384 //{
385 // result = new List<object>((result as ArrayList).ToArray());
386 //}
387 return this.Dictionary.ContainsKey(binder.Name);
388 }
389 }
390 #endregion