MVC WebAPI 三層分佈式框架開發

前言:SOA(面向服務的架構)是目前企業應用開發過程當中廣泛採用的技術,基於MVC WebAPI三層分佈式框架開發,以此適用於企業信息系統的業務處理,是本文論述的重點。此外,插件技術的應用,富客戶端jQuery實現技術,本文也對其具體實現作以說明。相關示例解決方案能夠參考GitHub資源,在文章結尾給出。html

 

1. 系統分層體系架構設計前端

 

分佈式三層系統簡單分爲數據訪問層,業務邏輯層和前端展示層。分層架構設計是構建大型分佈式系統的必要手段,由於可使得系統健壯,可擴展。java

 

SOA即面向服務的架構,能夠幫助企業構建靈活,擴展性強的複雜業務系統,按照服務的理念進行功能交付,調用方也不用去知道實現一方的具體細節;雙方是按照統一消息格式,接口方式進行交互的。


SOA的實現是基於以Web服務的方式發佈Api接口,目前WebAPI是一種Restfule形式的Web服務,相比WCF的複雜性,WebAPI的開發效率更高,並且在配置時也不須要客戶端和服務端的xml配置。


企業核心業務數據可讓桌面、Web、平板、手機或物聯設備訪問,因此須要統一API接口,WebApi做爲業務邏輯處理服務可以知足接口訪問和接口之間交互的需求。mysql

2.基礎類庫模塊
2.1 數據訪問:Dapper-微型ORMapping框架
Dapper的優點:
1,Dapper是一個輕型的ORM類。代碼就一個SqlMapper.cs文件,編譯後就40K的一個很小的Dll.
2,Dapper很快。Dapper的速度接近與IDataReader,取列表的數據超過了DataTable。
3,Dapper支持Mysql,SqlLite,Mssql,Oracle等一系列的數據庫,固然若是你知道原理也可讓它支持Mongo db
4,Dapper的r支持多表並聯的對象。支持一對多 多對多的關係。而且沒侵入性,想用就用,不想用就不用。無XML無屬性。代碼之前怎麼寫如今還怎麼寫。
5,Dapper原理經過Emit反射IDataReader的序列隊列,來快速的獲得和產生對象。性能實在高。
6,Dapper 是C#實現,支持.net framework 各類版本;

7,Dapper語法十分簡單。而且無須遷就數據庫的設計。jquery

國外大型網站採用的有:
–StackOverflow, StackExcahnge等。。。

讀取500條記錄,並作簡單對象的序列化操做時間對好比下圖:git

2.2 DataRepository類github

 

•實現數據實體操做封裝
-Insert—插入
-Update—更新
-Delete—刪除
-Select—選取
-Paged—分頁
2.3  ServiceBase類
•實現業務實體對象的操做封裝
–Insert—插入
–Update—更新
–Delete—刪除
–Select—選取
–Paged—分頁
2.4 服務實現類

 

-實現Iservice接口
-繼承ServiceBase基類
 
2.5 WebAPI服務發佈

API Controllerajax

    --[HttpGet]sql

    --[HttpPost]

    --[HttpPut]

    --[HttpDelete]

2.6 動態加載插件
-系統的擴展性
-系統的變化性
-客戶二次開發
-MEF
–運行時加載
 
2.7 AutoMapper—實體對象之間轉換
•兩個實體類
–EPProduct –  數據實體
–Product–  業務實體
•轉化示例代碼
–EPProduct  p =ProductRepository.Get(long.Parse(id));
–AutoMapper.Mapper.CreateMap<EPProduct, Product>();
–Productentity =AutoMapper.Mapper.Map<EPProduct, Product>(p)
 
2.8 面向接口編程--Ioc框架
•SimpleInjector
–靜態類型
–編譯階段
•MEF
–動態類型
–運行時階段
 
