來源:互聯(lián)網(wǎng) 閱讀:-
.NET框架之“小馬過河”
有許多流行的 .NET
框架,大家都覺得挺“重”,認(rèn)為很麻煩,重量級,不如其它“輕量級”框架,從而不愿意使用。面對形形色色的框架發(fā)愁,筆者也曾發(fā)愁。但我發(fā)現(xiàn)只要敢于嘗試,這些框架都是“紙老虎”。就像“小馬過河”一樣,自己嘗試一下,就會發(fā)現(xiàn)“原來河水既不像老牛說的那樣淺,也不像松鼠說的那樣深?!?/p>
項目中的代碼,都在 LINQPad6
中運行并測試通過,也可以復(fù)制到VisualStudio
中執(zhí)行。
Http
服務(wù)器很“重”有些非常簡單的 Http
服務(wù)器,我看到有些.NET
開發(fā)居然也用Node.js
、Python
等語言,一問,他們會回答說“這種簡單的東西,用.NET
,太重了”。殊不知其實用.NET
做起來,也很輕(甚至更輕):
// 代碼不需要引入任何第三方包
var http = new HttpListener;
http.Prefixes.Add("http://localhost:8080/");
http.Start;
while (true)
{
var ctx = await http.GetContext;
using var writer = new StreamWriter(ctx.Response.OutputStream);
writer.Write(DateTime.Now);
}
運行效果:
可見,包括空行,僅10行代碼即可完成一個簡單的 HTTP
服務(wù)器。
EntityFramework
很“重”EntityFramework
,簡稱EF
,現(xiàn)在有兩個版本,EFCore
和EF6
,其中EFCore
可以同時運行在.NETFramework
和.NETCore
中,但EF6
只能在.NETFramework
中運行。本文中只測試了EFCore
,但EF6
代碼也一樣簡單。
EntityFramework
是.NET
下常用的數(shù)據(jù)訪問框架,以代碼簡單、功能強(qiáng)大而著名。但不少人卻嗤之以鼻、不以為意。詢問時,回答說EntityFramework
很“重”。
這個“重”字,我理解為它可能占用內(nèi)存高,或者它可能代碼極其麻煩,配置不方便(像iBatis
/Hibernate
那樣),真的這樣嗎?
如圖,假設(shè)我有一個 UserVoiceStatus
表:
下面,我們通過 EF
將數(shù)據(jù)取出來:
// 引用NuGet包:
// Microsoft.EntityFrameworkCore.SqlServer
void Main
{
var db = new MyDB(new DbContextOptionsBuilder
.UseSqlServer(Util.GetPassword("ConnectionString"))
.Options);
db.UserVoiceStatus.Dump;
}
public class UserVoiceStatus
{
public byte Id { get; set; }
public string Name { get; set; }
}
public class MyDB : DbContext
{
public MyDB(DbContextOptions options): base(options)
{
}
public DbSet<UserVoiceStatus> UserVoiceStatus { get; set; }
}
執(zhí)行效果如圖:
注意,如果使用
LINQPad
,事情還能更簡單,只要一行代碼即可,效果完全一樣:UserVoiceStatuses
ASP.NET MVC
很“重”上文說到了如何做一個簡單的 Http
服務(wù)器,如果想復(fù)雜一點,初始化ASP.NET MVC
也很簡單,甚至只需要一個文件即可完成:
void Main
{
WebHost
.CreateDefaultBuilder
.UseStartup<UserQuery>
.UseUrls("https://localhost:55555")
.Build
.Run;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers;
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting;
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}",
defaults: new { controller = "Home", action = "Index" });
});
}
namespace Controllers
{
public class HomeController : Controller
{
public DateTime Index
{
return DateTime.Now;
}
}
}
麻雀雖小,五臟俱全,這么簡短的幾千代碼中,可以使用 Https
、包含了依賴注入,還能完整的路由功能,就構(gòu)成了ASP.NET MVC
的基本代碼。運行效果如圖:
WebSockets
很“重”WebSockets
是個流行的Http
雙向通信技術(shù),以前在Node.js
中很流行(用socket.io
)。代碼如下:
async Task Main
{
await WebHost
.CreateDefaultBuilder
.UseStartup<UserQuery>
.UseUrls("https://*:55555")
.Build
.RunAsync;
}
async Task Echo(HttpContext ctx, WebSocket webSocket, CancellationToken cancellationToken)
{
var buffer = new byte[4096];
ValueWebSocketReceiveResult result = await webSocket.ReceiveAsync(buffer.AsMemory, cancellationToken);
while (!result.EndOfMessage)
{
await webSocket.SendAsync(buffer.AsMemory(..result.Count), result.MessageType, result.EndOfMessage, cancellationToken);
result = await webSocket.ReceiveAsync(buffer.AsMemory, cancellationToken);
}
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure, "NA", cancellationToken);
}
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app)
{
app.UseWebSockets;
app.Use(async (ctx, next) =>
{
if (ctx.Request.Path == "/ws")
{
if (ctx.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await ctx.WebSockets.AcceptWebSocketAsync;
await Echo(ctx, webSocket, CancellationToken.None);
return;
}
}
await next;
});
app.Run(x => x.Response.WriteAsync("Please call /ws using WebSockets."));
}
該代碼是個 Echo
服務(wù)器,它會將客戶端發(fā)過來和內(nèi)容,按原因返回給客戶端。然后,.NET
也內(nèi)置了WebSockets
的客戶端:可以高效地訪問剛剛創(chuàng)建并運行的WebSockets
服務(wù)器。
using (var ws = new ClientWebSocket)
{
await ws.ConnectAsync(new Uri("wss://localhost:55555/ws"), CancellationToken.None);
var completeEvent = new ManualResetEventSlim;
var cts = new CancellationTokenSource;
new Task( => SendMessage(ws, cts)).Start;
var buffer = new byte[4096];
do
{
var r = await ws.ReceiveAsync(buffer, cts.Token);
$"[{Util.ElapsedTime}] Received {Encoding.UTF8.GetString(buffer, 0, r.Count)}".Dump;
} while (ws.State != WebSocketState.Closed);
}
$"[{Util.ElapsedTime}] Closed.".Dump;
async void SendMessage(WebSocket ws, CancellationTokenSource cts)
{
for (var i = 0; i <3; ++i)
{
await ws.SendAsync(
Encoding.UTF8.GetBytes($"[{Util.ElapsedTime}] Send {DateTime.Now.ToString}".Dump),
WebSocketMessageType.Text,
endOfMessage: false, default);
await Task.Delay(1000);
}
await ws.CloseAsync(WebSocketCloseStatus.Empty, , default);
cts.Cancel;
}
最后,客戶端與服務(wù)器雙向通信效果如下:
SignalR
很“重”SignalR
是ASP.NET
推出的抽象式的Http
協(xié)議雙向通信框架。SignalR
可以用相同的API
,支持像長輪詢、ServerSentEvents
和WebSocket
的技術(shù)。SignalR
默認(rèn)優(yōu)先選擇使用WebSocket
以達(dá)到最高性能,如果客戶端或服務(wù)器不支持,則會回退至其它稍慢的技術(shù)。
SignalR
客戶端還支持幾乎所有語言、所有平臺。它是如此好用,幾乎可以取代傳統(tǒng)的請求/響應(yīng),成為新的Http
開發(fā)模型。(事實上Blazor
正在嘗試這樣做)
但 SignalR
最為令人震撼的,還是它非常簡單的使用方式,而恰恰是這一點給人誤會最深。它的服務(wù)端API
,甚至比WebSocket
還要簡單清晰簡單:
async Task Main
{
await WebHost
.CreateDefaultBuilder
.UseStartup<UserQuery>
.UseUrls("https://localhost:55555")
.Build
.RunAsync;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddSignalR;
}
public void Configure(IApplicationBuilder app)
{
app.UseRouting;
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<Hubs.ChatHub>("/chat");
});
}
namespace Hubs
{
public class ChatHub : Hub
{
public async Task Broadcast(string id, string text)
{
await Clients.All.SendAsync("Broadcast", id, text);
}
}
}
前文提到, SignalR
提供了所有平臺的SignalR
客戶端,如js
、Android
等,其中當(dāng)然(顯然)也包括.NET
的。SignalR
的.NET
客戶端使用起來也非常簡單:
// 引入NuGet包:Microsoft.AspNetCore.SignalR.Client
// 代碼在LINQPad中運行
var hub = new HubConnectionBuilder
.WithUrl("https://localhost:55555/chat")
.Build;
hub.On("Broadcast", (string id, string msg) =>
{
Console.WriteLine($"{id}: {msg}");
});
new Label("姓名: ").Dump;
var idBox = new TextBox(Guid.NewGuid.ToString).Dump;
await hub.StartAsync;
while (true)
{
var text = Console.ReadLine;
if (text == "Q") break;
await hub.SendAsync("Broadcast", idBox.Text, text);
}
這是一個非常簡單的多人聊天室,運行效果如下:
面對形形色色的框架發(fā)愁,筆者也曾發(fā)愁。但現(xiàn)在不了,什么框架拿過來,馬上試試,也就幾十秒鐘的事。好用不好用,用用便知。
那么讀者,你的“小馬過河”的故事是怎樣的呢?
推薦閱讀:蘋果8p屏幕材質(zhì)