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

在今年年初, 恰逢新春佳节临近的时候. 微软给全球的C#开发者们, 着实的送上了一分惊喜. 微软正式开源Blazor ,将.NET带回到浏览器.

这个小惊喜, 迅速的在dotnet开发者中间传开了. 而就在昨天(2018年3月22日) Blazor发布了它的第一次Release. Blazor到底是个什么样的东西呢?我们是否真的可以携着C#语言进入前端的市场中? 不如现在就跟我一起体验dotnet blazor吧.

首先

获取最新版的dotnet core 并安装Blazor模板:

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

  • 对于简单的尝试来说, VS code 已经足够. 所以笔者并没有亲自安装Visual Studio.

使用命令行初始化项目:

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中创建新的测试项目:

    • 选择 File -> New Project -> Web -> ASP.NET Core Web Application

    • 确定在Target Framework里选择了 .NET Core and ASP.NET Core 2.0.

    • 选择 Blazor 模板

敌后根据地? 如何在前端渲染cshtml

当我们运行起项目之后, 就可以看到如下提示


个时候我们在浏览器里打开监听的端口 http://localhost:17477. 就可以看到我们这个项目的网页了.

这个简单的示例项目带了3个页面

 第一个页面比较简单, 但先别急,让我们打开浏览器工具. 先看看页面在加载页面过程中都加载了什么

在初次打开页面的时候, 我们看到的是这样一个Loading..的页面.  这个页面的代码是这样的.


<!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可以看到这个页面加载了两个js, 第一个是bootstrap的, 第二个叫做blazor.js. 只不过这个js有非常多的参数, 有 main, entrypoint, 和 references. 看看References里写的是不是很熟悉? 一看就是.netdll.

blazor.js 加载了mono.js, mono.js 加载了mono.wasm. 这个是个什么文件?


asm代表的就是Web Assembly, 简单地说它就是编译好的二进制文件, 可以由浏览器直接运行, 源语言可以是C/C++或者任何可以编译到Web Assembly的文件, 而这里我们加载的就是mono 编译好的Web Assembly文件, 它被加载之后, 相当于浏览器中启动了一个mono 运行环境.

随后的两个js 是笔者chrome浏览器插入的js, 在这里不要被他们干扰了. 那么mono 运行时加载完成之后. 就需要加载dotnet 的Dll了, 首先是入口库, 接着就是需要的引用库

好家伙 1.9MB. 当所有的Dll被下载完毕之后, 这个时候我们的浏览器就可以运行我们这个dotnet的网页了. 于是就回到了我们最开始看到的那个应用程序.

所以 总结一下 blazor.js 调用mono.js, mono.js加载mono.wsam, 然后根据写在script标签里的内容继续的加载dotnet的库文件. 如果浏览器不支持wsam, 就会尝试使用asm.js加载mono.asm.js

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

我们已经知道,经过前面的步骤,浏览器里已经运行了一个.Net 运行时了. 而且加载了项目必须的dll. 那么这样一个简单的程序,它的代码究竟是怎么样的呢? 

打开项目代码,映入眼帘的是一个标准的.net Project

_ViewImports.cshtml包含了项目一些其他页面中最常使用的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是程序的入口点

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");

        }

    }

}

在入口点中, 我们注册了一个浏览器渲染服务 BrowserRender,让他渲染App

App.cshmtl是这样的

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

这里的Router对应的是Microsoft.AspNetCore.Blazor.Routing.Router. 当给它一个AppAssembly时, 他就会自动的把当前的Url 和 AppAssembly的其他Pages对应起来.

所以 当我们在浏览器里输入 /Counter时,他就会加载Pages/Couter.cshtml.

Shared文件夹里分别是布局文件,导航栏, 还有一个我们自定义的控件 SurveyPrompt. 

熟悉Razor引擎的小伙伴们一定很轻车熟路了. 那么当我们打开网站时, 默认显示给我们的 就是Index, 这个时候我们会加载Pages/Index.cshtml

Index.cshtml的代码是这个样子的

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

@page 可以告诉Router, 当前页面注册到 "/"

除了显示hello world以外, 我们在这里还看到了刚刚说到的第三方控件. SurveyPrompt. 果然不简单嘛, 一个看似简单的页面, 居然还告诉了我们如何使用自定义控件.

