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

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > C# >内容正文

C#

来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor

發(fā)布時(shí)間:2023/12/4 C# 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在今年年初, 恰逢新春佳節(jié)臨近的時(shí)候. 微軟給全球的C#開發(fā)者們, 著實(shí)的送上了一分驚喜. 微軟正式開源Blazor ,將.NET帶回到瀏覽器.

這個(gè)小驚喜, 迅速的在dotnet開發(fā)者中間傳開了. 而就在昨天(2018年3月22日) Blazor發(fā)布了它的第一次Release. Blazor到底是個(gè)什么樣的東西呢?我們是否真的可以攜著C#語言進(jìn)入前端的市場中? 不如現(xiàn)在就跟我一起體驗(yàn)dotnet blazor吧.

首先

獲取最新版的dotnet core 并安裝Blazor模板:

  • 安裝 最新的.Net Core(版本需要高于2.1.101)

  • 對于簡單的嘗試來說, VS code 已經(jīng)足夠. 所以筆者并沒有親自安裝Visual Studio.

使用命令行初始化項(xiàng)目:

dotnet new -i Microsoft.AspNetCore.Blazor.Templatesdotnet new blazor -o BlazorApp1cd BlazorApp1dotnet run

?

  • 如果你需要使用Visual Studio,

    • 安裝最新的Visual Studio 2017.

    • 安裝 ASP.NET Core Blazor Language Services extension

    • 在Visual Studio中創(chuàng)建新的測試項(xiàng)目:

    • 選擇 File -> New Project -> Web -> ASP.NET Core Web Application

    • 確定在Target Framework里選擇了 .NET Core and ASP.NET Core 2.0.

    • 選擇 Blazor 模板

敵后根據(jù)地? 如何在前端渲染cshtml

當(dāng)我們運(yùn)行起項(xiàng)目之后, 就可以看到如下提示


個(gè)時(shí)候我們在瀏覽器里打開監(jiān)聽的端口 http://localhost:17477. 就可以看到我們這個(gè)項(xiàng)目的網(wǎng)頁了.

這個(gè)簡單的示例項(xiàng)目帶了3個(gè)頁面

?第一個(gè)頁面比較簡單, 但先別急,讓我們打開瀏覽器工具. 先看看頁面在加載頁面過程中都加載了什么

在初次打開頁面的時(shí)候, 我們看到的是這樣一個(gè)Loading..的頁面.? 這個(gè)頁面的代碼是這樣的.


<!DOCTYPE html><html><head><meta charset="utf-8" /><title>BlazorDemo</title><base href="/" /><link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" /><link href="css/site.css" rel="stylesheet" /></head><body><app>Loading...</app><script src="css/bootstrap/bootstrap-native.min.js"></script><script src="_framework/blazor.js" main="BlazorDemo.dll" entrypoint="BlazorDemo.Program::Main" references="Microsoft.AspNetCore.Blazor.Browser.dll,Microsoft.AspNetCore.Blazor.dll,Microsoft.Extensions.DependencyInjection.Abstractions.dll,Microsoft.Extensions.DependencyInjection.dll,mscorlib.dll,netstandard.dll,System.Core.dll,System.Diagnostics.StackTrace.dll,System.dll,System.Globalization.Extensions.dll,System.Net.Http.dll,System.Runtime.Serialization.Primitives.dll,System.Security.Cryptography.Algorithms.dll" linker-enabled="true"></script></body></h可以看到這個(gè)頁面加載了兩個(gè)js, 第一個(gè)是bootstrap的, 第二個(gè)叫做blazor.js. 只不過這個(gè)js有非常多的參數(shù), 有 main, entrypoint, 和 references. 看看References里寫的是不是很熟悉? 一看就是.netdll.

blazor.js 加載了mono.js, mono.js 加載了mono.wasm. 這個(gè)是個(gè)什么文件?


asm代表的就是Web Assembly, 簡單地說它就是編譯好的二進(jìn)制文件, 可以由瀏覽器直接運(yùn)行, 源語言可以是C/C++或者任何可以編譯到Web Assembly的文件, 而這里我們加載的就是mono 編譯好的Web Assembly文件, 它被加載之后, 相當(dāng)于瀏覽器中啟動(dòng)了一個(gè)mono 運(yùn)行環(huán)境.

