热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

unitymvc框架背包系统json_【复杂系统迁移.NETCore平台系列】之界面层

源宝导读:微软跨平台技术框架—.NETCore已经日趋成熟,已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NETFramework

a27a7e01-6e1e-eb11-8da9-e4434bdf6706.png

a77a7e01-6e1e-eb11-8da9-e4434bdf6706.png

源宝导读:微软跨平台技术框架—.NET Core已经日趋成熟,已经具备了支撑大型系统稳定运行的条件。本文将介绍明源云ERP平台从.NET Framework向.NET Core迁移过程中的实践经验。

一、背景

    随着ERP的产品线越来越多,业务关联也日益复杂,应用间依赖关系也变得错综复杂,单体架构的弱点日趋明显。19年初,由于平台底层支持了分应用部署模式,将ERP从应用子系统层面进行了切割分离,迈出了从单体架构向微服务架构转型的坚实一步。不久的将来,ERP会进一步将各业务拆分成众多的微服务,而微服务势必需要进行容器化部署和运行管理,这就要求ERP技术底层必须支持跨平台,所以将现有ERP系统从.NET Framework迁移到 .NET Core平台势在必行。

    上一篇《【复杂系统迁移 .NET Core平台系列】之迁移项目工程》的文章中,我们分享了在改造.NET Core工程和类库过程中的经验,本文我们将分享在界面层改造过程中遇到的问题和解决思路。

    ERP目前使用的是Asp.Net WebForm框架,在.NET Core中已经被废弃了,那么这部分就只有采用重写的方式。在Asp.Net Core Mvc中RazorPage的访问方式跟WebForm基于物理路径的访问提供了类似的机制;并且PageModel也跟Aspx的CodeBehind的方式类似。就是基于这样类似的方式,提供了结构和逻辑复用的可能性。基于这个起点,本篇将从如下步骤讲述界面层的改造过程:

  1. 页面路由:改造Url重定向的逻辑,定位到页面;

  2. Aspx页面:改造Aspx页面为cshtml页面;

  3. 模板页面:改造Master为Layout页面;

  4. 服务端控件:改造服务端用户Ascx页面。

二、页面路由改造

    ERP的页面有两种,一种是由建模配置出来的叫标准页面,由平台托管来提供功能;另一种是自定义页面,自己写Aspx实现所有业务逻辑。标准页面使用Url重写,而自定义页面直接用路径访问。在Asp.Net Core MVC中从Url映射到RazorPage是通过路由模块来实现的,为了支持以前的访问Url不变,我们需要对路由进行扩展。

    区别于传统Asp.Net Mvc的页面通过路径加载,然后运行时编译不同,在.NET Core中默认是直接将*.cshtml页面编译到DLL中,然后通过AssemblyPart加载到MVC框架中,默认RazorPage的路径是DLL中相对于Page文件夹的路径。

    例如下图所示的页面访问路径为“/PubPlatform/Nav/Home/Default”:

ab7a7e01-6e1e-eb11-8da9-e4434bdf6706.png

1、标准页面路由

   举一个平台的标准页面Url的例子:“/std/00002212/822952a2-5091-e711-9bda-001583b5bd1a.aspx”。这个Url可以通过HttpModule重写为:

“/_frontend/templates/pages/Grid/template.aspx?FunctionCode=00002212&_pagename=822952a2-5091-e711-9bda-001583b5bd1a”。重写主要目的是找到“822952a2-5091-e711-9bda-001583b5bd1a”这个ID对应页面元数据内容,然后通过配置映射到物理路径的template.aspx页面。

 RazorPage是通过IPageRouteModel Convention来提供路由的扩展的,提供了PageRouteModelConvention和FolderRoute ModelConvention类来实现扩展,这两种使用方式可以通过内置的AddPageRoute和AddFolderRouteModelConvention方法来实现,下面是平台使用文件夹路由转换的代码示例:

b27a7e01-6e1e-eb11-8da9-e4434bdf6706.png

    在上述代码中我们为所有/templates/pages路径下的页面,添加三个路由参数:

  1. AppConst.FunctionCodeKey(FucntionCode):模块代码 对应上述Url中的00002212;

  2. AppConst.PageNameKey(PageName):元数据标识 对应上述Url中的822952a2-5091-e711-9bda-001583b5bd1a;

  3. AppConst.PageKey(Page):RazorPage页面的相对于Page文件夹的路径(框架自带)。

    TemplateConstraint实现IActionConstraint用于在路由系统中决定URL是否匹配当前页面,还是仿照之前HttpModule中Url重写逻辑来做路由匹配即可实现Url路由到对应的RazorPage。