从声明上看, 我们知道 SunveyPrompt是一个控件,并且有一个属性Title. 现在我们打开它的代码

<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的伙伴们恐怕不会对这种混写感到陌生. 这个就是Blazor的语法. Html部分很像使Razor的模板方式. 而最后整个页面都会被编译成一个类, 这个类派生自 Component. 如果你编译过项目, 你会在Debug下面的Shared目录找到一个叫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

我们发现@functions里面的内容 会作为这个类的成员变量和 成员方法, 而上面的内容则被编译到了BuildRenderTree方法中.

那么到了这里我们大概知道了这个简单的HomePage都有什么玄机了. 我们也大概知道了Blazor的语法, 也知道其实我们所有的页面最终都会是一个Componet.

那么什么是Componet呢? 在这里并不想过多的去笔墨介绍这个概念. 如果你是一个Vue或者React的开发, 你应该对这个模块化开发不陌生. 一个Componet, 就是满足一定的功能, 有自己的属性, 状态. 可以展示特定数据的元素.

就如同我们这里的SurveyPrompt, 接受一个Title属性,并且负责把他展示成这样子

 数据驱动? Blazor的刷新和绑定机制初探

现在我们知道了一个简单的页面是如何渲染出来的. 那么让我们打开Counter这个配置来看一看. 数据是如何交互的

我们第二个page张这样子

有一个button, 大声的叫我们点它. 当我们点击的时候. 上面的current count 变成了 1

 

这一切是怎么发生的呢? 以下是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++;

    }

}

 我们看到 这个页面非常简单, 我们定义了一个CurrentCount的Field, 然后在IncreaseCount方法里给它加一. 一个叫Click me的button标签里 有一个@onclick方法, 将IncreaseCount作为参数

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其实在这里就是执行了一个Component的一个方法onclick, 顾名思义,当这个Component被点击的时候就被调用. 我们的IncreaseCount被作为参数传给了它, 可见onclick会在被点击的时候执行IncreaseCount.

那么问题来了,当我们执行了IncreaseCount方法时, 页面怎么会知道要不要刷新? 是刷新整个页面还是刷新所有?

熟悉WPF的同学可能知道, 在WPF中如果我们需要让一个ViewModel可以被监听变化, 他就需要实现INotifyChanged事件. 那么同样道理, 我们的这个IncreaseCount可能也是类似的吗?

然而基于编译后的代码我们可以发现 CurrentCount作为我们Counter这个类的Field, 并没有任何机会高速Page自己变化了. 而且这个Field非常普通,也不是什么WPF中的DP, 所以到目前为止变化是怎么通知的.并没有一个合理的解释. 后面的时间里我会尝试阅读Blazor的代码搞清楚这件事情. 

第一个问题画个问号, 那么第二个问题呢? 

打开浏览器工具, 定位到button, 再次点击button观察dom的反应.

我们看到 在点击Button的时候, button上面的<p>标签闪动了, 说明它被刷新了, 而其他标签并没有. 所以局部刷新的功能是有的. 效率问题不用担心了. 

编辑Click me, 把他的内容变成 "点击我", 再次点击按钮, 我们看到还是只有p变, 而且button也没有变回原来的内容

 

 所以我们知道, 这个局部刷新不是简单的拿Dom作比较, 肯定是有Virtual Dom的机制在里面.

 

 星星之火,可燎原?

在简单的尝试了Blazor之后, 还是很兴奋的. 可以看到Blazor是一个初具规模的产品. 我们C#开发可以用Blazor在今后写前端渲染的网页了! 

我很期望这样一个产品能够持续的演进下去.

就目前版本看(0.1.0), Blazor尚不能应用到产品中. 主要还是有以下的原因

  •  打包大小太大, 1.8M的大小对于网站简直是致命的.

  •  产品还不成熟, 现在Component还只能支持简单的事件, 笔者测试的时候只有onclick,onchange. 

  •  兼容性差,使用了WebAssembly,就注定了两年前的浏览器必定不能支持.

当然我们还是不能否认, Blazor为如何让更多语言进入前端世界打开了一扇新的大门. 也许未来JavaScript将不仅仅是前端唯一可以使用的利器. 我们会看到C/C++, Python, Java写的前端渲染页面也不一定呢.

