查看: 104|回复: 0

终于开始学 Asp.Net Core 的我竟然发现它比 WPF 要更容易学

[复制链接]

4

主题

10

帖子

18

积分

新手上路

Rank: 1

积分
18
发表于 2023-3-1 18:38:51 | 显示全部楼层 |阅读模式
** 自学笔记,欢迎指正 **
之前都是活在 Web 技术很难的刻板印象里面,所以在艰难地啃食了 WPF 很长一段时间之后陆陆续续开始接触了 Web 三大件(html、css、JavaScript)稍微有了点基础才开始接触同为 .Net Framework Core 的 http://Asp.Net Core。
结果发现其实 http://Asp.Net Core 并没有那么高冷。在一开始完全被依赖注入(DI)和控制反转(IoC)震慑了一段时间慢慢熟悉了它们,反而感觉到了它们的友善和智能。整个框架给我感觉就是一种“麻烦的事情交给我处理,你们只管编写网站就好了”的感觉。
<hr/>因为还没有学到部署(特别是云端部署)的部分,所以现在只对 Web App 解决方案之内的东西做一个总结。
Web 技术为什么说比桌面友善呢?因为归根结底它都脱离不了使用 html css JavaScript。有固定的东西,那么学起来就比较不那么眼花缭乱。
举个例子,我在网页上需要渲染固定格式的若干张卡片用来显示信息,比如商品,比如书籍,我们有好多选择:

  • 直接使用 Razor 提供的 foreach 语句结合 html
  • 使用 partial 标签助手
  • 使用 Razor Components
但是归根结底,都是在给用户请求的网页里面用花里胡哨的方法和结构生成一段段的html,万变不离其宗。Web 技术只要掌握好了(当然要做到这一点并不简单),无论是用什么架构写网站都会有一个强大的技术栈核心,特定框架下的所有特征看起来都非常简单非常符合逻辑,因为你知道它最终的输出内容总是脱离不开 Web 三大件,只不过是具体形态变了而已。
对比学习制作 Desktop App,各种框架,各种语言,各种操作系统全都是不一样的感觉。桌面应用的优势在于可以去渲染更强大的视觉效果,但是现在凭借着越来越优秀的浏览器表现,网页技术也在赶上,缩小差距。
实际上就算是 Desktop App 也越来越依附网络通讯了,越来越少的需求非要用离网单机的应用来实现不可。现在 C# 在游戏制作领域非常显眼(Unity,Mono),而 WPF 被大量运用在上位机上。
仔细想一想,PC 端大型 3D 游戏在软件分类是一种“超级饱和的桌面富客户端”不是么?网站给我服务器端渲染个 4K 120FPS《毁灭战士:永恒》看看?一根细细的网线能和PCIe口比数据传输速度?
但我能想到的也只有电子游戏了。
上位机流行 WPF 应该是符合“离线”,“单机”,“稳定”的应用场景。
所以既然需求方面越来越紧靠网络,网页技术表现也越来越舒服,为什么不直接放弃桌面本地客户端直接把整个一套东西搬上网呢?越来越多的公司也确实在这么做。
谷歌之前甚至都想用云来提供游戏的流媒体服务。也是颇有野心。个人认为是有点过于激进了。
<hr/>网页开发在作为小白的我看来一直非常高大上。导致我一直对 http://Asp.Net Core 怀着畏惧之心,不仅迟迟没有学习,学起来的时候还断断续续地,感觉整个玩意是个神秘的玄学体系。
三个字:看不懂。
其实回头看起来,其实纠结的点主要就是不知道为什么哪些依赖注入的对象的构造函数的参数这么复杂然后一次都没有被叫到。
这不就是依赖注入的最大的特征吗?在运行时,服务提供者对象会把自己内部被注入的所有对象自己匹配起来。不需要程序员给它们分配对象,程序员只要告诉他们什么样子的对象是匹配的,或者它们生命周期里面不可或缺的,它们会在服务集合里面自己找。
"Don't think about it, feel it."
理解这个规律之后整个依赖注入和控制反转体系只有亲切和便利的感觉。
看 b站的教程学过依赖注入,但是例子太过于简单了根本就体会不出依赖注入的厉害和优势。当初我想要学习依赖注入的时候看这个视频,皱着眉头心里问了一万遍“为什么不直接 new 一个对象呢?”
如果也有朋友在学习依赖注入的时候有类似的疑问,请想象一下你在一个较大规模的软件开发过程中,其中一个对象在不同的命名空间、不同的文件、被 new 了一千多次之后,现在你这些地方使用这个对象的所有方法换一个,该怎么办?Ctrl+Shift + H 吗?接口之下的具体实施怎么控制呢?什么时候用同一个对象的实例什么时候新生成一个对象实例呢?请注意,如果你觉得我去 Ctrl+Shift + H 无所谓我喜欢,那么你可以再想象一下现在你有需要 refactoring 的需求,你写了两个或者好几个不同规格的这个对象替代这几千个实例,那么你需要重复 Ctrl+Shift + H 好几次。
手动惊喜。
头疼吗?依赖注入和控制反转机制就是为了让你头不疼而诞生的。
题外话,给正在学习编程的朋友。很多编程概念不仅名词高大上玄乎而且光看纸面定义会看得一头雾水不明所以。但是真的,一定要坚持多实践新的概念和特征,而且在实践的同时要关闭大脑的思考机制。在实践积累到一定时候,习惯这些新特征的具体行为模式之后,反过来再看看这些概念就会觉得“它当然就应该是这样的,要不然呢?”之前玄幻的词汇也会变得那么自然和贴切,纸面的文档定义也会变得简单易懂。
实践这一个过程是极其重要而且无法替代的。
<hr/>路由与请求