2、自定义页面路由

    我们先看看改造前和改造后页面的组织结构对比:

b77a7e01-6e1e-eb11-8da9-e4434bdf6706.png

  在改造自定义页面路由的时候我们使用IPageRouteModelProvider扩展OnProviders Executing,扩展代码如下:

bb7a7e01-6e1e-eb11-8da9-e4434bdf6706.png

    在标准页面中我们使用了MVC自带的扩展机制,自定义页面我们使用IPageRoute ModelProvider扩展OnProvidersExecuting,因为在标准页面中我们使用路径来做匹配,但是自定义页面中需要兼容产品页面路径和项目页面路径,使用了类似于黑名单和白名单的区别,所以分别采用了不同的策略。另外这里我们扩展了OnProvidersExecuted的方法,在所有路由加载完之后来进行路由替换,来实现项目页面替换产品页面。

三、页面改造

    解决了路由访问的问题,接下来就要进行Aspx页面改造成cshtml了。首先我们简单介绍下RazorPage的一些基本特性:

  1. 前端通过cshmtl来渲染Html;

  2. 后端通过PageModel来处理业务逻辑;

  3. 通过OnGet或者OnPost来提供访问;

  4. 通过PageModel属性和BindProperty来实现参数到模型的绑定;

  5. 通过PageModel属性实现PageModel到cshtml页面的数据传递。

    ERP所有的Aspx都没有*.cs的后台代码。这里简单介绍下ERP对Aspx页面的使用规范:

  1. 实现Html渲染逻辑;

  2. OnLoad方法重写实现取数等简单后台操作;

  3. 页面回传请求通过Ajax处理 从功能特性可以发现我们不用处理传统Aspx的回传的请求。Aspx的OnLoad可以使用RazorPag的OnGet方法中来替换,然后赋值给PageModel的属性来传递给cshtml来绑定数据,页面中只需要将Aspx语法替换成Razor的语法即可。

    语法转换工具可以从这里找到:https://github.com/telerik/razor-converter。

    在之前ERP中由于缺少了继承自Page的基类所以在页面中会有重复代码,在新版本改造中我们将一些通用方法进行了抽取,做了如下的继承层级的改造:

be7a7e01-6e1e-eb11-8da9-e4434bdf6706.png

    有了这一层之后就能对一些例如权限、多语言、多时区等进行通用代码的封装。并且为以后通用逻辑等定义一个可扩展的地方。但是封装之后还有一个问题如果每个页面都需要去设置继承关系就会显得有些重复,并且容易犯错,在MVC中提供了如下两种简洁的方式:

  1. _ViewStart中定义的逻辑全部页面生效;

  2. _ViewImport按照目录优先级,路径靠近_ViewImport会重写上层的逻辑,对下层的页面生效。

四、模板页面改造

    我们在做页面的时候一般都是需要使用Master页面来做布局封装的,首先我们来一张看看平台Aspx和cshtml的布局层级对比图 :

c47a7e01-6e1e-eb11-8da9-e4434bdf6706.png

1、顶层Layout页面

    原来的Master页面中有大量的重复代码,所以这里做了一层抽象。顶层Layout页面用来定义Html结构,通常html中将css部分放在header中,将script部分放在body的最下面。另外css和js分别可以分类为,第三方css/js,通用css/js,文件引用的css/js,系统自定义输出到界面的css/js和用户自定义的css和js,这些都是通过MVC的RenderSection方法,提供类似与类中virutal方法一样可以由页面重写。下面是示例代码:

cc7a7e01-6e1e-eb11-8da9-e4434bdf6706.png

2、模板页面

    Nav模板页面定义Body结构,包括不同的页面布局:

  • _Nav.cshtml 用来定义带导航的页面;

  • _Json.cshtml 用来定义json页面;

  • _Content.cshtml 用来定义无导航的内容页面;

  • _Dialog.cshtml 用来定义弹框页面。

3、模板页面设置

    在ERP中因为标准页面可以挂载到不同的模板中,例如常见的表单页面可以加载到带导航的页面中,也可以加载到弹出框中。而且指定模板的方式不是通过直接跟路径关联.由于使用了预编译的机制,并且页面的路径希望对其他引用者屏蔽,所以用名字代替页面路径来设置模板,从而让模板页面路径和使用者解耦。通过如下逻辑来替换:

  1. 在自定义页面中我们直接使用名字指定;

  2. 在标准建模页面中我们使用元数据中配置的名字来指定;

  3. 在url中通过_mp参数来指定模板的名字,兼容一些图书兼容场景,例如页面嵌套的业务场景;

  4. 最终为了兼容一套名称和路径对应关系,兼容Framework和Core我们使用了类似如下的映射方式。