3.富客戶端開發
3.1 Asp.NETMVC 富客戶端開發
•Model
–WebAPI (服務接口)
•Controller
–路由
•View
–頁面
•富客戶端
–Ajax 局部刷新
– 鼠標、鍵盤響應事件等
–如Gmail郵箱等應用示例
3.2 Jquery插件
•Layout—Jquery Layout
•DataGrid – SlickGrid –性能很是高
•Tree– Jstree/Ztree –評價都不錯
•Tab– Jquery Tools
•Toolbar– Jquery Tools
•Dialog– Jquery Tools
•Form–Jquery Tools
3.3 前端頁面Ajax調用:
GET/POST/PUT/DELETE
[javascript]  view plain copy
  1. /*** 
  2.     * HttpGet獲取服務端數據 
  3.     * @url 業務數據 
  4.     * @data 
  5.     */  
  6.    $.doHttpClientGet = function(url, fn) {  
  7.        $.getJSON(url, fn);  
  8.    }  
  9.   
  10.   
  11.    /*** 
  12.     * HttpPut更新數據到服務端 
  13.     * @url 業務數據 
  14.     * @data 
  15.     */  
  16.    $.doHttpClientUpdate = function(url, data, fn) {  
  17.        $.ajax({  
  18.            url: url,  
  19.            type: 'PUT',  
  20.            data: data,  
  21.            dataType: 'json',  
  22.            contentType: 'application/json',  
  23.            success: fn  
  24.        });  
  25.    }  
  26.   
  27.   
  28.    /*** 
  29.     * HttpDelete刪除數據 
  30.     * @url 業務數據 
  31.     * @data 
  32.     */  
  33.    $.doHttpClientDelete = function(url, data, fn) {  
  34.        $.ajax({  
  35.            url: url,  
  36.            type: 'DELETE',  
  37.            data: data,  
  38.            dataType: 'json',  
  39.            contentType: 'application/json',  
  40.            success: fn  
  41.        });  
  42.    }  
  43.   
  44.   
  45.    /*** 
  46.     * HttpPost保存數據 
  47.     * @url 業務數據 
  48.     * @data 
  49.     */  
  50.    $.doHttpClientSave = function(url, data, fn) {  
  51.        $.ajax({  
  52.            url: url,  
  53.            type: 'POST',  
  54.            data: data,  
  55.            dataType: 'json',  
  56.            contentType: 'application/json',  
  57.            success: fn  
  58.        });  
  59.    }  
  60.   
  61.   
  62.    /*** 
  63.     * ajax獲取服務端數據 
  64.     * @url 業務數據 
  65.     * @data 
  66.     */  
  67.    $.doAjaxGet = function(url, fn) {  
  68.        //$.getJSON(url, fn);  
  69.        $.ajax({  
  70.            url: url,  
  71.            type: "GET",  
  72.            dataType: 'json',  
  73.            //data: data,  
  74.            contentType: 'application/json',  
  75.            success: fn  
  76.        });  
  77.    }  
  78.   
  79.   
  80.    $.doAjaxPost = function(url, data, fn) {  
  81.        $.ajax({  
  82.            url: url,  
  83.            type: 'POST',  
  84.            data: data,  
  85.            dataType: 'json',  
  86.            contentType: 'application/json',  
  87.            success: fn  
  88.        });  
  89.    }  
  90.   
  91.   
  92.    //構造html的通用方法  
  93.    $.buildHTML = function(tag, html, attrs) {  
  94.        // you can skip html param  
  95.        if (typeof (html) != 'string') {  
  96.            attrs = html;  
  97.            html = null;  
  98.        }  
  99.        var h = '<' + tag;  
  100.        for (attr in attrs) {  
  101.            if (attrs[attr] === false) continue;  
  102.            h += ' ' + attr + '="' + attrs[attr] + '"';  
  103.        }  
  104.        return h += html ? ">" + html + "</" + tag + ">" : "/>";  
  105.    }  
  106.   
  107.   
  108.    //構造JsTree的通用方法  
  109.    $.fn.buildJsTree = function (url, fn) {  
  110.        var object = require(['jstree'], function(){  
  111.            $.jstree._themes = "/PlatJS/Scripts/jstree/themes/";  
  112.            var myTree = $(this).jstree({  
  113.                "json_data": {  
  114.                    "ajax": {  
  115.                        "url": url,  
  116.                        "type": "GET",  
  117.                        "dataType": "json",  
  118.                        "contentType": "application/json charset=utf-8",  
  119.                        "success": fn  
  120.                    }  
  121.                },  
  122.                "plugins": ["themes", "json_data", "ui"]  
  123.            });  
  124.        })  
  125.    }  

3.4 如何調試?
•Fiddler--*****5star

FireBug for Firefox

•查看HTML,CSS,Javascript等
•監控下載圖片資源時間線
•完善友好的調試
 

Firefox的RestClient插件—Rest Client測試插件

http://localhost:8081/ProductSys.WebAPI/api/order/insertwith?type="insertwith

 [HttpPost]

public HttpResponseMessageInsertWith(Order entity, string type)

 

http://localhost:8081/ProductSys.WebAPI/api/order/4

 [HttpDelete]

 public HttpResponseMessage Delete(string id)

 

 

3.5 Web異常錯誤代碼

 

•100-199– Informational
•200-299– Client request successful
•300-399– Client request redirected, further action necessary
•400-499– Client request incomplete
•500-599– Server error
 