隨后的兩個(gè)js 是筆者chrome瀏覽器插入的js, 在這里不要被他們干擾了. 那么mono 運(yùn)行時(shí)加載完成之后. 就需要加載dotnet 的Dll了, 首先是入口庫, 接著就是需要的引用庫

好家伙 1.9MB. 當(dāng)所有的Dll被下載完畢之后, 這個(gè)時(shí)候我們的瀏覽器就可以運(yùn)行我們這個(gè)dotnet的網(wǎng)頁了. 于是就回到了我們最開始看到的那個(gè)應(yīng)用程序.

所以 總結(jié)一下 blazor.js 調(diào)用mono.js, mono.js加載mono.wsam, 然后根據(jù)寫在script標(biāo)簽里的內(nèi)容繼續(xù)的加載dotnet的庫文件. 如果瀏覽器不支持wsam, 就會(huì)嘗試使用asm.js加載mono.asm.js

柳暗花明又一村,Blazor的模板究竟是怎樣的.

我們已經(jīng)知道,經(jīng)過前面的步驟,瀏覽器里已經(jīng)運(yùn)行了一個(gè).Net 運(yùn)行時(shí)了. 而且加載了項(xiàng)目必須的dll. 那么這樣一個(gè)簡單的程序,它的代碼究竟是怎么樣的呢??

打開項(xiàng)目代碼,映入眼簾的是一個(gè)標(biāo)準(zhǔn)的.net Project

_ViewImports.cshtml包含了項(xiàng)目一些其他頁面中最常使用的namespace

5


7

@using?System.Net.Http

@using?Microsoft.AspNetCore.Blazor

@using?Microsoft.AspNetCore.Blazor.Components

@using?Microsoft.AspNetCore.Blazor.Layouts

@using?Microsoft.AspNetCore.Blazor.Routing

@using?BlazorDemo

@using?BlazorDemo.Shared

 

Program.cs是程序的入口點(diǎn)

using Microsoft.AspNetCore.Blazor.Browser.Rendering;

using Microsoft.AspNetCore.Blazor.Browser.Services;

using System;


namespace BlazorDemo

{

? ? class Program

? ? {

? ? ? ? static void Main(string[] args)

? ? ? ? {

? ? ? ? ? ? var serviceProvider = new BrowserServiceProvider(configure =>

? ? ? ? ? ? {

? ? ? ? ? ? ? ? // Add any custom services here

? ? ? ? ? ? });


? ? ? ? ? ? new BrowserRenderer(serviceProvider).AddComponent<App>("app");

? ? ? ? }

? ? }

}

在入口點(diǎn)中, 我們注冊了一個(gè)瀏覽器渲染服務(wù) BrowserRender,讓他渲染App

App.cshmtl是這樣的

<Router AppAssembly=typeof(Program).Assembly />

這里的Router對應(yīng)的是Microsoft.AspNetCore.Blazor.Routing.Router. 當(dāng)給它一個(gè)AppAssembly時(shí), 他就會(huì)自動(dòng)的把當(dāng)前的Url 和 AppAssembly的其他Pages對應(yīng)起來.

所以 當(dāng)我們在瀏覽器里輸入 /Counter時(shí),他就會(huì)加載Pages/Couter.cshtml.

Shared文件夾里分別是布局文件,導(dǎo)航欄, 還有一個(gè)我們自定義的控件 SurveyPrompt.?

熟悉Razor引擎的小伙伴們一定很輕車熟路了. 那么當(dāng)我們打開網(wǎng)站時(shí), 默認(rèn)顯示給我們的 就是Index, 這個(gè)時(shí)候我們會(huì)加載Pages/Index.cshtml

Index.cshtml的代碼是這個(gè)樣子的

@page "/"<h1>Hello, world!</h1>Welcome to your new app. <SurveyPrompt Title="How is Blazor working for you?" />

@page 可以告訴Router, 當(dāng)前頁面注冊到 "/"

除了顯示hello world以外, 我們在這里還看到了剛剛說到的第三方控件. SurveyPrompt. 果然不簡單嘛, 一個(gè)看似簡單的頁面, 居然還告訴了我們?nèi)绾问褂米远x控件.

從聲明上看, 我們知道 SunveyPrompt是一個(gè)控件,并且有一個(gè)屬性Title. 現(xiàn)在我們打開它的代碼