cf7a7e01-6e1e-eb11-8da9-e4434bdf6706.png五、服务端控件ascx改造

    在Aspx的使用中为了提高代码的复用程度,一般都会使用Ascx的自定义控件,在MVC中有多种的替代方式,在比较单纯的数据绑定页面中我们使用了PartialView来替代,这部分主要在布局页面中使用,有如下模板:

  1. Collapse.cshtml分类组件页面,默认收起左侧导航;

  2. Footer.cshtml 底部组件,用于返回顶部;

  3. Holder.cshtml 内容部件;

  4. Navbar.cshtml 顶部导航组件,用于显示用户相关设置通知等信息;

  5. Sidebar.cshtml 用于显示左边菜单。

    为了将CSS,JS等资源加载更加集中化,我们也将布局页面中一些资源按照功能加载进行了加载。如下:

  1. 模块化sea.js;

  2. 默认的一些输出到界面的js变量,如用户名,时区,页面元数据等;

  3. 权限事件脚本等,(之前这部分可能会放在后台cs代码中,现在也放在部分页里面加载)。

    除了这些简单逻辑之外,还有一些组件会直接使用后台的服务取数据,然后渲染页面这部分使用Core的Component(视图组件)来加载 例如tab页面的加载,这里需要取得上下文中用户信息,从而获取权限然后判断是否加载。

    在标准页面中会用到列表,树列表等大控件,这类控件的逻辑在后台配合RazorEngine来渲染的,这部分对Asp.NET Core MVC正好兼容,在原来是通过自定义控件来提供访问,在Asp.NET MVC中是通过Html.XXXFor类似方法提供访问,在Core中为了让cshtml可读性更好,提供了TagHelper的方式,这里也将访问方式通过了TagHelper封装,代码示例:

d57a7e01-6e1e-eb11-8da9-e4434bdf6706.png六、总结

    在Framework中有很多前端代码和后端代码糅合在一个Aspx页面中。有了RazorPage之后可以用cshtml来渲染界面,使用PageModel来处理数据,这样做到前端逻辑和后端逻辑的分离,并且根据职责将之前的不同功能的界面渲染需求,进行封装和职责的分离,使前端渲染逻辑更加清晰也更容易维护。在下一篇分享中,我们将介绍针对页面资源文件引用(例如CSS、JS文件)的迁移过程,大家敬请期待。

------ END ------

作者简介

熊同学: 研发工程师,目前负责ERP运行平台的设计与开发工作。

也许您还想看

【复杂系统迁移 .NET Core平台系列】之迁移项目工程

.NET Core MVC扩展实践

分布式锁的实现与探索

ERP缓存实践经验分享

ef7a7e01-6e1e-eb11-8da9-e4434bdf6706.jpeg




