1. 設為首頁   文化中國網歡迎您~!

          .NET框架之“小馬過河”

          .NET框架之“小馬過河”

          有許多流行的 .NET框架,大家都覺得挺“重”,認為很麻煩,重量級,不如其它“輕量級”框架,從而不愿意使用。面對形形色色的框架發愁,筆者也曾發愁。但我發現只要敢于嘗試,這些框架都是“紙老虎”。就像“小馬過河”一樣,自己嘗試一下,就會發現“原來河水既不像老牛說的那樣淺,也不像松鼠說的那樣深。”

          項目中的代碼,都在 LINQPad6中運行并測試通過,也可以復制到VisualStudio中執行。

          做簡單的 Http服務器很“重”

          有些非常簡單的 Http服務器,我看到有些.NET開發居然也用Node.jsPython等語言,一問,他們會回答說“這種簡單的東西,用.NET,太重了”。殊不知其實用.NET做起來,也很輕(甚至更輕):

          1. // 代碼不需要引入任何第三方包

          2. var http = new HttpListener;

          3. http.Prefixes.Add("http://localhost:8080/");

          4. http.Start;


          5. while (true)

          6. {

          7. var ctx = await http.GetContext;

          8. using var writer = new StreamWriter(ctx.Response.OutputStream);

          9. writer.Write(DateTime.Now);

          10. }

          運行效果:

          可見,包括空行,僅10行代碼即可完成一個簡單的 HTTP服務器。

          使用 EntityFramework很“重”

          EntityFramework,簡稱EF,現在有兩個版本,EFCoreEF6,其中EFCore可以同時運行在.NETFramework.NETCore中,但EF6只能在.NETFramework中運行。本文中只測試了EFCore,但EF6代碼也一樣簡單。

          EntityFramework.NET下常用的數據訪問框架,以代碼簡單、功能強大而著名。但不少人卻嗤之以鼻、不以為意。詢問時,回答說EntityFramework很“重”。

          這個“重”字,我理解為它可能占用內存高,或者它可能代碼極其麻煩,配置不方便(像iBatis/Hibernate那樣),真的這樣嗎?

          如圖,假設我有一個 UserVoiceStatus表:

          下面,我們通過 EF將數據取出來:

          1. // 引用NuGet包:

          2. // Microsoft.EntityFrameworkCore.SqlServer

          3. void Main

          4. {

          5. var db = new MyDB(new DbContextOptionsBuilder

          6. .UseSqlServer(Util.GetPassword("ConnectionString"))

          7. .Options);

          8. db.UserVoiceStatus.Dump;

          9. }


          10. public class UserVoiceStatus

          11. {

          12. public byte Id { get; set; }

          13. public string Name { get; set; }

          14. }


          15. public class MyDB : DbContext

          16. {

          17. public MyDB(DbContextOptions options): base(options)

          18. {

          19. }


          20. public DbSet<UserVoiceStatus> UserVoiceStatus { get; set; }

          21. }

          執行效果如圖:

          注意,如果使用 LINQPad,事情還能更簡單,只要一行代碼即可,效果完全一樣:UserVoiceStatuses

          使用 ASP.NET MVC很“重”

          上文說到了如何做一個簡單的 Http服務器,如果想復雜一點,初始化ASP.NET MVC也很簡單,甚至只需要一個文件即可完成:

          1. void Main

          2. {

          3. WebHost

          4. .CreateDefaultBuilder

          5. .UseStartup<UserQuery>

          6. .UseUrls("https://localhost:55555")

          7. .Build

          8. .Run;

          9. }


          10. public void ConfigureServices(IServiceCollection services)

          11. {

          12. services.AddControllers;

          13. }


          14. public void Configure(IApplicationBuilder app)

          15. {

          16. app.UseRouting;

          17. app.UseEndpoints(endpoints =>

          18. {

          19. endpoints.MapControllerRoute(

          20. name: "default",

          21. pattern: "{controller}/{action}/{id?}",

          22. defaults: new { controller = "Home", action = "Index" });

          23. });

          24. }


          25. namespace Controllers

          26. {

          27. public class HomeController : Controller

          28. {

          29. public DateTime Index

          30. {

          31. return DateTime.Now;

          32. }

          33. }

          34. }

          麻雀雖小,五臟俱全,這么簡短的幾千代碼中,可以使用 Https、包含了依賴注入,還能完整的路由功能,就構成了ASP.NET MVC的基本代碼。運行效果如圖:

          使用 WebSockets很“重”

          WebSockets是個流行的Http雙向通信技術,以前在Node.js中很流行(用socket.io)。代碼如下:

          1. async Task Main

          2. {

          3. await WebHost

          4. .CreateDefaultBuilder

          5. .UseStartup<UserQuery>

          6. .UseUrls("https://*:55555")

          7. .Build

          8. .RunAsync;

          9. }


          10. async Task Echo(HttpContext ctx, WebSocket webSocket, CancellationToken cancellationToken)

          11. {

          12. var buffer = new byte[4096];

          13. ValueWebSocketReceiveResult result = await webSocket.ReceiveAsync(buffer.AsMemory, cancellationToken);

          14. while (!result.EndOfMessage)

          15. {

          16. await webSocket.SendAsync(buffer.AsMemory(..result.Count), result.MessageType, result.EndOfMessage, cancellationToken);

          17. result = await webSocket.ReceiveAsync(buffer.AsMemory, cancellationToken);

          18. }

          19. await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "NA", cancellationToken);

          20. }


          21. public void ConfigureServices(IServiceCollection services)

          22. {

          23. }


          24. public void Configure(IApplicationBuilder app)

          25. {

          26. app.UseWebSockets;

          27. app.Use(async (ctx, next) =>

          28. {

          29. if (ctx.Request.Path == "/ws")

          30. {

          31. if (ctx.WebSockets.IsWebSocketRequest)

          32. {

          33. WebSocket webSocket = await ctx.WebSockets.AcceptWebSocketAsync;

          34. await Echo(ctx, webSocket, CancellationToken.None);

          35. return;

          36. }

          37. }

          38. await next;

          39. });

          40. app.Run(x => x.Response.WriteAsync("Please call /ws using WebSockets."));

          41. }

          該代碼是個 Echo服務器,它會將客戶端發過來和內容,按原因返回給客戶端。然后,.NET也內置了WebSockets的客戶端:可以高效地訪問剛剛創建并運行的WebSockets服務器。

          1. using (var ws = new ClientWebSocket)

          2. {

          3. await ws.ConnectAsync(new Uri("wss://localhost:55555/ws"), CancellationToken.None);

          4. var completeEvent = new ManualResetEventSlim;

          5. var cts = new CancellationTokenSource;

          6. new Task( => SendMessage(ws, cts)).Start;


          7. var buffer = new byte[4096];

          8. do

          9. {

          10. var r = await ws.ReceiveAsync(buffer, cts.Token);

          11. $"[{Util.ElapsedTime}] Received {Encoding.UTF8.GetString(buffer, 0, r.Count)}".Dump;

          12. } while (ws.State != WebSocketState.Closed);

          13. }

          14. $"[{Util.ElapsedTime}] Closed.".Dump;


          15. async void SendMessage(WebSocket ws, CancellationTokenSource cts)

          16. {

          17. for (var i = 0; i <3; ++i)

          18. {

          19. await ws.SendAsync(

          20. Encoding.UTF8.GetBytes($"[{Util.ElapsedTime}] Send {DateTime.Now.ToString}".Dump),

          21. WebSocketMessageType.Text,

          22. endOfMessage: false, default);

          23. await Task.Delay(1000);

          24. }

          25. await ws.CloseAsync(WebSocketCloseStatus.Empty, , default);

          26. cts.Cancel;

          27. }

          最后,客戶端與服務器雙向通信效果如下:

          使用 SignalR很“重”

          SignalRASP.NET推出的抽象式的Http協議雙向通信框架。SignalR可以用相同的API,支持像長輪詢、ServerSentEventsWebSocket的技術。SignalR默認優先選擇使用WebSocket以達到最高性能,如果客戶端或服務器不支持,則會回退至其它稍慢的技術。

          SignalR客戶端還支持幾乎所有語言、所有平臺。它是如此好用,幾乎可以取代傳統的請求/響應,成為新的Http開發模型。(事實上Blazor正在嘗試這樣做)

          SignalR最為令人震撼的,還是它非常簡單的使用方式,而恰恰是這一點給人誤會最深。它的服務端API,甚至比WebSocket還要簡單清晰簡單:

          1. async Task Main

          2. {

          3. await WebHost

          4. .CreateDefaultBuilder

          5. .UseStartup<UserQuery>

          6. .UseUrls("https://localhost:55555")

          7. .Build

          8. .RunAsync;

          9. }


          10. public void ConfigureServices(IServiceCollection services)

          11. {

          12. services.AddSignalR;

          13. }


          14. public void Configure(IApplicationBuilder app)

          15. {

          16. app.UseRouting;

          17. app.UseEndpoints(endpoints =>

          18. {

          19. endpoints.MapHub<Hubs.ChatHub>("/chat");

          20. });

          21. }


          22. namespace Hubs

          23. {

          24. public class ChatHub : Hub

          25. {

          26. public async Task Broadcast(string id, string text)

          27. {

          28. await Clients.All.SendAsync("Broadcast", id, text);

          29. }

          30. }

          31. }

          前文提到, SignalR提供了所有平臺的SignalR客戶端,如jsAndroid等,其中當然(顯然)也包括.NET的。SignalR.NET客戶端使用起來也非常簡單:

          1. // 引入NuGet包:Microsoft.AspNetCore.SignalR.Client

          2. // 代碼在LINQPad中運行

          3. var hub = new HubConnectionBuilder

          4. .WithUrl("https://localhost:55555/chat")

          5. .Build;


          6. hub.On("Broadcast", (string id, string msg) =>

          7. {

          8. Console.WriteLine($"{id}: {msg}");

          9. });


          10. new Label("姓名: ").Dump;

          11. var idBox = new TextBox(Guid.NewGuid.ToString).Dump;

          12. await hub.StartAsync;

          13. while (true)

          14. {

          15. var text = Console.ReadLine;

          16. if (text == "Q") break;

          17. await hub.SendAsync("Broadcast", idBox.Text, text);

          18. }

          這是一個非常簡單的多人聊天室,運行效果如下:

          總結

          面對形形色色的框架發愁,筆者也曾發愁。但現在不了,什么框架拿過來,馬上試試,也就幾十秒鐘的事。好用不好用,用用便知。

          那么讀者,你的“小馬過河”的故事是怎樣的呢?

          推薦閱讀:手機要降價
          好运来 www.hg01678.com:无极县| www.baiyunplaza.com:蒙山县| www.mop-mrp.com:卫辉市| www.eoilc.com:九龙坡区| www.cp6220.com:宝兴县| www.wyadorkable.com:炎陵县| www.reitzhausproductions.com:德昌县| www.bintangnusantara.com:奎屯市| www.qshinny.com:祁阳县| www.aiweizhi.com:介休市| www.hisfountain.net:大同县| www.cafe-hofmann.com:西林县| www.lslcw.com:元谋县| www.waizit.com:台东县| www.01qiuxiady.com:克东县| www.lishanan.com:高青县| www.m2676.com:岚皋县| www.abdulkafi.com:托克逊县| www.fengxiangfa.com:高雄市| www.nederlandsefilms.com:永胜县| www.wangsedu.com:凤阳县| www.snmp-thermometer.com:永年县| www.gear168.com:绍兴市| www.flying-nerd.com:赤水市| www.yctcg.cn:江阴市| www.61e7.com:冀州市| www.godfoodwine.com:南安市| www.4fsy.com:化德县| www.21wangmi.com:轮台县| www.whagy.com:虹口区| www.jshongfu56.com:剑川县| www.myrtlebeachrealestatetips.com:临沧市| www.eccacaceres.org:霸州市| www.hg91789.com:濮阳县| www.poeticasvisuais.com:乐安县| www.bashmaistora-bg.com:海晏县| www.tusbolsaspublicitarias.com:昌邑市| www.jlkyp.com:姚安县| www.wedding-invites.net:大荔县| www.healthyrootcanal.org:辽宁省| www.hu31.com:娄烦县| www.belle1.com:门源| www.488cl.com:剑川县| www.cngsc.com:雅江县| www.spike123.com:莱州市| www.simonsapartments.com:河源市| www.waizit.com:神农架林区| www.sujokcenter.com:渝北区| www.blackindianmusic.com:邹城市| www.yuanfangauction.com:阿鲁科尔沁旗| www.escortseoservices.com:霍州市| www.classifiedscolumn.com:霍城县| www.smashingoffernow.com:桂平市| www.guggamugga.com:霍州市| www.moanabbqonline.com:广南县| www.tjgcwy.com:西藏| www.arfengwork.com:花莲市| www.georgepappasltd.com:寿阳县| www.guitartrick.net:徐闻县| www.tanglay.net:嵩明县| www.anjiescl.com:板桥市| www.reindeerrowe.com:长春市| www.no-flash.com:静乐县| www.ystsclq.com:山阴县| www.23682368.com:介休市| www.breakfastbrampton.com:保德县| www.esfhera.com:黄大仙区| www.janainaewilliam.com:新晃| www.daxingxiyiji.com:阿克陶县| www.802248.com:岑巩县| www.spiritridersmc.org:秀山| www.yumaii.com:定远县| www.zhouyuzheng.com:特克斯县| www.mt779.com:庆云县| www.christaiceforest.com:鄂伦春自治旗| www.xmkainos.com:峨眉山市| www.ylzttgbus.com:罗山县| www.2dfloorplan.com:柳河县| www.018448.com:肥西县| www.raid88.com:开封县| www.xueyugifts.com:新泰市| www.adipexdietpillblog.com:平乡县| www.postnuk.com:剑川县| www.pstee.com:嵊州市|