当然在后端语言打入前端世界的道路上, WebAssembly也未必是唯一的路劲, 比如Scala.js就完全使用了js重写了Scala的库函数, 类似的还有Kotlin.js. 可以看到虽然JavaScript已经非常Fancy了,但是后端程序员们进军前端的热情可谓从未停歇过啊.

祝dotnet的应用越来越广, 祝广大后端程序员们新年成就慢慢, 加薪升职.

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


.NET社区新闻,深度好文,欢迎访问公众号文章汇总 http://www.csharpkit.com


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/321863.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

dotnet watch+vs code提升asp.net core开发效率

在园子中&#xff0c;已经又前辈介绍过dotnet watch的用法&#xff0c;但是是基于asp.net core 1.0的较老版本来讲解的&#xff0c;在asp.net core 2.0的今天&#xff0c;部分用法已经不太一样&#xff0c;所以就再写一篇文章来介绍dotnet watch vs code来提升asp.net core开发…

ASP.NET Core + Docker + Jenkins + gogs + CentOS 从零开始搭建持续集成

没有采用gitlab&#xff0c;因为gitlab比较吃配置。也比较重&#xff0c;用不到那么多功能。采用go语言开发的gogs来代替。免费HTTPS证书安装Gogs (一个gitserver&#xff0c;类似于gitlab)安装DockerDocker配置加速器 一定要配置&#xff0c;用官方的源会让你体会到什么叫做绝…

使用CoreRT将.NET Core发布为Native应用程序

在上一篇文章《使用.NET Core快速开发一个较正规的命令行应用程序》中我们看到了使用自包含方式发布的.NET Core应用中包含了216个文件。我就写一个cat命令用得着这么动真格。。。这写出来的命令行还有人用吗&#xff1f;今天我们就来介绍一下MS的另一个开源项目CoreRT。用来解…

.NET Core 2.1预览版首次引入Global Tools

Global Tools是.NET Core 2.1预览版中其中一个初次出现的特性。Global Tools提供了一种方法&#xff0c;让开发人员编写的.NET Core应用可以打包成NuGet包交付。如果.NET Core运行在目标平台上&#xff0c;那么一个恰当打包的Global Tool就可以在那上面运行。JavaScript开发人员…

开源服务容错处理库Polly使用文档

在进入SOA之后&#xff0c;我们的代码从本地方法调用变成了跨机器的通信。任何一个新技术的引入都会为我们解决特定的问题&#xff0c;都会带来一些新的问题。比如网络故障、依赖服务崩溃、超时、服务器内存与CPU等其它问题。正是因为这些问题无法避免&#xff0c;所以我们在进…

大部分Intel hardware intrinsic 将在 .NET Core 2.1 中启用

编者注&#xff1a;SIMD via C# 引入了一套全新的机制&#xff0c;使得C# 以后可以像C/C 一样直接使用intrinsic functions 来直接操作Intel CPU 的大多数SIMD 指令了&#xff08;从SSE 到AVX2&#xff09;随着 .NET Core 2.1 发布的临近&#xff0c;上周CoreCLR 已经停止向mas…

运动员最佳配对问题

西安交大 软件53 蔡少斐 题号&#xff1a;6_5 题目叙述&#xff1a; 羽毛球队有男女运动员各n人。 给定2个nn矩阵P和Q。P[i][j]是男运动员i和女运动员j配对组成混合双打的男运动员竞赛优势&#xff1b;Q[i][j]是女运动员i和男运动员j配合的女运动员竞赛优势。 由于技术配合…

TensorflowSharp 简单使用与KNN识别MNIST流程

机器学习是时下非常流行的话题&#xff0c;而Tensorflow是机器学习中最有名的工具包。TensorflowSharp是Tensorflow的C#语言表述。本文会对TensorflowSharp的使用进行一个简单的介绍。本文会先介绍Tensorflow的一些基本概念&#xff0c;然后实现一些基本操作例如数字相加等运算…

刷题bingo挑战赛1

前言 为了提高做题效率&#xff0c;最近发现了个玩bingo的好网站 https://bingosync.com 然后就有了这场bingobingobingo赛。 正题 生成代码 [ {"name":"P2638"},{"name":"P4265"},{"name":"P2331"},{"n…

ASP.NET Core Web 支付功能接入 微信-扫码支付篇