<div class="alert alert-survey" role="alert">

? ? <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>

? ? <strong>@Title</strong>


? ? Please take our

? ? <a target="_blank" class="alert-link" href="https://go.microsoft.com/fwlink/?linkid=870381">

? ? ? ? brief survey

? ? </a>

? ? and tell us what you think.

</div>

@functions

{

? ? // This is to demonstrate how a parent component can supply parameters

? ? public string Title { get; set; }

}

我們可以看到代碼分為兩部分, @functions上面是類似html的東西, 下面是類似C#的東西. 熟悉React或者Vue的伙伴們恐怕不會(huì)對這種混寫感到陌生. 這個(gè)就是Blazor的語法. Html部分很像使Razor的模板方式. 而最后整個(gè)頁面都會(huì)被編譯成一個(gè)類, 這個(gè)類派生自 Component. 如果你編譯過項(xiàng)目, 你會(huì)在Debug下面的Shared目錄找到一個(gè)叫SurveyPrompt.g.cs的東西

#pragma checksum "/Users/pzhi/SCM/gitHub/zhipu123/BlazorDemo/Shared/SurveyPrompt.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "a2a2ea88635b799343bc6d9647bbb818c8a20c9d"

// <auto-generated/>

#pragma warning disable 1591

namespace BlazorDemo.Shared

{

? ? #line hidden

? ? using System;

? ? using System.Collections.Generic;

? ? using System.Linq;

? ? using System.Threading.Tasks;

? ? using System.Net.Http;

? ? using Microsoft.AspNetCore.Blazor;

? ? using Microsoft.AspNetCore.Blazor.Components;

? ? using Microsoft.AspNetCore.Blazor.Layouts;

? ? using Microsoft.AspNetCore.Blazor.Routing;

? ? using BlazorDemo;

? ? using BlazorDemo.Shared;

? ? public class SurveyPrompt : Microsoft.AspNetCore.Blazor.Components.BlazorComponent

? ? {

? ? ? ? #pragma warning disable 1998

? ? ? ? protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)

? ? ? ? {

? ? ? ? ? ? base.BuildRenderTree(builder);

? ? ? ? ? ? builder.OpenElement(0, "div");

? ? ? ? ? ? builder.AddAttribute(1, "class", "alert alert-survey");

? ? ? ? ? ? builder.AddAttribute(2, "role", "alert");

? ? ? ? ? ? builder.AddContent(3, "\n? ? ");

? ? ? ? ? ? builder.OpenElement(4, "span");

? ? ? ? ? ? builder.AddAttribute(5, "class", "glyphicon glyphicon-ok-circle");

? ? ? ? ? ? builder.AddAttribute(6, "aria-hidden", "true");

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(7, "\n? ? ");

? ? ? ? ? ? builder.OpenElement(8, "strong");

? ? ? ? ? ? builder.AddContent(9, Title);

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(10, "\n\n? ? Please take our\n? ? ");

? ? ? ? ? ? builder.OpenElement(11, "a");

? ? ? ? ? ? builder.AddAttribute(12, "target", "_blank");

? ? ? ? ? ? builder.AddAttribute(13, "class", "alert-link");

? ? ? ? ? ? builder.AddAttribute(14, "href", "https://go.microsoft.com/fwlink/?linkid=870381");

? ? ? ? ? ? builder.AddContent(15, "\n? ? ? ? brief survey\n? ? ");

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(16, "\n? ? and tell us what you think.\n");

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(17, "\n\n");

? ? ? ? }

? ? ? ? #pragma warning restore 1998

? ? ? ??

? ? // This is to demonstrate how a parent component can supply parameters

? ? public string Title { get; set; }

? ? }

}

#pragma warning restore 1591

我們發(fā)現(xiàn)@functions里面的內(nèi)容 會(huì)作為這個(gè)類的成員變量和 成員方法, 而上面的內(nèi)容則被編譯到了BuildRenderTree方法中.

那么到了這里我們大概知道了這個(gè)簡單的HomePage都有什么玄機(jī)了. 我們也大概知道了Blazor的語法, 也知道其實(shí)我們所有的頁面最終都會(huì)是一個(gè)Componet.