推荐阅读
  • Web开发框架概览:Java与JavaScript技术及框架综述
    Web开发涉及服务器端和客户端的协同工作。在服务器端,Java是一种优秀的编程语言,适用于构建各种功能模块,如通过Servlet实现特定服务。客户端则主要依赖HTML进行内容展示,同时借助JavaScript增强交互性和动态效果。此外,现代Web开发还广泛使用各种框架和库,如Spring Boot、React和Vue.js,以提高开发效率和应用性能。 ... [详细]
  • 在Java项目中,当两个文件进行互相调用时出现了函数错误。具体问题出现在 `MainFrame.java` 文件中,该文件位于 `cn.javass.bookmgr` 包下,并且导入了 `java.awt.BorderLayout` 和 `java.awt.Event` 等相关类。为了确保项目的正常运行,请求提供专业的解决方案,以解决函数调用中的错误。建议从类路径、依赖关系和方法签名等方面入手,进行全面排查和调试。 ... [详细]
  • 第六章:枚举类型与switch结构的应用分析
    第六章深入探讨了枚举类型与 `switch` 结构在编程中的应用。枚举类型(`enum`)是一种将一组相关常量组织在一起的数据类型,广泛存在于多种编程语言中。例如,在 Cocoa 框架中,处理文本对齐时常用 `NSTextAlignment` 枚举来表示不同的对齐方式。通过结合 `switch` 结构,可以更清晰、高效地实现基于枚举值的逻辑分支,提高代码的可读性和维护性。 ... [详细]
  • 在Kohana 3框架中,实现最优的即时消息显示方法是许多开发者关注的问题。本文将探讨如何高效、优雅地展示flash消息,包括最佳实践和技术细节,以提升用户体验和代码可维护性。 ... [详细]
  • 在没有功能代码的C++控制台应用程序中,观察到有三个线程在运行。根据Stack Overflow的解释,Windows操作系统为了加速进程启动,会在程序开始执行时利用多个CPU内核进行快速初始化,这涉及到`ntdll.dll`库的调用。通过深入了解这些线程的行为,可以更好地进行性能优化,提高应用程序的响应速度和效率。 ... [详细]
  • 本文深入探讨了NoSQL数据库的四大主要类型:键值对存储、文档存储、列式存储和图数据库。NoSQL(Not Only SQL)是指一系列非关系型数据库系统,它们不依赖于固定模式的数据存储方式,能够灵活处理大规模、高并发的数据需求。键值对存储适用于简单的数据结构;文档存储支持复杂的数据对象;列式存储优化了大数据量的读写性能;而图数据库则擅长处理复杂的关系网络。每种类型的NoSQL数据库都有其独特的优势和应用场景,本文将详细分析它们的特点及应用实例。 ... [详细]
  • 本文详细探讨了使用纯JavaScript开发经典贪吃蛇游戏的技术细节和实现方法。通过具体的代码示例,深入解析了游戏逻辑、动画效果及用户交互的实现过程,为开发者提供了宝贵的参考和实践经验。 ... [详细]
  • ButterKnife 是一款用于 Android 开发的注解库,主要用于简化视图和事件绑定。本文详细介绍了 ButterKnife 的基础用法,包括如何通过注解实现字段和方法的绑定,以及在实际项目中的应用示例。此外,文章还提到了截至 2016 年 4 月 29 日,ButterKnife 的最新版本为 8.0.1,为开发者提供了最新的功能和性能优化。 ... [详细]
  • 本文探讨了资源访问的学习路径与方法,旨在帮助学习者更高效地获取和利用各类资源。通过分析不同资源的特点和应用场景,提出了多种实用的学习策略和技术手段,为学习者提供了系统的指导和建议。 ... [详细]
  • 解决lib-flexible安装过程中遇到的错误问题
    在安装 lib-flexible 时,遇到了 `saveError ENOENT: No such file or directory` 错误,具体表现为无法打开 `E:\Github\SDIO\package.json` 文件。解决此问题的关键在于确保项目根目录下存在 `package.json` 文件,并且在正确的项目路径中执行安装命令。建议先检查项目结构,确认文件是否存在,然后再尝试重新安装依赖。 ... [详细]
  • 设计实战 | 10个Kotlin项目深度解析:首页模块开发详解
    设计实战 | 10个Kotlin项目深度解析:首页模块开发详解 ... [详细]
  • 掌握Android UI设计:利用ZoomControls实现图片缩放功能
    本文介绍了如何在Android应用中通过使用ZoomControls组件来实现图片的缩放功能。ZoomControls提供了一种简单且直观的方式,让用户可以通过点击放大和缩小按钮来调整图片的显示大小。文章详细讲解了ZoomControls的基本用法、布局设置以及与ImageView的结合使用方法,适合初学者快速掌握Android UI设计中的这一重要功能。 ... [详细]
  • jQuery插件验证与屏幕键盘功能的集成解决方案
    本文介绍了一种集成了验证功能和屏幕键盘的jQuery插件解决方案。该插件不仅提供了强大的表单验证功能,还引入了一个高度可定制的屏幕键盘,以增强用户体验。通过这一集成方案,开发者可以轻松实现复杂的表单验证逻辑,并为用户提供便捷的输入方式,特别适用于移动设备或特殊输入场景。 ... [详细]
  • 在探讨C语言编程文本编辑器的最佳选择与专业推荐时,本文将引导读者构建一个基础的文本编辑器程序。该程序不仅能够打开并显示文本文件的内容及其路径,还集成了菜单和工具栏功能,为用户提供更加便捷的操作体验。通过本案例的学习,读者可以深入了解文本编辑器的核心实现机制。 ... [详细]
  • GDB 使用心得与技巧总结
    在使用 GDB 进行调试时,可以采用以下技巧提升效率:1. 通过设置 `set print pretty on` 来美化打印输出,使数据结构更加易读;2. 掌握常见数据结构的打印方法,如链表、树等;3. 利用 `info locals` 命令查看当前作用域内的所有局部变量;4. 在需要进行类型强制转换时,正确使用语法,例如 `p (Test::A *) pObj`。这些技巧能够显著提高调试的便捷性和准确性。 ... [详细]
author-avatar
爱着你心却痛_534
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有