这篇文章将介绍ASP.NET Core中使用 开源项目 Payment&#xff0c;实现接入微信-扫码支付及异步通知功能。开发环境&#xff1a;Win 10 x64、VS2017 15.6.4、.NET Core SDK 2.1.101、.NET Core Runtime 2.0.61.新建"ASP.NET Core Web 应用程序"项目&#xff0c;我将它…

14、java中的集合(1)

1、为什么使用集合 面向对象语言使用对象体现事物&#xff0c;存储对象可以使用数组&#xff0c;但是数组的长度是固定的&#xff0c;存储的对象类型单一&#xff0c;不适用需求的变化&#xff0c;所以提供了集合。 2、集合和数组的区别 1&#xff09;数组长度定义之后不能改…

Microsoft AI - Custom Vision in C#

概述前面一篇 Microsoft AI - Custom Vision 中&#xff0c;我们介绍了 Azure 认知服务中的自定义影像服务&#xff1a;Custom Vision&#xff0c;也介绍了如果通过这个在线服务&#xff0c;可视化的完成项目创建、数据集上传和标注、模型训练、模型评估和测试。我们也提到&…

Unity引擎及编辑器C#源代码发布

3月23日我们在GitHub上发布了Unity引擎和编辑器的C#源代码&#xff0c;仅供Unity学习参考使用。为何如此决定为了了解或改进自己的Unity项目&#xff0c;一直以来有用户对Unity .NET程序集反汇编&#xff0c;我们的服务条款明确允许这样做。但反汇编有二大缺点&#xff1a;尽管…

k8s实战为aspnetcore.webapi微服务注入配置信息

1、浅析k8s配置信息Secret以密文的形式存储数据&#xff0c;可以用来保存一些敏感信息&#xff0c;例如&#xff1a;OAuth tokens、私钥、密码、数据库连接、事件总线连接等。ConfigMap以明文的形式存储数据&#xff0c;可以用来保存一些非敏感信息&#xff0c;例如&#xff1a…

10、mysql数据表中数据的查询(2)

介绍一下mysql中查询的重中之重&#xff0c;连接查询 创建student和teacher表&#xff0c;表中数据如下&#xff1a; studentteacher 交叉连接查询 查询结果是连接的几个表中满足条件的相关联的数据的交集 sql SELECT s.id sid, s.name sname , t.id tid ,t.name tname FRO…

微软将人工智能嵌入Windows 10更新

下一轮Windows 10更新为Windows应用程序与人工智能功能的集成提供了新途径&#xff0c;将直接令数以亿计的个人电脑、平板、IoT边缘设备等Windows设备受益。新版Windows ML平台可供开发者直接通过Visual Studio将预先训练好的深度学习模型与自己的应用程序集成&#xff0c;在导…

24、mysql连接线程的show和kill

1、登陆到mysql服务器 Mysql –h ip –u 用户名 –p 密码; 2、检查当前连接的线程 show full processlist 或 show processlist 或 selelct * from information_schema.processlist; Id&#xff1a;线程标识 User&#xff1a;当前用户 Host&#xff1a;sql的来源&#xff0c;i…

ASP.NET Core MVC 2.1 顶级参数验证

本文讨论ASP.NET Core 2.1中与ASP.NET Core MVC / Web API控制器中的模型绑定相关的功能。虽说这是一个功能&#xff0c;但从我的角度来看&#xff0c;它更像是一个错误修复&#xff01;请注意&#xff0c;我使用的是 NET Core 2.1 Preview 1&#xff0c;正式版发布后&#xff…

.net core2.0下Ioc容器Autofac使用

Autofac基本使用Autofac是一款轻量级的IOC框架&#xff0c;使用率上还是挺高的&#xff0c;官方网站http://autofac.org&#xff0c;源码下载地址https://github.com/autofac/Autofac。下面以狗的列子来介绍autofac&#xff0c;nuget搜索Autofac进行安装public interface IDog{…

微软重组变两大事业部:Windows主管离职

微软CEO纳德拉通过内部邮件宣布&#xff0c;整个公司进行重大重组&#xff0c;划分为两个新的事业部(部门)&#xff0c;同时Windows业务主管Terry Myerson(特里梅尔森)将离开微软。Terry Myerson最为人诟病的就是推倒了Windows Mobile而打造全新的Windows Phone&#xff0c;结果…