CoreCRM 開發實錄 —— 前後端分離的重構

来源:http://www.cnblogs.com/holmescn/archive/2017/05/05/frontend-backend-seperated.html
-Advertisement-
Play Games

雖然2月初就回來了,可 CoreCRM 一直到5月才開始恢復開發,期間是各種生活中的意外和不方便。 1. 為什麼要重構 首先是一件很值得高興的事情:CoreCRM 有了第一位 contributor! "Larry" 是我原來的一位實習生,現在在某公司做前端開發。因為 Larry 的加入,我就不再是 ...


雖然2月初就回來了,可 CoreCRM 一直到5月才開始恢復開發,期間是各種生活中的意外和不方便。

1. 為什麼要重構

首先是一件很值得高興的事情:CoreCRM 有了第一位 contributor!Larry 是我原來的一位實習生,現在在某公司做前端開發。因為 Larry 的加入,我就不再是一個人戰鬥了。當然,也就得考慮怎麼進行合作的事情了。

年前的開發計劃是:使用 Bootstrap 按照悟空CRM的樣子先弄出一個可以用的版本來。然後再使用一些比較好的後臺前端框架來代替 Bootstrap。在和 Larry 討論之後,他覺得 Bootstrap 已經有點跟不上時代,以後擴展 UI 都會有一些困難。加上 Bootstrap 是 jQuery 作為交互基礎的,和 VueJS 這樣的框架也是不太配合。正好 Larry 的公司正在使用螞蟻金服出品的 Ant Design 開發後臺程式,他感覺這個框架設計的不錯:組件豐富、設計合理、社區活躍、文檔豐富(還是中文)。Ant Design 基於 React Component,也是當前非常流行的前端框架,經過多年的發展,據說其組件的豐富程度已經與 jQuery 不遑多讓。

鑒於之前我使用 VueJS 做全頁渲染的經驗,我認為 React 這東西,如果不做 Server-Side Rendering(SSR),用戶體驗不會太好。如何集成 SSR,其實有兩種方案:

  1. 完全使用 nodejs 來做前端伺服器,ASP.NET Core 做 API 伺服器
  2. 集成 node 到 ASP.NET Core 里,通過 ASP.NET Core 提供一些 Web 的服務

去年我也曾經用了一周的時間去研究幾個 ASP.NET Core 的 React Server-side Rendering 方案,可一個人的精力畢竟有限,要同時使用兩種語言開發,腦子的轉換效率是一個問題。最後我放棄了 React,轉而使用 ASP.NET Core 的 Razor 來做頁面渲染了。只對其中一些動態的部分做了 VueJS 組件。不過這次情況不一樣了,有 Larry 做前端的開發,我可以把更多的精力放到後面的API 開發和架構的優化上。而且,前後分離之後,還可以在對方工作滯後的情況下繼續開發。所以我決定對整個項目進行重構。

2. 重構的嘗試

近些年前端技術發展迅速,各種 hot reload 橫行,在開發的時候要方便和高效的多。那麼應該怎麼來實現 SSR 呢?我進行了三次嘗試:

2.1 Microsoft.AspNetCore.SpaServices

做為 ASP.NET Core 團隊的作品,感覺上是比 Facebook 做的 ReactJS.NET 更好用一些。特別是和 ASP.NET Core 的互通性上,應該有一些優勢。不過,ReactJS.NET 的 SSR 已經內置,寫起來要容易一些。

一開始,我嘗試使用 aspnetcore-spa 這個 yeoman generator,可這貨居然還是使用的 typescript 做為主語言。雖然我之前也學了一點 typescript,但與別人合作的時候,就不能只考慮自己的技術棧了。為了不增加 Larry 的學習成本,以使得項目能夠儘快進入開發,我決定還是自己搞一個基於 es6 的 ClientApp。方法當然也很簡單:用 dva-cli 創建一下就 OK 了。

在完成了 ClientApp 的創建之後,需要添加一個 boot-server.js 來實現 SSR:

var { match } = require('react-router');
var { createServerRenderer } = require('aspnet-prerendering');

module.exports = createServerRenderer(function(params) {
    return new Promise(function (resolve, reject) {
        var re = /^\/([^\/]*)(/[^\/]*)?/;
        var matched = params.location.path.match(re);
        var controller = matched[1];
        var codeFile = './dist/' + controller;
        var App = require(codeFile); // eslint-disable-line

        var path = matched[2] === '' ? '/' : matched[2]; // this line is buggy.
        match({
            routes: App.routes,
            location: path
        }, function (err, redirectLocation, renderProps) {
            if (err) throw new Error("Route match failed: " + err);

            if (redirectLocation) new Error("I don't know how to redirect.");

            var initialState = {};
            resolve({ html: App.renderHTML(initialState, renderProps)});
        })
    });
});