4. Javascript 類語法
4.1 常見問題
•Namespace(命名空間)
–默認爲全局範圍,有潛在類型衝突隱患
•SelfExecuting Fuction (自執行匿名函數)
•Objectand Array (對象和數組初始化)
–不要使用new  關鍵字
•NullOr Empty (檢查NULL)

4.2 Javascript-自執行匿名函數
[javascript]  view plain copy
  1. //Self-Executing Anonymous Func: Part 2 (Public & Private)  
  2. (function( skillet, $, undefined ) {  
  3.     //Private Property  
  4.     var isHot = true;  
  5.    
  6.     //Public Property  
  7.     skillet.ingredient = "Bacon Strips";  
  8.        
  9.     //Public Method  
  10.     skillet.fry = function() {  
  11.         var oliveOil;  
  12.            
  13.         addItem( "\t\n Butter \n\t" );  
  14.         addItem( oliveOil );  
  15.         console.log( "Frying " + skillet.ingredient );  
  16.     };  
  17.        
  18.     //Private Method  
  19.     function addItem( item ) {  
  20.         if ( item !== undefined ) {  
  21.             console.log( "Adding " + $.trim(item) );  
  22.         }  
  23.     }      
  24. }( window.skillet = window.skillet || {}, jQuery ));  
  25.  <pre name="code" class="javascript">//Public Properties  
  26. console.log( skillet.ingredient ); //Bacon Strips  
  27.    
  28. //Public Methods  
  29. skillet.fry(); //Adding Butter & Fraying Bacon Strips  
  30.    
  31. //Adding a Public Property  
  32. skillet.quantity = "12";  
  33. console.log( skillet.quantity ); //12  
  34.    
  35. //Adding New Functionality to the Skillet  
  36. (function( skillet, $, undefined ) {  
  37.     //Private Property  
  38.     var amountOfGrease = "1 Cup";  
  39.        
  40.     //Public Method  
  41.     skillet.toString = function() {  
  42.         console.log( skillet.quantity + " " +   
  43.                      skillet.ingredient + " & " +   
  44.                      amountOfGrease + " of Grease" );  
  45.         console.log( isHot ? "Hot" : "Cold" );  
  46.     };      
  47. }( window.skillet = window.skillet || {}, jQuery ));  
  48.    
  49. try {  
  50.     //12 Bacon Strips & 1 Cup of Grease  
  51.     skillet.toString(); //Throws Exception  
  52. catch( e ) {  
  53.     console.log( e.message ); //isHot is not defined  
  54. }  
[javascript]  view plain copy
  1. </pre>  
 
4.3 對象和數組初始化
[javascript]  view plain copy
  1. //建議申明對象或數組的寫法  
  2. var person = {},   
  3.     keys = [];  
  4.   
  5. //申明覆雜對象或數組的寫法  
  6. var person = {  
  7.         firstName: "Elijah",  
  8.         lastName: "Manor",  
  9.         sayFullName: function() {  
  10.             console.log( this.firstName + " " +   
  11.                 this.lastName );  
  12.         }  
  13.     },   
  14.     keys = ["123", "676", "242", "4e3"];  

4.4 判斷對象是否爲NULL(c#)
[csharp]  view plain copy
  1. // <span >C# 例子. 不要在Javascript中這樣寫</span>  
  2. if ( someString != null &&  
  3.     someString.length > 0 ) {  
  4.     //Do something here...  
  5. }  
  6.   
  7. // C# 例子 檢查字符串是否爲空  
  8. if ( !string.IsNullOrEmpty(someString) ) {  
  9.     //Do something here...  
  10. }  

4.5 判斷對象是否爲NULL(javascript)
[javascript]  view plain copy
  1. Javascript中的正確寫法  
  2. // Simplified JavaScript syntax to check for  
  3. // undefined, null, & empty string values  
  4. if ( someString ) {  
  5.     //Do something here...  
  6. }  

4.6 設置缺省值(c#)
 
[csharp]  view plain copy
  1. <span style="color: rgb(255, 0, 0);">// C# 例子,不要在Javascript這樣寫</span>  
  2. if ( someString == null ) {  
  3.    someString = "default Value";  
  4. }  
  5. // Slightly better, but don't do this either  
  6. someString = someString ? someString : "default value"; <pre name="code" class="javascript">請在Javascript按以下格式寫  
  7. // JavaScript syntax to set a default value  
  8. someString = someString || "default value";  
 
 
4.7 不一樣類型的比較操做符(==, !=)
•// Unexpected Comparisons using the== Operator
•0         ==  ''        //true
•0         ==  '0'       //true
•false     ==  '0'       //true
•null      ==  undefined //true
•'\t\r\n ' ==  0         //true
 
4.8 不一樣類型的比較操做符(===, !==)
•// Expected Comparisons using the ===Operator
•0         === ''        //false
•0         === '0'       //false
•false     === '0'       //false
•null      === undefined //false
•'\t\r\n ' === 0         //false
 
4.9  不可取的數組遍歷操做符for…in
[csharp]  view plain copy
  1. var myArray = [], name;  
  2. myArray[5] = "test";  
  3. console.log( myArray.length ); //6  
  4.    
  5. for ( name in myArray ) {  
  6.     console.log( name, myArray[name] );  
  7.     //Outputs...  
  8.     //   5, test  
  9. }  

4.10 正確的數組遍歷操做符for…;…;
[javascript]  view plain copy
  1. var myArray = [], name;  
  2. myArray[5] = "test";  
  3. console.log( myArray.length ); //6  
  4.    
  5. for ( var i = 0, length = myArray.length; i < length; i++ ) {  
  6.     console.log( i, myArray[i] );  
  7.     //Outputs...  
  8.     //   0, undefined  
  9.     //   1, undefined  
  10.     //   2, undefined  
  11.     //   3, undefined  
  12.     //   4, undefined  
  13.     //   5, test  
  14. }  
[javascript]  view plain copy
  1. for ( var name in object ) {  
  2.     //Your code here  
  3. }  
  4.   
  5. /* Check if object has property before 
  6. iterating, because functions inherited 
  7. from prototype are also included */  
  8. for ( var name in object ) {  
  9.    if ( object.hasOwnProperty(name) ) {  
  10.       //Your code here  
  11.    }  
  12. }  
 
5. RequireJS 模塊化腳本
RequireJS 是一個很是小巧的 JavaScript 模塊載入框架,是 AMD 規範最好的實現者之一。最新版本的 RequireJS 壓縮後只有 14K,堪稱很是輕量。它還同時能夠和其餘的框架協同工做,使用 RequireJS 必將使的前端代碼質量得以提高。
 
RequireJS 做爲 JavaScript 文件的加載器,仍是能夠完成異步非阻塞的文件加載。
[javascript]  view plain copy
  1. define(['Controllers/Main/ListView'], function (ListView) {  
  2.     function start() {  
  3.         var users = JSON.parse(localStorage.users);  
  4.         ListView.render({ users: users });  
  5.     }  
  6.   
  7.     return {  
  8.         start: start  
  9.     };  
  10. });  
 
6. 網絡資源
6.1 NuGet—快捷獲取軟件包
•充分利用開源軟件包,避免重複製造輪子;
•也能夠本身發佈軟件包,回饋社區,先進技術的積累能夠節約項目成本。
6.2 技術資源
 
•Asp.net MVC WebAPI
–RestfulWeb Service的發展
•Jquery
–官網
–插件開發
•RequrieJS
–Javascript模塊化開發框架
•Dapper
–微型ORMapping 框架
•EntityFramework
–Microsoft實體框架
 
7. 總結:
本文基於MVC WebAPI實現分佈式三層架構,實現了通用數據訪問操做,業務實體和數據實體的交互操做,業務模塊之間的接口交互;實現了插件化的加載技術。此外限於篇幅,對於流程化的設計,會在下文論述,主要會談及到工做流Api和WebApi的交互。
 
 
代碼示例說明:

提供的示例RequireMVC199中,能夠看一下ProductSys.WebApi的服務層代碼,前端代碼看RequireMvc199的WebApplication項目便可。

 

完整示例,能夠看一下ProductList頁面的代碼,這個示例是完整的,包括文件:

WebApplication 包括:

\Controllers

    --ProductController.cs

\ViewJS

  \Controllers

    \Product

       --product-list.js

      --product-detail.js

 

\Views

  \Product

    --productlist.cshtml

 

WebApi 包括:

ProductSys.WebApi

  \Controllers

    --ProductController.cs

 

ProductSys.ServiceImp

  \Service

    --ProductService.cs

 
解決方案下載地址:
https://github.com/besley/Plat2012
 
新版本下載:
http://github.com/besley/slickone
 
後記:
不斷有朋友問到,是否有新版本?是否支持ORACLE?目前在最新的版本里已經解決這些問題。你能夠在Slickflow的項目裏面看到,即仍然是Mvc, WebApi和Dapper的架構,可是簡化甚多,真是物至簡方可盡其用,但願你們一塊兒學習討論。謝謝你們關注。
相關文章
相關標籤/搜索