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.warnarumah.net:城口县| www.soft-file.org:龙游县| www.lifeisalabyrinth.com:淮阳县| www.qdtingmei.com:德钦县| www.fjfgg.com:南雄市| www.youthsportsfinder.com:来宾市| www.meujp.com:丽水市| www.pj43730.com:屏山县| www.befms.com:额敏县| www.hg93789.com:连州市| www.chcdistribution.com:乐昌市| www.salsa-101.com:扶风县| www.raycorodriguez.com:铜山县| www.hg81456.com:虞城县| www.zhengdayy.com:曲松县| www.463507.com:遵化市| www.wzjdsb.com:西乌珠穆沁旗| www.wunderkind56dvoek.net:南部县| www.dwbkp.cn:丰顺县| www.shshangxin.com:兰溪市| www.cz833.com:九江县| www.13425690000.com:甘南县| www.dreamleadership.org:诸暨市| www.hse6.com:班戈县| www.gigsea.com:罗甸县| www.corsetcollege.com:夏邑县| www.szbxmchess.com:景宁| www.qhzxz.com:荆州市| www.gondex.com:蓬溪县| www.diendankientruc.net:绥中县| www.n3969.com:开封县| www.jiuyang579.com:利辛县| www.geyikmakinesi.com:加查县| www.awov.org:伊宁市| www.dchsci.com:建瓯市| www.fxptgs.com:正阳县| www.gaobaoit.com:蓝山县| www.jh0oxs.com:宣恩县| www.jam-bg.com:满洲里市| www.backinbody.com:宁城县| www.tmcmotor.com:奈曼旗| www.judaicaboutique.com:蛟河市| www.daggervale.org:合阳县| www.eqmadmin.com:夏津县| www.juegosdraculaura.com:连州市| www.shyanggang.com:左权县| www.xmldzyls.com:大方县| www.z5838.com:顺昌县| www.jhjxjgc.com:新和县| www.hg52456.com:利川市| www.hg41678.com:南投县| www.bjjyzy.com:寿宁县| www.bdyjxm.com:安多县| www.howsvps.com:皮山县| www.voltthemes.com:上虞市| www.mehmet-ali.net:淮滨县| www.g3g2.com:金乡县| www.shlsdp.com:苍山县| www.sznks.com:郓城县| www.cp5339.com:桂东县| www.saybelfld.com:罗山县| www.rlasurveys.org:南雄市| www.pianfang120.com:湖北省| www.qm-cz.com:大兴区| www.liujianshufa.com:崇礼县| www.mariahturkiye.net:洛川县| www.vmorepro.com:临清市| www.8a88004.com:宁夏| www.g6559.com:淮安市| www.bellinghamkiwanis.com:泽库县| www.parrotfm.com:荣昌县| www.fengxiangfa.com:平阳县| www.nanopowerindia.com:古浪县| www.yuanrongxing.com:潼关县| www.jiandingqinzi.com:阳东县| www.ircdzone.net:萨迦县| www.exoovnis.com:武山县| www.gangesfruit.com:嘉善县| www.abcpda.com:抚顺县| www.cp7781.com:上饶县| www.faisal1624.com:资溪县| www.hychq.com:新绛县| www.char-o-lotranch.com:于田县| www.xdemachinery.com:堆龙德庆县|