params 里包含了一些從 Razor 傳進來的數據,比如訪問的路由、初始化數據等。這裡本來應該直接使用 params.location.path來匹配路由,進行渲染的,可是我並沒有使用完全的 SPA (Single Page Application) 架構,而是有所分離,所以就需要使用正則表達式分離 controller 和 action,然後再進行頁內的匹配。現在 repo 里的代碼只是實現了單頁的測試載入,還沒有正式的使用起來。

2.2 koa + Web API Server

本來以為上面這個方案就已經可以了。前端使用了 dva + antd + roadhog,可以直接運行一個 webpack-dev-server 直接進行開發。然後我再轉到 Razor 里做為一個 Controller 的 View。不過,Larry 希望能完全脫離 ASP.NET Core 運行前端代碼。我也考慮了使用
SpaServices 可能會有一些限制,比如:需要處理路由、不能使用 ES6,同時運行的時候也還是需要安裝 Node,其實和一個獨立的前端 Server 並沒有什麼區別。所以我又嘗試把前端的 Server 完全分離出來。

這一步可能做的有點太激進了,我嘗試使用 Web API 的模板重新創建了 CoreCRM 這個 project。結果就悲劇了:Web API 是非常輕量的框架,裡面什麼也沒有。加上如果要分離前後端 Server,比較好的許可權驗證方案是使用 JSON-Web-Token,不然還需要在兩個 Server 之前同步 session,也是比較麻煩的事情。而搞一套 JWT 的驗證機制,也不是很容易。已經有的解決方案不是太簡單,就是太複雜……

回歸 SpaServices

上面這些困難加起來,讓我覺得這裡面的學習成本現在不可接受。所以就先放棄了這個方案。在經過一點設計和開發之後,我發現這其實和使用 koa 並沒有太大的差別。問題總是可以通過一些服務間的交互來解決的。只是現在這個節點,使用 SpaServices 更容易上手一點。待到項目有一個可用的版本,後面可以嘗試以其它的方式進行重構,也不是不可能的事情。畢竟這個項目至少還有2.0版。

3. 經驗

“選擇”總是一件很困難的事情。特別是每個選項都各有利弊的時候,選擇就更加困難。每一種組合都是一種可能,每一種組合有都有它的局限。差別可能就在團隊成員之間是不是能順暢的合作。如果合作出現問題,能不能及時調整。

希望這次調整能給項目帶來更多的活力。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 調用 1 List<StackPanel> initToolBarWeChatUserSp = GetChildObjects<StackPanel>(name, typeof(StackPanel)); 調用 1 Border tbBorder = FindParent<Border>(name) ...
  • 一,頁面上有一個checkbox和一個文本框。切換checkbox能對文本框輸入文本與否: <input type="checkbox" ng-model="ckSwitch" /> <input id="Text1" type="text" ng-disabled="!ckSwitch" ng-m ...
  • 大概所有做APP的公司都是不願意做自定義的,哪怕自己的功能再爛也願意慢慢修補不願意開源一部分。 卡牛… 51信用卡… 一次次的逾期 自己寫個信用卡管理工具,從郵件中提取賬單,還款後做個登記,到了還款日前檢查是否還完,沒還完就開始給自己發郵件騷擾吧,現在的手機郵箱都有郵件通知了,然後簡訊一條接一條,想... ...
  • webservice 可以用於分散式應用程式之間的交互,和不同程式之間的交互。 概念性的東西就不說太多,下麵開始創建一個簡單的webservice的例子。這裡我用的是Visual Studio 2015開發工具。 首先創建一個空的Web應用程式。 然後滑鼠右鍵點擊項目,選擇 添加>新建項。 選擇We ...
  • 在好多的.net的書籍中都看到過逆變和協變的概念,也在網上搜了一些關於這兩個概念的解釋,但是一直感覺似懂非懂的,直到最近在項目中實際遇到了一個問題,恰好用到了逆變,總算對逆變的理解又進了一步。 逆變只能用到泛型介面和委托中,以前一直不理解為什麼要用在泛型中,今天終於想明白了。在介紹逆變之前,先來說說 ...
  • 一直很羡慕和佩服園子中伍華聰的界面設計和佈局。好多年都沒有真正寫過C/S項目了,今天翻出來6年前剛開始學習WinForm的時候寫的一個簡單的HR管理系統,思緒一下子很複雜,記得是6年前的夏天,天氣很熱,租住的房子里沒有空調,身邊放個扇子,人家周末出去玩的時候,我還在拼命的敲著代碼,一心只想著好好提高 ...
  • 在使用Sqlhelper類時,出現cs0103錯誤 當前上下文中不存在名稱configurationmanager 解決方案,除了using引用using System.Configuration外,還需在解決方案資源管理器里的“引用”中添加“System.Configuration”。 ...
  • 這個訪問層的代碼實際上是園子里某個前輩的,本人只是覺得好使,記錄了下來。 本訪問層需要通過Nuget安裝EntityFramework Core,不過個人認為EF 6同樣可以使用。 搭配資料庫,最好是Sql Server(微軟支持,你懂的) 下麵貼代碼 先是IRepository.cs 然後是實現 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...