那么什么是Componet呢? 在這里并不想過多的去筆墨介紹這個(gè)概念. 如果你是一個(gè)Vue或者React的開發(fā), 你應(yīng)該對這個(gè)模塊化開發(fā)不陌生. 一個(gè)Componet, 就是滿足一定的功能, 有自己的屬性, 狀態(tài). 可以展示特定數(shù)據(jù)的元素.

就如同我們這里的SurveyPrompt, 接受一個(gè)Title屬性,并且負(fù)責(zé)把他展示成這樣子

?數(shù)據(jù)驅(qū)動(dòng)? Blazor的刷新和綁定機(jī)制初探

現(xiàn)在我們知道了一個(gè)簡單的頁面是如何渲染出來的. 那么讓我們打開Counter這個(gè)配置來看一看. 數(shù)據(jù)是如何交互的

我們第二個(gè)page張這樣子

有一個(gè)button, 大聲的叫我們點(diǎn)它. 當(dāng)我們點(diǎn)擊的時(shí)候. 上面的current count 變成了 1

?

這一切是怎么發(fā)生的呢? 以下是Counter.cshtml的代碼

@page "/counter"

<h1>Counter</h1>


<p>Current count: @currentCount</p>


<button @onclick(IncrementCount)>Click me</button>


@functions {

? ? int currentCount = 0;


? ? void IncrementCount()

? ? {

? ? ? ? currentCount++;

? ? }

}

?我們看到 這個(gè)頁面非常簡單, 我們定義了一個(gè)CurrentCount的Field, 然后在IncreaseCount方法里給它加一. 一個(gè)叫Click me的button標(biāo)簽里 有一個(gè)@onclick方法, 將IncreaseCount作為參數(shù)

Counter.cshtml編譯后的代碼張這樣

#pragma checksum "/Users/pzhi/SCM/gitHub/zhipu123/BlazorDemo/Pages/Counter.cshtml" "{ff1816ec-aa5e-4d10-87f7-6f4963833460}" "05ad2dd449cbc9f09f8b759e1f06e7eb5e9583b4"

// <auto-generated/>

#pragma warning disable 1591

namespace BlazorDemo.Pages

{

? ? #line hidden

? ? using System;

? ? using System.Collections.Generic;

? ? using System.Linq;

? ? using System.Threading.Tasks;

? ? using System.Net.Http;

? ? using Microsoft.AspNetCore.Blazor;

? ? using Microsoft.AspNetCore.Blazor.Components;

? ? using Microsoft.AspNetCore.Blazor.Layouts;

? ? using Microsoft.AspNetCore.Blazor.Routing;

? ? using BlazorDemo;

? ? using BlazorDemo.Shared;

? ? [Microsoft.AspNetCore.Blazor.Layouts.LayoutAttribute(typeof(MainLayout))]

? ? [Microsoft.AspNetCore.Blazor.Components.RouteAttribute("/counter")]

? ? public class Counter : Microsoft.AspNetCore.Blazor.Components.BlazorComponent

? ? {

? ? ? ? #pragma warning disable 1998

? ? ? ? protected override void BuildRenderTree(Microsoft.AspNetCore.Blazor.RenderTree.RenderTreeBuilder builder)

? ? ? ? {

? ? ? ? ? ? base.BuildRenderTree(builder);

? ? ? ? ? ? builder.OpenElement(0, "h1");

? ? ? ? ? ? builder.AddContent(1, "Counter");

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(2, "\n\n");

? ? ? ? ? ? builder.OpenElement(3, "p");

? ? ? ? ? ? builder.AddContent(4, "Current count: ");

? ? ? ? ? ? builder.AddContent(5, currentCount);

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(6, "\n\n");

? ? ? ? ? ? builder.OpenElement(7, "button");

? ? ? ? ? ? builder.AddAttribute(8, onclick(IncrementCount));

? ? ? ? ? ? builder.AddContent(9, "Click me");

? ? ? ? ? ? builder.CloseElement();

? ? ? ? ? ? builder.AddContent(10, "\n\n");

? ? ? ? }

? ? ? ? #pragma warning restore 1998

? ? ? ??

? ? int currentCount = 0;


? ? void IncrementCount()

? ? {

? ? ? ? currentCount++;

? ? }

? ? }

}

#pragma warning restore 1591

