日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

仿微信 即时聊天工具 - SignalR (一)

發(fā)布時間:2024/8/1 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 仿微信 即时聊天工具 - SignalR (一) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

話不多說,先上圖

?

?

?

?

?

?

背景:

微信聊天,經(jīng)常會遇見視頻發(fā)不了,嗯,還有聊天不方便的問題,于是我就自己買了服務(wù)器,部署了一套可以直接在微信打開的網(wǎng)頁進行聊天,這樣只需要發(fā)送個url給朋友,就能聊天了!

由于自己無聊弄著玩的,代碼比較粗糙,各位多指正!

1、首先安裝SignalR,這步我就不做過多說明了

安裝好以后在根目錄新建一個Hubs文件夾,做用戶的注冊和通知

MessageHub.cs 文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

using?Microsoft.AspNet.SignalR;

using?Microsoft.AspNet.SignalR.Hubs;

using?System;

using?System.Collections;

using?System.Collections.Generic;

using?System.Linq;

using?System.Threading;

using?System.Threading.Tasks;

using?System.Web;

?

namespace?SignalR.Hubs

{

????[HubName("MessageHub")]

????public?class?MessageHub : Hub

????????{

????????????private?readonly?ChatTicker ticker;

????????????public?MessageHub()

????????????{

????????????????ticker = ChatTicker.Instance;

????????????}

?

????????????public?void?register(string?username,?string?group?=?"default")

????????????{

????????????????var?list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");

????????????????if?(list ==?null)

????????????????{

????????????????????list =?new?List<SiginalRModel>();

????????????????}

????????????????

?

????????????????if?(list.Any(x => x.connectionId == Context.ConnectionId))

????????????????{

????????????????????Clients.Client(Context.ConnectionId).broadcastMessage("已經(jīng)注冊,無需再次注冊");

????????????????}

????????????else?if?(list.Any(x => x.name == username))

????????????{

????????????????var?model = list.Where(x => x.name == username && x.group?==?group).FirstOrDefault();

????????????????if?(model !=?null)

????????????????{

????????????????????//注冊到全局?

????????????????????ticker.GlobalContext.Groups.Add(Context.ConnectionId,?group);

????????????????????Clients.Client(model.connectionId).exit();

????????????????????ticker.GlobalContext.Groups.Remove(model.connectionId,?group);

????????????????????list.Remove(model);

????????????????????model.connectionId = Context.ConnectionId;

????????????????????list.Add(model);

????????????????????Clients.Group(group).removeUserList(model.connectionId);

????????????????????Thread.Sleep(200);

????????????????????var?gourpList = list.Where(x => x.group?==?group).ToList();

????????????????????Clients.Group(group).appendUserList(Context.ConnectionId, gourpList);

????????????????????HttpRuntime.Cache.Insert("msg_hs", list);

????????????????????// Clients.Client(model.connectionId).broadcastMessage("名稱重復(fù),只能注冊一個");

????????????????}

????????????????//Clients.Client(Context.ConnectionId).broadcastMessage("名稱重復(fù),只能注冊一個");

????????????}

????????????else

????????????????{

????????????????????list.Add(new?SiginalRModel() { name = username,?group?=?group, connectionId = Context.ConnectionId });

?

????????????????????//注冊到全局?

????????????????????ticker.GlobalContext.Groups.Add(Context.ConnectionId,?group);

????????????????????Thread.Sleep(200);

?

????????????????????var?gourpList = list.Where(x => x.group?==?group).ToList();

????????????????????Clients.Group(group).appendUserList(Context.ConnectionId, gourpList);

????????????????????HttpRuntime.Cache.Insert("msg_hs", list);

????????????????}

?

????????????}

?

????????????public?void?Say(string?msg)

????????????{

????????????????var?list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");

????????????????if?(list ==?null)

????????????????{

????????????????????list =?new?List<SiginalRModel>();

????????????????}

????????????????var?userModel = list.Where(x => x.connectionId == Context.ConnectionId).FirstOrDefault();

????????????????if?(userModel !=?null?)

????????????????{

????????????????????Clients.Group(userModel.group).Say(userModel.name, msg);

????????????????}

????????????}

?

????????public?void?Exit()

????????{

????????????OnDisconnected(true);

????????}

?

????????public?override?Task OnDisconnected(bool?s)

????????????????{

????????????????????var?list = (List<SiginalRModel>)HttpRuntime.Cache.Get("msg_hs");

????????????????????if?(list ==?null)

????????????????????{

????????????????????????list =?new?List<SiginalRModel>();

????????????????????}

????????????????????var?closeModel = list.Where(x => x.connectionId == Context.ConnectionId).FirstOrDefault();

?

????????????????????if?(closeModel !=?null)

????????????????????{

????????????????????????list.Remove(closeModel);

?

????????????????????????Clients.Group(closeModel.group).removeUserList(Context.ConnectionId);

?

?????????????????????}

????????????????????HttpRuntime.Cache.Insert("msg_hs", list);

?????????????????

????????????????????return?base.OnDisconnected(s);

????????????????}

????????????}

?????????

?

????public?class?ChatTicker

????????{

????????????#region 實現(xiàn)一個單例

?

????????????private?static?readonly?ChatTicker _instance =

????????????????new?ChatTicker(GlobalHost.ConnectionManager.GetHubContext<MessageHub>());

?

????????????private?readonly?IHubContext m_context;

?

????????????private?ChatTicker(IHubContext context)

????????????{

?

????????????????m_context = context;

????????????????//這里不能直接調(diào)用Sender,因為Sender是一個不退出的“死循環(huán)”,否則這個構(gòu)造函數(shù)將不會退出。?

????????????????//其他的流程也將不會再執(zhí)行下去了。所以要采用異步的方式。?

????????????????//Task.Run(() => Sender());

????????????}

?

????????????public?IHubContext GlobalContext

????????????{

????????????????get?{?return?m_context; }

????????????}

?

????????????public?static?ChatTicker Instance

????????????{

????????????????get?{?return?_instance; }

????????????}

?

????????????#endregion

????????}

?

????public?class?SiginalRModel {

????????public?string?connectionId {?get;?set; }

?

????????public?string?group?{?get;?set; }

????????public?string?name {?get;?set; }

????}

}<br data-filtered="filtered"><br data-filtered="filtered">我把類和方法都寫到一塊了,大家最好是分開!

