• MVC WebAPI 三层分布式框架开发


    前言:SOA(面向服务的架构)是目前企业应用开发过程中普遍采用的技术,基于MVC WebAPI三层分布式框架开发,以此适用于企业信息系统的业务处理,是本文论述的重点。此外,插件技术的应用,富客户端jQuery实现技术,本文也对其具体实现做以说明。相关示例解决方案可以参考GitHub资源,在文章结尾给出。

    1. 系统分层体系架构设计

    分布式三层系统简单分为数据访问层,业务逻辑层和前端展现层。分层架构设计是构建大型分布式系统的必要手段,因为可以使得系统健壮,可扩展。

    SOA即面向服务的架构,可以帮助企业构建灵活,扩展性强的复杂业务系统,按照服务的理念进行功能交付,调用方也不用去知道实现一方的具体细节;双方是按照统一消息格式,接口方式进行交互的。


    SOA的实现是基于以Web服务的方式发布Api接口,目前WebAPI是一种Restfule形式的Web服务,相比WCF的复杂性,WebAPI的开发效率更高,而且在配置时也不需要客户端和服务端的xml配置。


    企业核心业务数据可以让桌面、Web、平板、手机或物联设备访问,所以需要统一API接口,WebApi作为业务逻辑处理服务能够满足接口访问和接口之间交互的需求。

    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语法十分简单。并且无须迁就数据库的设计。

    国外大型网站采用的有:
    –StackOverflow, StackExcahnge等。。。

    读取500条记录,并做简单对象的序列化操作时间对比如下图:

    2.2 DataRepository类

    •实现数据实体操作封装
    -Insert—插入
    -Update—更新
    -Delete—删除
    -Select—选取
    -Paged—分页
    2.3  ServiceBase类
    •实现业务实体对象的操作封装
    –Insert—插入
    –Update—更新
    –Delete—删除
    –Select—选取
    –Paged—分页
    2.4 服务实现类
    -实现Iservice接口
    -继承ServiceBase基类
     
    2.5 WebAPI服务发布

    API Controller

        --[HttpGet]

        --[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( "  Butter  " );  
    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
    •' ' ==  0         //true
     
    4.8 不同类型的比较操作符(===, !==)
    •// Expected Comparisons using the ===Operator
    •0         === ''        //false
    •0         === '0'       //false
    •false     === '0'       //false
    •null      === undefined //false
    •' ' === 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的架构,但是简化甚多,真是物至简方可尽其用,希望大家一起学习讨论。谢谢大家关注。
  • 相关阅读:
    数学之美(吴军著)学习总结和经典摘抄
    【翻译自mos文章】Oracle GoldenGate 怎么在源头的传输进程和目的端的server/collector进程之间分配 port?
    atitit.浏览器插件解决方式----ftp插件 attilax 总结
    Libgdx: android单机斗地主支持局域网wifi联网的网络模块核心代码
    毕业前的五味杂陈
    Online Object Tracking: A Benchmark 论文笔记
    开源前夕先给大家赞赏一下我用C语言开发的云贴吧 站点自己主动兼容-移动、手机、PC自己主动兼容云贴吧
    JVM —— Java 对象占用空间大小计算
    Python之爬虫-京东商品
    Python之游戏开发-飞机大战
  • 原文地址:https://www.cnblogs.com/webenh/p/6094455.html
Copyright © 2020-2023  润新知