我們看到 @onclick其實(shí)在這里就是執(zhí)行了一個(gè)Component的一個(gè)方法onclick, 顧名思義,當(dāng)這個(gè)Component被點(diǎn)擊的時(shí)候就被調(diào)用. 我們的IncreaseCount被作為參數(shù)傳給了它, 可見onclick會(huì)在被點(diǎn)擊的時(shí)候執(zhí)行IncreaseCount.

那么問題來了,當(dāng)我們執(zhí)行了IncreaseCount方法時(shí), 頁面怎么會(huì)知道要不要刷新? 是刷新整個(gè)頁面還是刷新所有?

熟悉WPF的同學(xué)可能知道, 在WPF中如果我們需要讓一個(gè)ViewModel可以被監(jiān)聽變化, 他就需要實(shí)現(xiàn)INotifyChanged事件. 那么同樣道理, 我們的這個(gè)IncreaseCount可能也是類似的嗎?

然而基于編譯后的代碼我們可以發(fā)現(xiàn) CurrentCount作為我們Counter這個(gè)類的Field, 并沒有任何機(jī)會(huì)高速Page自己變化了. 而且這個(gè)Field非常普通,也不是什么WPF中的DP, 所以到目前為止變化是怎么通知的.并沒有一個(gè)合理的解釋. 后面的時(shí)間里我會(huì)嘗試閱讀Blazor的代碼搞清楚這件事情.?

第一個(gè)問題畫個(gè)問號(hào), 那么第二個(gè)問題呢??

打開瀏覽器工具, 定位到button, 再次點(diǎn)擊button觀察dom的反應(yīng).

我們看到 在點(diǎn)擊Button的時(shí)候, button上面的<p>標(biāo)簽閃動(dòng)了, 說明它被刷新了, 而其他標(biāo)簽并沒有. 所以局部刷新的功能是有的. 效率問題不用擔(dān)心了.?

編輯Click me, 把他的內(nèi)容變成 "點(diǎn)擊我", 再次點(diǎn)擊按鈕, 我們看到還是只有p變, 而且button也沒有變回原來的內(nèi)容

?

?所以我們知道, 這個(gè)局部刷新不是簡單的拿Dom作比較, 肯定是有Virtual Dom的機(jī)制在里面.

?

?星星之火,可燎原?

在簡單的嘗試了Blazor之后, 還是很興奮的. 可以看到Blazor是一個(gè)初具規(guī)模的產(chǎn)品. 我們C#開發(fā)可以用Blazor在今后寫前端渲染的網(wǎng)頁了!?

我很期望這樣一個(gè)產(chǎn)品能夠持續(xù)的演進(jìn)下去.

就目前版本看(0.1.0), Blazor尚不能應(yīng)用到產(chǎn)品中. 主要還是有以下的原因

  • ?打包大小太大, 1.8M的大小對于網(wǎng)站簡直是致命的.

  • ?產(chǎn)品還不成熟, 現(xiàn)在Component還只能支持簡單的事件, 筆者測試的時(shí)候只有onclick,onchange.?

  • ?兼容性差,使用了WebAssembly,就注定了兩年前的瀏覽器必定不能支持.

當(dāng)然我們還是不能否認(rèn), Blazor為如何讓更多語言進(jìn)入前端世界打開了一扇新的大門. 也許未來JavaScript將不僅僅是前端唯一可以使用的利器. 我們會(huì)看到C/C++, Python, Java寫的前端渲染頁面也不一定呢.

當(dāng)然在后端語言打入前端世界的道路上, WebAssembly也未必是唯一的路勁, 比如Scala.js就完全使用了js重寫了Scala的庫函數(shù), 類似的還有Kotlin.js. 可以看到雖然JavaScript已經(jīng)非常Fancy了,但是后端程序員們進(jìn)軍前端的熱情可謂從未停歇過啊.

祝dotnet的應(yīng)用越來越廣, 祝廣大后端程序員們新年成就慢慢, 加薪升職.

原文:?https://www.cnblogs.com/Gerryz/p/get-start-with-dotnet-blazor.html?


.NET社區(qū)新聞,深度好文,歡迎訪問公眾號(hào)文章匯總 http://www.csharpkit.com


總結(jié)

以上是生活随笔為你收集整理的来自后端的突袭? --开包即食的教程带你浅尝最新开源的C# Web引擎 Blazor的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

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