?

接下來是控制器

HomeController.cs

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

using?Microsoft.AspNet.SignalR;

using?Microsoft.AspNet.SignalR.Client;

using?SignalR.Hubs;

using?SignalR.ViewModels;

using?System;

using?System.Collections;

using?System.Collections.Generic;

using?System.IO;

using?System.Linq;

using?System.Web;

using?System.Web.Mvc;

using?Newtonsoft.Json;

using?System.Diagnostics;

using?System.Text.RegularExpressions;

?

namespace?SignalR.Controllers

{

????public?class?HomeController : Controller

????{

????????public?ActionResult Index()

????????{

?????

????????????return?View();

????????}

?

?

????????public?ActionResult GetV(string?v)

????????{

????????????if?(!string.IsNullOrEmpty(v))

????????????{

????????????????string?url = RedisHelper.Get(v)?.ToString();

????????????????if?(!string.IsNullOrEmpty(url))

????????????????{

????????????????????return?Json(new?{ isOk =?true, m = url }, JsonRequestBehavior.AllowGet);

????????????????}

????????????????return?Json(new?{ isOk =?false}, JsonRequestBehavior.AllowGet);

????????????}

????????????return?Json(new?{ isOk =?false?}, JsonRequestBehavior.AllowGet);

????????}

?

????????public?ActionResult getkey(string?url)

????????{

????????????if?(!string.IsNullOrEmpty(url))

????????????{

????????????????var?s =?"v"?+ Util.GetRandomLetterAndNumberString(new?Random(), 5).ToLower();

????????????????var?dt = Convert.ToDateTime(DateTime.Now.AddDays(1).ToString("yyyy-MM-dd 04:00:00"));

????????????????int?min = Convert.ToInt16((dt - DateTime.Now).TotalMinutes);

????????????????RedisHelper.Set(s, url, min);

????????????????return?Json(new?{ isOk =?true, m = s }, JsonRequestBehavior.AllowGet);

????????????}

????????????return?Json(new?{ isOk =?false?}, JsonRequestBehavior.AllowGet);

????????}

?

????????public?ActionResult upfile()

????????{

????????????try

????????????{

????????????????if?(Request.Files.Count > 0)

????????????????{

????????????????????var?file = Request.Files[0];

????????????????????if?(file !=?null)

????????????????????{

????????????????????????var?imgList =?new?List<string>() {?".gif",?".jpg",?".bmp",?".png"?};

????????????????????????var?videoList =?new?List<string>() {?".mp4"?};

????????????????????????FileModel fmodel =?new?FileModel();

?

????????????????????????string?name = Guid.NewGuid().ToString();

????????????????????????string?fileExt = Path.GetExtension(file.FileName).ToLower();//上傳文件擴展名

????????????????????????string?path = Server.MapPath("~/files/") + name + fileExt;

????????????????????????file.SaveAs(path);

?

????????????????????????string?extension =?new?FileInfo(path).Extension;

?

????????????????????????if?(extension ==?".mp4")

????????????????????????{

????????????????????????????fmodel.t = 2;

????????????????????????}

????????????????????????else?if?(imgList.Contains(extension))

????????????????????????{

????????????????????????????fmodel.t = 1;

????????????????????????}

????????????????????????else

????????????????????????{

????????????????????????????fmodel.t = 0;

????????????????????????}

????????????????????????string?url = Guid.NewGuid().ToString();

????????????????????????fmodel.url =?"http://"?+ Request.Url.Host;

????????????????????????if?(Request.Url.Port != 80)

????????????????????????{

????????????????????????????fmodel.url +=?":"?+ Request.Url.Port;

????????????????????????}

????????????????????????fmodel.url +=?"/files/"?+ name + fileExt;

????????????????????????GetImageThumb(Server.MapPath("~") +?"files\\"?+ name + fileExt, name);

????????????????????????return?Json(new?{ isOk =?true, m =?"file:"?+ JsonConvert.SerializeObject(fmodel) }, JsonRequestBehavior.AllowGet);

????????????????????}

????????????????}

????????????}

????????????catch(Exception ex)

????????????{

????????????????Log.Info(ex);

????????????}

????????????

????????????

????????????return?Content("");

????????}

?

????????public?string?GetImageThumb(string?localVideo,string?name)

????????{

????????????string?path = AppDomain.CurrentDomain.BaseDirectory;

????????????string?ffmpegPath = path +?"/ffmpeg.exe";

????????????string?oriVideoPath = localVideo;

????????????int?frameIndex = 5;

????????????int?_thubWidth;

????????????int?_thubHeight;

????????????GetMovWidthAndHeight(localVideo,?out?_thubWidth,?out?_thubHeight);

????????????int?thubWidth = 200;

????????????int?thubHeight = _thubWidth == 0 ? 200 : (thubWidth * _thubHeight / _thubWidth );?

?????????????

????????????string?thubImagePath = path +??"files\\"?+ name +?".jpg";

????????????string?command =?string.Format("\"{0}\" -i \"{1}\" -ss {2} -vframes 1 -r 1 -ac 1 -ab 2 -s {3}*{4} -f image2 \"{5}\"", ffmpegPath, oriVideoPath, frameIndex, thubWidth, thubHeight, thubImagePath);

????????????Cmd.RunCmd(command);

????????????return?name;

????????}

?

????????/// <summary>

????????/// 獲取視頻的幀寬度和幀高度

????????/// </summary>

????????/// <param name="videoFilePath">mov文件的路徑</param>

????????/// <returns>null表示獲取寬度或高度失敗</returns>

????????public?static?void?GetMovWidthAndHeight(string?videoFilePath,?out?int?width,?out?int?height)

????????{

????????????try

????????????{

?

????????????????//執(zhí)行命令獲取該文件的一些信息

????????????????string?ffmpegPath = AppDomain.CurrentDomain.BaseDirectory +??"/ffmpeg.exe";

????????????????string?output;

????????????????string?error;

????????????????ExecuteCommand("\""?+ ffmpegPath +?"\""?+?" -i "?+?"\""?+ videoFilePath +?"\"",?out?output,?out?error);

????????????????if?(string.IsNullOrEmpty(error))

????????????????{

????????????????????width = 0;

????????????????????height = 0;

????????????????}

?

????????????????//通過正則表達式獲取信息里面的寬度信息

????????????????Regex regex =?new?Regex("(\\d{2,4})x(\\d{2,4})", RegexOptions.Compiled);

????????????????Match m = regex.Match(error);

????????????????if?(m.Success)

????????????????{

????????????????????width =?int.Parse(m.Groups[1].Value);

????????????????????height =?int.Parse(m.Groups[2].Value);

????????????????}

????????????????else

????????????????{

????????????????????width = 0;

????????????????????height = 0;

????????????????}

????????????}

????????????catch?(Exception)

????????????{

????????????????width = 0;

????????????????height = 0;

????????????}

????????}

?

????????public?static?void?ExecuteCommand(string?command,?out?string?output,?out?string?error)

????????{

????????????try

????????????{

????????????????//創(chuàng)建一個進程

????????????????Process pc =?new?Process();

????????????????pc.StartInfo.FileName = command;

????????????????pc.StartInfo.UseShellExecute =?false;

????????????????pc.StartInfo.RedirectStandardOutput =?true;

????????????????pc.StartInfo.RedirectStandardError =?true;

????????????????pc.StartInfo.CreateNoWindow =?true;

?

????????????????//啟動進程

????????????????pc.Start();

?

????????????????//準(zhǔn)備讀出輸出流和錯誤流

????????????????string?outputData =?string.Empty;

????????????????string?errorData =?string.Empty;

????????????????pc.BeginOutputReadLine();

????????????????pc.BeginErrorReadLine();

?

????????????????pc.OutputDataReceived += (ss, ee) =>

????????????????{

????????????????????outputData += ee.Data;

????????????????};

?

????????????????pc.ErrorDataReceived += (ss, ee) =>

????????????????{

????????????????????errorData += ee.Data;

????????????????};

?

????????????????//等待退出

????????????????pc.WaitForExit();

?

????????????????//關(guān)閉進程

????????????????pc.Close();

?

????????????????//返回流結(jié)果

????????????????output = outputData;

????????????????error = errorData;

????????????}

????????????catch?(Exception)

????????????{

????????????????output =?null;

????????????????error =?null;

????????????}

????????}

?

????}

?

????public?class?Util

????{

????????public?static?string?GetRandomLetterAndNumberString(Random random,?int?length)

????????{

????????????if?(length < 0)

????????????{

????????????????throw?new?ArgumentOutOfRangeException("length");

????????????}

????????????char[] pattern =?new?char[] {?'0',?'1',?'2',?'3',?'4',?'5',?'6',?'7',?'8',?'9',

????????'A',?'B',?'C',?'D',?'E',?'F',?'G',?'H',?'I',?'J',?'K',?'L',?'M',?'N',?'O',?'P',

????????'Q',?'R',?'S',?'T',?'U',?'V',?'W',?'X',?'Y',?'Z'?};

????????????string?result =?"";

????????????int?n = pattern.Length;

????????????for?(int?i = 0; i < length; i++)

????????????{

????????????????int?rnd = random.Next(0, n);

????????????????result += pattern[rnd];

????????????}

????????????return?result;

????????}

????}

?

????class?Cmd

????{

????????private?static?string?CmdPath =?@"C:\Windows\System32\cmd.exe";

????????/// <summary>

????????/// 執(zhí)行cmd命令 返回cmd窗口顯示的信息

????????/// 多命令請使用批處理命令連接符:

????????/// <![CDATA[

????????/// &:同時執(zhí)行兩個命令

????????/// |:將上一個命令的輸出,作為下一個命令的輸入

????????/// &&:當(dāng)&&前的命令成功時,才執(zhí)行&&后的命令

????????/// ||:當(dāng)||前的命令失敗時,才執(zhí)行||后的命令]]>

????????/// </summary>

????????/// <param name="cmd">執(zhí)行的命令</param>

????????public?static?string?RunCmd(string?cmd)

????????{

????????????cmd = cmd.Trim().TrimEnd('&') +?"&exit";//說明:不管命令是否成功均執(zhí)行exit命令,否則當(dāng)調(diào)用ReadToEnd()方法時,會處于假死狀態(tài)

????????????using?(Process p =?new?Process())

????????????{

????????????????p.StartInfo.FileName = CmdPath;

????????????????p.StartInfo.UseShellExecute =?false;????????//是否使用操作系統(tǒng)shell啟動

????????????????p.StartInfo.RedirectStandardInput =?true;???//接受來自調(diào)用程序的輸入信息

????????????????p.StartInfo.RedirectStandardOutput =?true;??//由調(diào)用程序獲取輸出信息

????????????????p.StartInfo.RedirectStandardError =?true;???//重定向標(biāo)準(zhǔn)錯誤輸出

????????????????p.StartInfo.CreateNoWindow =?true;??????????//不顯示程序窗口

????????????????p.Start();//啟動程序

?

????????????????//向cmd窗口寫入命令

????????????????p.StandardInput.WriteLine(cmd);

????????????????p.StandardInput.AutoFlush =?true;

?

????????????????//獲取cmd窗口的輸出信息

????????????????string?output = p.StandardOutput.ReadToEnd();

????????????????p.WaitForExit();//等待程序執(zhí)行完退出進程

????????????????p.Close();

?

????????????????return?output;

????????????}

????????}

????}

}<br data-filtered="filtered"><br data-filtered="filtered">我還是都寫到一塊了,大家記得分開!

