MVC WebAPI 三层分布式框架开发

出处:http://blog.csdn.net/besley/article/details/8479943


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



国外大型网站采用的有:

�CStackOverflow, StackExcahnge等。。。



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



2.2 DataRepository

实现数据实体操作封装

-Insert―插入

-Update―更新

-Delete―删除

-Select―选取

-Paged―分页


2.3  ServiceBase

实现业务实体对象的操作封装

�CInsert―插入

�CUpdate―更新

�CDelete―删除

�CSelect―选取

�CPaged―分页



2.4 服务实现类

-实现Iservice接口

-继承ServiceBase基类



2.5 WebAPI服务发布

API Controller

    --[HttpGet]

    --[HttpPost]

    --[HttpPut]

    --[HttpDelete]



2.6 动态加载插件

-系统的扩展性

-系统的变化性

-客户二次开发

-MEF

�C运行时加载

2.7 AutoMapper实体对象之间转换

两个实体类

�CEPProduct �C 数据实体

�CProduct�C 业务实体

转化示例代码

�CEPProduct p =ProductRepository.Get(long.Parse(id));

�CAutoMapper.Mapper.CreateMap<EPProduct, Product>();

�CProductentity =AutoMapper.Mapper.Map<EPProduct, Product>(p)


2.8 面向接口编程--Ioc框架


SimpleInjector

�C静态类型

�C编译阶段

MEF

�C动态类型

�C运行时阶段

3.富客户端开发

3.1 Asp.NETMVC 富客户端开发

Model

�CWebAPI (服务接口)

Controller

�C路由

View

�C页面

�C

富客户端

�CAjax 局部刷新

�C 鼠标、键盘响应事件等

�C如Gmail邮箱等应用示例


3.2 Jquery插件

Layout―Jquery Layout

DataGrid �C SlickGrid �C性能非常高

Tree�C Jstree/Ztree �C评价都不错

Tab�C Jquery Tools

Toolbar�C Jquery Tools

Dialog�C Jquery Tools

Form�CJquery Tools


3.3 前端页面Ajax调用:
GET/POST/PUT/DELETE

[javascript] view plaincopy

  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] === falsecontinue;  

  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等

监控下载图片资源时间线

完善友好的调试



FirefoxRestClient插件―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�C Informational

200-299�C Client request successful

300-399�C Client request redirected, further action necessary

400-499�C Client request incomplete

500-599�C Server error

4. Javascript 类语法

4.1 常见问题

Namespace(命名空间)

�C默认为全局范围,有潜在类型冲突隐患

SelfExecuting Fuction (自执行匿名函数)

Objectand Array (对象和数组初始化)

�C不要使用new 关键字

NullOr Empty (检查NULL)



4.2 Javascript-自执行匿名函数

[javascript] view plaincopy

  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. }</pre><pre name="code" class="javascript"></pre>  


4.3 对象和数组初始化

[javascript] view plaincopy

  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 plaincopy

  1. // <span style="color:#ff0000;">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 plaincopy

  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 plaincopy

  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";  

  9. </pre><br>  

  10. <pre></pre>  

  11. <pre></pre>  

  12. <pre></pre>  

  13. <pre></pre>  

  14. <pre></pre>  

  15. <pre></pre>  

  16. <pre></pre>  

  17. <pre></pre>  

  18. <pre></pre>  

  19. <pre></pre>  

  20. <pre></pre>  


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 plaincopy

  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 plaincopy

  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 plaincopy

  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 plaincopy

  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

�CRestfulWeb Service的发展

Jquery

�C官网

�C插件开发

RequrieJS

�CJavascript模块化开发框架

Dapper

�C微型ORMapping 框架

EntityFramework

�CMicrosoft实体框架


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/lgsky/Plat2012


你可能感兴趣的:(ASP.NETMVC,asp.net分布式架构)