WebExtension.cs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439
  1. using Masuit.Tools.Core.Config;
  2. using Masuit.Tools.Core.NoSQL;
  3. using Masuit.Tools.Logging;
  4. using Masuit.Tools.Models;
  5. using Masuit.Tools.NoSQL;
  6. using Microsoft.AspNetCore.Http;
  7. using Newtonsoft.Json;
  8. using Newtonsoft.Json.Linq;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Net.Http;
  14. using System.Net.Http.Headers;
  15. using System.Threading.Tasks;
  16. namespace Masuit.Tools.Core.Net
  17. {
  18. /// <summary>
  19. /// Web操作扩展
  20. /// </summary>
  21. public static class WebExtension
  22. {
  23. #region 获取线程内唯一的EF上下文对象
  24. /// <summary>
  25. /// 获取线程内唯一的EF上下文对象,.NetCore中获取EF数据上下文对象,需要通过依赖注入的方式,请考虑在自己的项目中通过Masuit.Tools提供的CallContext对象实现获取线程内唯一的EF上下文对象,示例代码:
  26. /// <para>public static DataContext GetDbContext()</para>
  27. /// <para>{</para>
  28. /// <para> DataContext db;</para>
  29. /// <para> if (CallContext&lt;DataContext>.GetData("db") is null)</para>
  30. /// <para> {</para>
  31. /// <para> DbContextOptions&lt;DataContext> dbContextOption = new DbContextOptions&lt;DataContext>();</para>
  32. /// <para> DbContextOptionsBuilder&lt;DataContext> dbContextOptionBuilder = new DbContextOptionsBuilder&lt;DataContext>(dbContextOption);</para>
  33. /// <para> db = new DataContext(dbContextOptionBuilder.UseSqlServer(CommonHelper.ConnectionString).Options);</para>
  34. /// <para> CallContext&lt;DataContext>.SetData("db", db);</para>
  35. /// <para> }</para>
  36. /// <para> db = CallContext&lt;DataContext>.GetData("db");</para>
  37. /// <para> return db;</para>
  38. /// <para>}</para>
  39. /// </summary>
  40. /// <typeparam name="T">EF上下文容器对象</typeparam>
  41. /// <returns>EF上下文容器对象</returns>
  42. [Obsolete(@".NetCore中获取EF数据上下文对象,需要通过依赖注入的方式,请考虑在自己的项目中通过Masuit.Tools提供的CallContext对象实现获取线程内唯一的EF上下文对象,示例代码:
  43. public static DataContext GetDbContext()
  44. {
  45. DataContext db;
  46. if (CallContext<DataContext>.GetData(""db"") is null)
  47. {
  48. DbContextOptions<DataContext> dbContextOption = new DbContextOptions<DataContext>();
  49. DbContextOptionsBuilder<DataContext> dbContextOptionBuilder = new DbContextOptionsBuilder<DataContext>(dbContextOption);
  50. db = new DataContext(dbContextOptionBuilder.UseSqlServer(CommonHelper.ConnectionString).Options);
  51. CallContext<DataContext>.SetData(""db"", db);
  52. }
  53. db = CallContext<DataContext>.GetData(""db"");
  54. return db;
  55. }")]
  56. public static T GetDbContext<T>() where T : new()
  57. {
  58. throw new Exception(@".NetCore中获取EF数据上下文对象,需要通过依赖注入的方式,请考虑在自己的项目中通过Masuit.Tools提供的CallContext对象实现获取线程内唯一的EF上下文对象,示例代码:
  59. public static DataContext GetDbContext()
  60. {
  61. DataContext db;
  62. if (CallContext<DataContext>.GetData(""db"") is null)
  63. {
  64. DbContextOptions<DataContext> dbContextOption = new DbContextOptions<DataContext>();
  65. DbContextOptionsBuilder<DataContext> dbContextOptionBuilder = new DbContextOptionsBuilder<DataContext>(dbContextOption);
  66. db = new DataContext(dbContextOptionBuilder.UseSqlServer(CommonHelper.ConnectionString).Options);
  67. CallContext<DataContext>.SetData(""db"", db);
  68. }
  69. db = CallContext<DataContext>.GetData(""db"");
  70. return db;
  71. }
  72. ");
  73. }
  74. #endregion
  75. #region 获取客户端IP地址信息
  76. /// <summary>
  77. /// 根据IP地址获取详细地理信息
  78. /// </summary>
  79. /// <param name="ip"></param>
  80. /// <returns></returns>
  81. public static async Task<Tuple<string, List<string>>> GetIPAddressInfo(this string ip)
  82. {
  83. ip.MatchInetAddress(out var isIpAddress);
  84. if (isIpAddress)
  85. {
  86. var address = await GetPhysicsAddressInfo(ip);
  87. if (address.Status == 0)
  88. {
  89. string detail = $"{address.AddressResult.FormattedAddress} {address.AddressResult.AddressComponent.Direction}{address.AddressResult.AddressComponent.Distance ?? "0"}米";
  90. List<string> pois = address.AddressResult.Pois.Select(p => $"{p.AddressDetail}{p.Name} {p.Direction}{p.Distance ?? "0"}米").ToList();
  91. return new Tuple<string, List<string>>(detail, pois);
  92. }
  93. return new Tuple<string, List<string>>("IP地址不正确", new List<string>());
  94. }
  95. return new Tuple<string, List<string>>($"{ip}不是一个合法的IP地址", new List<string>());
  96. }
  97. /// <summary>
  98. /// 根据IP地址获取详细地理信息对象
  99. /// </summary>
  100. /// <param name="ip"></param>
  101. /// <returns></returns>
  102. public static async Task<PhysicsAddress> GetPhysicsAddressInfo(this string ip)
  103. {
  104. ip.MatchInetAddress(out var isIpAddress);
  105. if (isIpAddress)
  106. {
  107. string ak = CoreConfig.Configuration["AppSettings:BaiduAK"];
  108. if (string.IsNullOrEmpty(ak))
  109. {
  110. throw new Exception("未配置BaiduAK,请先在您的应用程序web.config或者App.config中的AppSettings节点下添加BaiduAK配置节(注意大小写)");
  111. }
  112. using (HttpClient client = new HttpClient() { BaseAddress = new Uri("http://api.map.baidu.com") })
  113. {
  114. client.DefaultRequestHeaders.Referrer = new Uri("http://lbsyun.baidu.com/jsdemo.htm");
  115. var task = client.GetAsync($"/location/ip?ak={ak}&ip={ip}&coor=bd09ll").ContinueWith(async t =>
  116. {
  117. if (t.IsFaulted || t.IsCanceled)
  118. {
  119. return null;
  120. }
  121. var res = await t;
  122. if (res.IsSuccessStatusCode)
  123. {
  124. var ipAddress = JsonConvert.DeserializeObject<BaiduIP>(await res.Content.ReadAsStringAsync());
  125. if (ipAddress.Status == 0)
  126. {
  127. LatiLongitude point = ipAddress.AddressInfo.LatiLongitude;
  128. string result = client.GetStringAsync($"/geocoder/v2/?location={point.Y},{point.X}&output=json&pois=1&radius=1000&latest_admin=1&coordtype=bd09ll&ak={ak}").Result;
  129. PhysicsAddress address = JsonConvert.DeserializeObject<PhysicsAddress>(result);
  130. if (address.Status == 0)
  131. {
  132. return address;
  133. }
  134. }
  135. else
  136. {
  137. using (var client2 = new HttpClient { BaseAddress = new Uri("http://ip.taobao.com") })
  138. {
  139. return await await client2.GetAsync($"/service/getIpInfo.php?ip={ip}").ContinueWith(async tt =>
  140. {
  141. if (tt.IsFaulted || tt.IsCanceled)
  142. {
  143. return null;
  144. }
  145. var result = await tt;
  146. if (result.IsSuccessStatusCode)
  147. {
  148. TaobaoIP taobaoIp = JsonConvert.DeserializeObject<TaobaoIP>(await result.Content.ReadAsStringAsync());
  149. if (taobaoIp.Code == 0)
  150. {
  151. return new PhysicsAddress()
  152. {
  153. Status = 0,
  154. AddressResult = new AddressResult()
  155. {
  156. FormattedAddress = taobaoIp.IpData.Country + taobaoIp.IpData.Region + taobaoIp.IpData.City,
  157. AddressComponent = new AddressComponent()
  158. {
  159. Province = taobaoIp.IpData.Region
  160. },
  161. Pois = new List<Pois>()
  162. }
  163. };
  164. }
  165. }
  166. return null;
  167. });
  168. }
  169. }
  170. }
  171. return null;
  172. });
  173. return await await task;
  174. }
  175. }
  176. return null;
  177. }
  178. /// <summary>
  179. /// 根据IP地址获取ISP
  180. /// </summary>
  181. /// <param name="ip"></param>
  182. /// <returns></returns>
  183. public static string GetISP(this string ip)
  184. {
  185. if (ip.MatchInetAddress())
  186. {
  187. using (var client = new HttpClient { BaseAddress = new Uri("http://ip.taobao.com") })
  188. {
  189. var task = client.GetAsync($"/service/getIpInfo.php?ip={ip}").ContinueWith(async t =>
  190. {
  191. if (t.IsFaulted)
  192. {
  193. return $"未能找到{ip}的ISP信息";
  194. }
  195. var result = await t;
  196. if (result.IsSuccessStatusCode)
  197. {
  198. TaobaoIP taobaoIp = JsonConvert.DeserializeObject<TaobaoIP>(await result.Content.ReadAsStringAsync());
  199. if (taobaoIp.Code == 0)
  200. {
  201. return taobaoIp.IpData.Isp;
  202. }
  203. }
  204. return $"未能找到{ip}的ISP信息";
  205. });
  206. return task.Result.Result;
  207. }
  208. }
  209. return $"{ip}不是一个合法的IP";
  210. }
  211. #endregion
  212. /// <summary>
  213. /// 上传图片到百度图床
  214. /// </summary>
  215. /// <param name="stream"></param>
  216. /// <returns></returns>
  217. public static async Task<string> UploadImageAsync(Stream stream)
  218. {
  219. using (HttpClient httpClient = new HttpClient()
  220. {
  221. BaseAddress = new Uri("https://sp1.baidu.com"),
  222. })
  223. {
  224. httpClient.DefaultRequestHeaders.UserAgent.Add(ProductInfoHeaderValue.Parse("Mozilla/5.0"));
  225. using (var bc = new StreamContent(stream))
  226. {
  227. bc.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
  228. {
  229. FileName = "1.jpg",
  230. Name = "image"
  231. };
  232. bc.Headers.ContentType = MediaTypeHeaderValue.Parse("image/jpeg");
  233. using (var content = new MultipartFormDataContent { bc })
  234. {
  235. return await await httpClient.PostAsync("/70cHazva2gU2pMbgoY3K/n/image?needJson=true", content).ContinueWith(async t =>
  236. {
  237. if (t.IsCanceled || t.IsFaulted)
  238. {
  239. Console.WriteLine("发送请求出错了" + t.Exception);
  240. return string.Empty;
  241. }
  242. var res = await t;
  243. if (res.IsSuccessStatusCode)
  244. {
  245. string s = await res.Content.ReadAsStringAsync();
  246. var token = JObject.Parse(s);
  247. if ((int)token["errno"] == 0)
  248. {
  249. s = (string)token["data"]["imageUrl"];
  250. return s;
  251. }
  252. s = (string)token["errmsg"];
  253. return s;
  254. }
  255. return string.Empty;
  256. });
  257. }
  258. }
  259. }
  260. }
  261. #region 写Session
  262. /// <summary>
  263. /// 写Session
  264. /// </summary>
  265. /// <param name="session"></param>
  266. /// <param name="key">键</param>
  267. /// <param name="value">值</param>
  268. public static void Set(this ISession session, string key, object value)
  269. {
  270. session.SetString(key, value.ToJsonString());
  271. }
  272. /// <summary>
  273. /// 将Session存到Redis,需要先在config中配置链接字符串,连接字符串在config配置文件中的ConnectionStrings节下配置,name固定为RedisHosts,值的格式:127.0.0.1:6379,allowadmin=true,若未正确配置,将按默认值“127.0.0.1:6379,allowadmin=true”进行操作,如:<br/>
  274. /// &lt;connectionStrings&gt;<br/>
  275. /// &lt;add name = "RedisHosts" connectionString="127.0.0.1:6379,allowadmin=true"/&gt;<br/>
  276. /// &lt;/connectionStrings&gt;
  277. /// </summary>
  278. /// <typeparam name="T"></typeparam>
  279. /// <param name="session"></param>
  280. /// <param name="key">键</param>
  281. /// <param name="obj">需要存的对象</param>
  282. /// <param name="expire">过期时间,默认20分钟</param>
  283. /// <returns></returns>
  284. public static void SetByRedis<T>(this ISession session, string key, T obj, int expire = 20)
  285. {
  286. if (HttpContext2.Current is null)
  287. {
  288. throw new Exception("请确保此方法调用是在同步线程中执行!");
  289. }
  290. session?.SetString(key, obj.ToJsonString());
  291. try
  292. {
  293. using (RedisHelper redisHelper = RedisHelper.GetInstance(RedisHelperFactory.ConnectionCache.Values.FirstOrDefault() ?? throw new ArgumentException("在使用该方法之前,请先在Startup.cs中配置services.AddxxxRedisHelper"), 1))
  294. {
  295. redisHelper.SetHash("Session:" + HttpContext2.Current.Connection.Id, key, obj, TimeSpan.FromMinutes(expire)); //存储数据到缓存服务器,这里将字符串"my value"缓存,key 是"test"
  296. }
  297. }
  298. catch
  299. {
  300. // ignored
  301. }
  302. }
  303. #endregion
  304. #region 获取Session
  305. /// <summary>
  306. /// 获取Session
  307. /// </summary>
  308. /// <typeparam name="T">对象</typeparam>
  309. /// <param name="session"></param>
  310. /// <param name="key">键</param>
  311. /// <returns>对象</returns>
  312. public static T Get<T>(this ISession session, string key)
  313. {
  314. string value = session.GetString(key);
  315. if (string.IsNullOrEmpty(value))
  316. {
  317. return default(T);
  318. }
  319. return JsonConvert.DeserializeObject<T>(value);
  320. }
  321. /// <summary>
  322. /// 从Redis取Session
  323. /// </summary>
  324. /// <typeparam name="T"></typeparam>
  325. /// <param name="_"></param>
  326. /// <param name="key">键</param>
  327. /// <param name="expire">过期时间,默认20分钟</param>
  328. /// <returns></returns>
  329. public static T GetByRedis<T>(this ISession _, string key, int expire = 20) where T : class
  330. {
  331. if (HttpContext2.Current is null)
  332. {
  333. throw new Exception("请确保此方法调用是在同步线程中执行!");
  334. }
  335. T obj = default(T);
  336. if (_ != null)
  337. {
  338. obj = _.Get<T>(key);
  339. }
  340. if (obj == default(T))
  341. {
  342. try
  343. {
  344. var sessionKey = "Session:" + HttpContext2.Current.Connection.Id;
  345. using (RedisHelper redisHelper = RedisHelper.GetInstance(RedisHelperFactory.ConnectionCache.Values.FirstOrDefault() ?? throw new ArgumentException("在使用该方法之前,请先在Startup.cs中配置services.AddxxxRedisHelper"), 1))
  346. {
  347. if (redisHelper.KeyExists(sessionKey) && redisHelper.HashExists(sessionKey, key))
  348. {
  349. redisHelper.Expire(sessionKey, TimeSpan.FromMinutes(expire));
  350. return redisHelper.GetHash<T>(sessionKey, key);
  351. }
  352. return default(T);
  353. }
  354. }
  355. catch
  356. {
  357. return default(T);
  358. }
  359. }
  360. return obj;
  361. }
  362. /// <summary>
  363. /// 从Redis移除对应键的Session
  364. /// </summary>
  365. /// <param name="session"></param>
  366. /// <param name="key"></param>
  367. /// <returns></returns>
  368. public static void RemoveByRedis(this ISession session, string key)
  369. {
  370. if (HttpContext2.Current is null)
  371. {
  372. throw new Exception("请确保此方法调用是在同步线程中执行!");
  373. }
  374. session?.Remove(key);
  375. try
  376. {
  377. var sessionKey = "Session:" + HttpContext2.Current.Connection.Id;
  378. using (RedisHelper redisHelper = RedisHelper.GetInstance(RedisHelperFactory.ConnectionCache.Values.FirstOrDefault() ?? throw new ArgumentException("在使用该方法之前,请先在Startup.cs中配置services.AddxxxRedisHelper"), 1))
  379. {
  380. if (redisHelper.KeyExists(sessionKey) && redisHelper.HashExists(sessionKey, key))
  381. {
  382. redisHelper.DeleteHash(sessionKey, key);
  383. }
  384. }
  385. }
  386. catch (Exception e)
  387. {
  388. LogManager.Error(e);
  389. }
  390. }
  391. /// <summary>
  392. /// Session个数
  393. /// </summary>
  394. /// <param name="session"></param>
  395. /// <returns></returns>
  396. public static int SessionCount(this ISession session)
  397. {
  398. try
  399. {
  400. using (RedisHelper redisHelper = RedisHelper.GetInstance(RedisHelperFactory.ConnectionCache.Values.FirstOrDefault() ?? throw new ArgumentException("在使用该方法之前,请先在Startup.cs中配置services.AddxxxRedisHelper"), 1))
  401. {
  402. return redisHelper.GetServer().Keys(1, "Session:*").Count();
  403. }
  404. }
  405. catch (Exception e)
  406. {
  407. LogManager.Error(e);
  408. return 0;
  409. }
  410. }
  411. #endregion
  412. }
  413. }