网站制作和桌面应用的第一个最大的显著不同在于网站的路由和请求机制。很明显桌面应用是不需要进行复杂的路由和请求的,按键绑定着窗口启动事件处理,按下去开一个新窗口或者输出一个新页面就可以了。
但是路由是网页导航的日常。
其实就是在主站的网址后面可以添加路径,靠这样的方式路由终点收到请求,并且按照自己的业务逻辑输出内容(html、json、字符串等)。
静态网站就是,我连接进去主页,然后它会根据 wwwroot 文件夹下发布的路径规律,提供相应的资源。
而 http://Asp.Net Core Mvc 架构就是我需要使用 app.UseEndpoints(endpoints => { //... }) 去映射每种请求的路由路径符合什么 pattern 匹配,然后如果匹配到了,我应该使用什么控制器,控制器的什么方法,传入什么参数。
例子:
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllerRoute(
                    name: "default",
                    pattern: "{controller=Home}/{action=Index}/{id?}");
            });
{controller=Home} 指第一个斜线片段会寻找某种Controller,默认是 HomeController。
{action=Index} 指第二个斜线片段会寻找上一个片段指定的 Controller 中的某种方法,默认是 Index。
{id?} 指在第三个斜线片段会映射一个名字叫做 id 的参数投入到上一个片段指定的方法中。可以不写。
具体的路由值数据的限制语法参照:
例子,想要强制规定为 int 类型,{id:int};字母(A-Za-z)强制规定,{name:alpha}。
注意点:有朋友可能想到这里可以使用正则表达式(Regular Expression)来处理请求字符串从而进行映射,但是这样的方式可能会有 DDoS 脆弱性。恶意连接可以通过不停地引发服务器端的正则表达机制造成处理资源满载,甚至程序崩溃。使用时需要注意。比如可以通过
public static string Replace (string input,
                              string pattern,
                              System.Text.RegularExpressions.MatchEvaluator evaluator,
                              System.Text.RegularExpressions.RegexOptions options,
                              TimeSpan matchTimeout);中规定 matchTimeout 来限制资源的使用,防止长时间的匹配操作。
我们可以通过 IRouteConstraint 接口来自定义路由限制的格式。也可以通过 IOutboundParameterTransformer 接口来实现参数自动格式转换。比如把 MyQueryParameter 转换成 my-query-parameter。
未完待续
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表