SController.cs? 這個是針對手機端單獨拎出來的,里面不需要什么內(nèi)容

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

using?System;

using?System.Collections.Generic;

using?System.Linq;

using?System.Web;

using?System.Web.Mvc;

?

namespace?SignalR.Controllers

{

????public?class?SController : Controller

????{

????????// GET: S

????????public?ActionResult Index()

????????{

????????????return?View();

????????}

????}

}

 根目錄新建一個ViewModels文件夾,里面新建FileModel.cs文件

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

using?System;

using?System.Collections.Generic;

using?System.Linq;

using?System.Web;

?

namespace?SignalR.ViewModels

{

????public?class?FileModel

????{

????????/// <summary>

????????/// 1 : 圖片? 2:視頻

????????/// </summary>

????????public?int?t {?get;?set; }

?

????????public?string?url {?get;?set; }

????}

} 

RedisHelper.cs

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

using?Microsoft.AspNet.SignalR.Messaging;

using?StackExchange.Redis;

using?System;

using?System.Collections.Generic;

using?System.IO;

using?System.Linq;

using?System.Net;

using?System.Runtime.Serialization.Formatters.Binary;

using?System.Threading.Tasks;

using?System.Web;

?

namespace?SignalR

{

????public?class?RedisHelper

????{

????????private?static?string?Constr =?"xxxx.cn:6379";

?

????????private?static?object?_locker =?new?Object();

????????private?static?ConnectionMultiplexer _instance =?null;

?

????????/// <summary>

????????/// 使用一個靜態(tài)屬性來返回已連接的實例,如下列中所示。這樣,一旦 ConnectionMultiplexer 斷開連接,便可以初始化新的連接實例。

????????/// </summary>

????????public?static?ConnectionMultiplexer Instance

????????{

????????????get

????????????{

????????????????if?(Constr.Length == 0)

????????????????{

????????????????????throw?new?Exception("連接字符串未設(shè)置!");

????????????????}

????????????????if?(_instance ==?null)

????????????????{

????????????????????lock?(_locker)

????????????????????{

????????????????????????if?(_instance ==?null?|| !_instance.IsConnected)

????????????????????????{

????????????????????????????_instance = ConnectionMultiplexer.Connect(Constr);

????????????????????????}

????????????????????}

????????????????}

????????????????//注冊如下事件

????????????????_instance.ConnectionFailed += MuxerConnectionFailed;

????????????????_instance.ConnectionRestored += MuxerConnectionRestored;

????????????????_instance.ErrorMessage += MuxerErrorMessage;

????????????????_instance.ConfigurationChanged += MuxerConfigurationChanged;

????????????????_instance.HashSlotMoved += MuxerHashSlotMoved;

????????????????_instance.InternalError += MuxerInternalError;

????????????????return?_instance;

????????????}

????????}

?

????????static?RedisHelper()

????????{

????????}

?

?

????????/// <summary>

????????///

????????/// </summary>

????????/// <returns></returns>

????????public?static?IDatabase GetDatabase()

????????{

????????????return?Instance.GetDatabase();

????????}

?

????????/// <summary>

????????/// 這里的 MergeKey 用來拼接 Key 的前綴,具體不同的業(yè)務(wù)模塊使用不同的前綴。

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????private?static?string?MergeKey(string?key)

????????{

????????????return?"SignalR:"+ key;

????????????//return BaseSystemInfo.SystemCode + key;

????????}

?

????????/// <summary>

????????/// 根據(jù)key獲取緩存對象

????????/// </summary>

????????/// <typeparam name="T"></typeparam>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?T Get<T>(string?key)

????????{

????????????key = MergeKey(key);

????????????return?Deserialize<T>(GetDatabase().StringGet(key));

????????}

?

????????/// <summary>

????????/// 根據(jù)key獲取緩存對象

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?object?Get(string?key)

????????{

????????????key = MergeKey(key);

????????????return?Deserialize<object>(GetDatabase().StringGet(key));

????????}

?

????????/// <summary>

????????/// 設(shè)置緩存

????????/// </summary>

????????/// <param name="key"></param>

????????/// <param name="value"></param>

????????/// <param name="expireMinutes"></param>

????????public?static?void?Set(string?key,?object?value,?int?expireMinutes = 0)

????????{

????????????key = MergeKey(key);

????????????if?(expireMinutes > 0)

????????????{

????????????????GetDatabase().StringSet(key, Serialize(value), TimeSpan.FromMinutes(expireMinutes));

????????????}

????????????else

????????????{

????????????????GetDatabase().StringSet(key, Serialize(value));

????????????}

?

????????}

?

?

????????/// <summary>

????????/// 判斷在緩存中是否存在該key的緩存數(shù)據(jù)

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?bool?Exists(string?key)

????????{

????????????key = MergeKey(key);

????????????return?GetDatabase().KeyExists(key);?//可直接調(diào)用

????????}

?

????????/// <summary>

????????/// 移除指定key的緩存

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?bool?Remove(string?key)

????????{

????????????key = MergeKey(key);

????????????return?GetDatabase().KeyDelete(key);

????????}

?

????????/// <summary>

????????/// 異步設(shè)置

????????/// </summary>

????????/// <param name="key"></param>

????????/// <param name="value"></param>

????????public?static?async Task SetAsync(string?key,?object?value)

????????{

????????????key = MergeKey(key);

????????????await GetDatabase().StringSetAsync(key, Serialize(value));

????????}

?

????????/// <summary>

????????/// 根據(jù)key獲取緩存對象

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?async Task<object> GetAsync(string?key)

????????{

????????????key = MergeKey(key);

????????????object?value = await GetDatabase().StringGetAsync(key);

????????????return?value;

????????}

?

????????/// <summary>

????????/// 實現(xiàn)遞增

????????/// </summary>

????????/// <param name="key"></param>

????????/// <returns></returns>

????????public?static?long?Increment(string?key)

????????{

????????????key = MergeKey(key);

????????????//三種命令模式

????????????//Sync,同步模式會直接阻塞調(diào)用者,但是顯然不會阻塞其他線程。

????????????//Async,異步模式直接走的是Task模型。

????????????//Fire - and - Forget,就是發(fā)送命令,然后完全不關(guān)心最終什么時候完成命令操作。

????????????//即發(fā)即棄:通過配置 CommandFlags 來實現(xiàn)即發(fā)即棄功能,在該實例中該方法會立即返回,如果是string則返回null 如果是int則返回0.這個操作將會繼續(xù)在后臺運行,一個典型的用法頁面計數(shù)器的實現(xiàn):

????????????return?GetDatabase().StringIncrement(key, flags: CommandFlags.FireAndForget);

????????}

?

????????/// <summary>

????????/// 實現(xiàn)遞減

????????/// </summary>

????????/// <param name="key"></param>

????????/// <param name="value"></param>

????????/// <returns></returns>

????????public?static?long?Decrement(string?key,?string?value)

????????{

????????????key = MergeKey(key);

????????????return?GetDatabase().HashDecrement(key, value, flags: CommandFlags.FireAndForget);

????????}

?

????????/// <summary>

????????/// 序列化對象

????????/// </summary>

????????/// <param name="o"></param>

????????/// <returns></returns>

????????private?static?byte[] Serialize(object?o)

????????{

????????????if?(o ==?null)

????????????{

????????????????return?null;

????????????}

????????????BinaryFormatter binaryFormatter =?new?BinaryFormatter();

????????????using?(MemoryStream memoryStream =?new?MemoryStream())

????????????{

????????????????binaryFormatter.Serialize(memoryStream, o);

????????????????byte[] objectDataAsStream = memoryStream.ToArray();

????????????????return?objectDataAsStream;

????????????}

????????}

?

????????/// <summary>

????????/// 反序列化對象

????????/// </summary>

????????/// <typeparam name="T"></typeparam>

????????/// <param name="stream"></param>

????????/// <returns></returns>

????????private?static?T Deserialize<T>(byte[] stream)

????????{

????????????if?(stream ==?null)

????????????{

????????????????return?default(T);

????????????}

????????????BinaryFormatter binaryFormatter =?new?BinaryFormatter();

????????????using?(MemoryStream memoryStream =?new?MemoryStream(stream))

????????????{

????????????????T result = (T)binaryFormatter.Deserialize(memoryStream);

????????????????return?result;

????????????}

????????}

?

????????/// <summary>

????????/// 配置更改時

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerConfigurationChanged(object?sender, EndPointEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("Configuration changed: " + e.EndPoint);

????????}

?

????????/// <summary>

????????/// 發(fā)生錯誤時

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerErrorMessage(object?sender, RedisErrorEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("ErrorMessage: " + e.Message);

????????}

?

????????/// <summary>

????????/// 重新建立連接之前的錯誤

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerConnectionRestored(object?sender, ConnectionFailedEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("ConnectionRestored: " + e.EndPoint);

????????}

?

????????/// <summary>

????????/// 連接失敗 , 如果重新連接成功你將不會收到這個通知

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerConnectionFailed(object?sender, ConnectionFailedEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("重新連接:Endpoint failed: " + e.EndPoint + ", " + e.FailureType +(e.Exception == null ? "" : (", " + e.Exception.Message)));

????????}

?

????????/// <summary>

????????/// 更改集群

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerHashSlotMoved(object?sender, HashSlotMovedEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("HashSlotMoved:NewEndPoint" + e.NewEndPoint + ", OldEndPoint" + e.OldEndPoint);

????????}

?

????????/// <summary>

????????/// redis類庫錯誤

????????/// </summary>

????????/// <param name="sender"></param>

????????/// <param name="e"></param>

????????private?static?void?MuxerInternalError(object?sender, InternalErrorEventArgs e)

????????{

????????????//LogHelper.SafeLogMessage("InternalError:Message" + e.Exception.Message);

????????}

?

????????//場景不一樣,選擇的模式便會不一樣,大家可以按照自己系統(tǒng)架構(gòu)情況合理選擇長連接還是Lazy。

????????//建立連接后,通過調(diào)用ConnectionMultiplexer.GetDatabase 方法返回對 Redis Cache 數(shù)據(jù)庫的引用。從 GetDatabase 方法返回的對象是一個輕量級直通對象,不需要進行存儲。

?

????????/// <summary>

????????/// 使用的是Lazy,在真正需要連接時創(chuàng)建連接。

????????/// 延遲加載技術(shù)

????????/// 微軟azure中的配置 連接模板

????????/// </summary>

????????//private static Lazy<ConnectionMultiplexer> lazyConnection = new Lazy<ConnectionMultiplexer>(() =>

????????//{

????????//??? //var options = ConfigurationOptions.Parse(constr);

????????//??? options.ClientName = GetAppName(); // only known at runtime

????????//??? //options.AllowAdmin = true;

????????//??? //return ConnectionMultiplexer.Connect(options);

????????//??? ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect(Coonstr);

????????//??? muxer.ConnectionFailed += MuxerConnectionFailed;

????????//??? muxer.ConnectionRestored += MuxerConnectionRestored;

????????//??? muxer.ErrorMessage += MuxerErrorMessage;

????????//??? muxer.ConfigurationChanged += MuxerConfigurationChanged;

????????//??? muxer.HashSlotMoved += MuxerHashSlotMoved;

????????//??? muxer.InternalError += MuxerInternalError;

????????//??? return muxer;

????????//});

?

?

????????#region? 當(dāng)作消息代理中間件使用 一般使用更專業(yè)的消息隊列來處理這種業(yè)務(wù)場景

?

????????/// <summary>

????????/// 當(dāng)作消息代理中間件使用

????????/// 消息組建中,重要的概念便是生產(chǎn)者,消費者,消息中間件。

????????/// </summary>

????????/// <param name="channel"></param>

????????/// <param name="message"></param>

????????/// <returns></returns>

????????public?static?long?Publish(string?channel,?string?message)

????????{

????????????StackExchange.Redis.ISubscriber sub = Instance.GetSubscriber();

????????????//return sub.Publish("messages", "hello");

????????????return?sub.Publish(channel, message);

????????}

?

????????/// <summary>

????????/// 在消費者端得到該消息并輸出

????????/// </summary>

????????/// <param name="channelFrom"></param>

????????/// <returns></returns>

????????public?static?void?Subscribe(string?channelFrom)

????????{

????????????StackExchange.Redis.ISubscriber sub = Instance.GetSubscriber();

????????????sub.Subscribe(channelFrom, (channel, message) =>

????????????{

????????????????Console.WriteLine((string)message);

????????????});

????????}

?

????????#endregion

?

????????/// <summary>

????????/// GetServer方法會接收一個EndPoint類或者一個唯一標(biāo)識一臺服務(wù)器的鍵值對

????????/// 有時候需要為單個服務(wù)器指定特定的命令

????????/// 使用IServer可以使用所有的shell命令,比如:

????????/// DateTime lastSave = server.LastSave();

????????/// ClientInfo[] clients = server.ClientList();

????????/// 如果報錯在連接字符串后加 ,allowAdmin=true;

????????/// </summary>

????????/// <returns></returns>

????????public?static?IServer GetServer(string?host,?int?port)

????????{

????????????IServer server = Instance.GetServer(host, port);

????????????return?server;

????????}

?

????????/// <summary>

????????/// 獲取全部終結(jié)點

????????/// </summary>

????????/// <returns></returns>

????????public?static?EndPoint[] GetEndPoints()

????????{

????????????EndPoint[] endpoints = Instance.GetEndPoints();

????????????return?endpoints;

????????}

????}

}

  

 總體項目結(jié)構(gòu)是這樣的

?

?

下期我將把前端代碼列出來,這個我只是為了實現(xiàn)功能,大神勿噴

?

轉(zhuǎn)自https://www.cnblogs.com/colyn/p/11976006.html

總結(jié)

以上是生活随笔為你收集整理的仿微信 即时聊天工具 - SignalR (一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。