asp.net mvc应用架构的思考--Unity的应用及三层代码

最近要做一个项目,和国外的架构师聊过之后。对方提到了他准备采用asp.net mvc, jquery, Unity 等技术来代替老的技术: 如asp.net web form. 他请我帮他想一些关于架构的东西。一直以来,关于asp.net mvc应用的架构,有一些想法。正好借这个机会写出来。资深的人士可能已经知道了,就当是复习吧。欢迎发表意见。指出不足。

Unity的应用

Unity出来已经有几年了。早几年的1.2版就可以实现这里所说的功能。目前最新稳定版是2.1。正在开发的3.0也许会给我们带来更强大的功能。这里写的是如何利用Unity实现aop, 降低代码的耦合程度。高层的代码依赖于一个抽象的接口,具体实现的代码是由Unity容器里的具体实现类来完成的。因此Unity容器负责创建具体实现类的实例,将其映射到抽象接口上。这样做是为了降低代码的耦合度。另外我们的应用程序里面有很多公共的部分,如logging, Exception处理,数据库事务处理等都可以通过aop的方式来实现。试想每一个商业方法里都得写调用logging, Exception处理的代码,我们开发人员一定会累的够呛。通过Unity实现了aop,将这些公共的代码从每一个商业方法里抽取出来,让我们的代码看上去更清爽。

用Unity降低代码的耦合度

为了降低代码的耦合度,需要让高层代码依赖于一个抽象的接口。然后具体的实现类就实现这个抽象接口,在Unity容器里注册抽象接口到实现类的映射。即指定了抽象接口映射到某个具体实现类。

具体的实现代码如下:

      <register type="BusinessLogic.IBLLUserForm, BusinessLogic" mapTo="BusinessLogic.BLLUserForm, BusinessLogic">
      </register>
      <register type="BusinessLogic.IBLLUserMenu, BusinessLogic" mapTo="BusinessLogic.BLLUserMenu, BusinessLogic">
      </register>

这里“BusinessLogic"是名称空间。IBLLUserForm和IBLLUserMenu是抽象接口。其名称空间是BusinessLogic。大家可以发现,具体实现类BLLUserForm和BLLUserMenu也是在BusinessLogic名称空间里,这个并不重要,抽象接口和具体实现类可以在同一个名称空间也可以不同名称空间。关键的是抽象类与具体实现类的映射是通过Unity容器来管理的。通过register这个方式向Unity容器表明这个抽象接口和具体实现类的映射关系。这样的映射关系可以在需要的时候改变,比如将来因业务需求出现新的情况,需要一个新的具体实现类叫BLLUserForm_blabla.那么可以用BLLUserForm_blabla代替原来的BLLUserForm, 就只需要改一下配置文件就可以了。原来的代码甚至不用重新编译。试想不用Unity,那么高层代码必须得依赖于具体实现类,因为,即使有抽象接口,抽象接口本身是无法直接创建实例的。高层代码必须得用new操作符来创建一个具体实现类的实例,这样就产生了对具体实现类的直接依赖。这样代码的耦合度就变高了。Unity是一个容器,是一个制造对象的工厂,你需要多少对象,它就制造多少对象。同时能管理这些抽象接口与具体实现类的映射关系。这就是人们常说的依赖于抽象的好处。

现实当中,也许会出现抽象接口IBLLUserForm等也得改的情况,这种情况的出现是由于OOA/OOD做的不到位,没有正确地发现抽象。得重新审视当时做的分析和设计。

用Unity实现aop,让代码清爽

商业方法中访问数据库,做业务处理难免会遇到未预见的问题,当出现问题时,不希望将此问题信息直接抛给用户,而是希望将问题的详细技术信息写入log。这是一个公用的做法。每一个商业方法都来写try catch,再调用做logging的类来写log。这样就会出现很多的重复代码。好在Unity可以帮我们省去这些重复代码。看看如何做:

这是代码1, 实现Microsoft.Practices.Unity.InterceptionExtension.ICallHandler接口。实现Invoke方法。"var retvalue = getNext()(input, getNext);"是调用被拦截的方法。if(retvalue.Exception != null) 判断retvalue.Exception是判断被拦截方法是否有Exception。如果有就将Exception写log。

using System;
using System.Data;
using System.Data.Common;
using System.Collections.Generic;
using Microsoft.Practices.Unity.InterceptionExtension;
using DataAccessCommon;
using CommonUtil;

namespace BusinessLogic
{
    public class MyDBHandler : ICallHandler
    {
        private int iOrder = 0;

        public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
        {
            var retvalue = getNext()(input, getNext); // call the intercepting method
            if (retvalue.Exception != null)
            {
                SysLog.GetInstance().LogError(retvalue.Exception);
            }
            return retvalue;
        }

        public int Order
        {
            get
            {
                return iOrder;
            }
            set
            {
                iOrder = value;
            }
        }
    }
}

这是代码2, 是一个handler attribute, 这个attribute用来标记是否要Unity进行拦截。所有需要拦截的抽象接口都要加上这个attribute. 在下面代码4配置文件里的拦截policy会看抽象接口上是否有这个attribute,有的话就会进行拦截。

using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace BusinessLogic
{
    public class MyDBHandlerAttribute : HandlerAttribute
    {
        public override ICallHandler CreateHandler(IUnityContainer container)
        {
            return new MyDBHandler();
        }
    }
}

代码3, 这是一个很简单的辅助类,用来帮助在代码4的拦截配置里指定一个自定义attribute的类型。

using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace BusinessLogic
{
    public class GetTypeConverter : System.ComponentModel.TypeConverter
    {
        public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context,
            System.Globalization.CultureInfo culture,
            object value)
        {
            return Type.GetType(value.ToString());
        }
    }
}

代码4, 这是一个拦截配置,其关键点在callHandler和matchingRule上。callHandler指定了用BusinessLogic.MyDBHandler类型来进行拦截处理。MyDBHandler已经在代码1里定义好(见上面)。matchingRule,这里用的是CustomAttributeMatchingRule,即自定义的Attribute作为拦截条件。CustomAttributeMatchingRule要求两个构造函数参数,一个是Type, 一个是否使用继承的类型. 在指定Type时,用的是一个字符串:"BusinessLogic.MyDBHandlerAttribute, BusinessLogic", 所以需要typeConverter将其转换成Type。

      <interception>
        <policy name="mypolicy">
          <callHandler name="myHandler1" type="BusinessLogic.MyDBHandler, BusinessLogic"></callHandler>
          <matchingRule name="myrule" type="CustomAttributeMatchingRule">
            <constructor>
              <param name="attributeType" type="System.Type, mscorlib">
                <value value="BusinessLogic.MyDBHandlerAttribute, BusinessLogic" typeConverter="BusinessLogic.GetTypeConverter, BusinessLogic" />
              </param>
              <param name="inherited" type="bool">
                <value value="true" />
              </param>
            </constructor>
          </matchingRule>
        </policy>
      </interception>

代码5, 相应地在类型注册当中也加入拦截器和policyinjection的设定。这里用的是InterfaceInterceptor。如下:

      <register type="BusinessLogic.IBLLUserForm, BusinessLogic" mapTo="BusinessLogic.BLLUserForm, BusinessLogic">
        <interceptor name="myinterceptor" type="InterfaceInterceptor" isDefaultForType="true" />
        <policyInjection />
      </register>
      <register type="BusinessLogic.IBLLUserMenu, BusinessLogic" mapTo="BusinessLogic.BLLUserMenu, BusinessLogic">
        <interceptor name="myinterceptor" type="InterfaceInterceptor" isDefaultForType="true" />
        <policyInjection />
      </register>

关于数据库的事务,如果你的数据库任务相对比较简单(比如仅CRUD),数据库事务size比较小,可以用System.Transactions.TransactionScope,那么可以下面的一段代码实现超简单aop方式的事务管理:

代码6, 这是替换代码1的一个片段:

                using (TransactionScope ts = new TransactionScope())
                {
                    var retvalue = getNext().Invoke(input, getNext);
                    if (retvalue.Exception != null)
                    {
                        SysLog.GetInstance().LogError(retvalue.Exception);
                    }
                    else
                    {
                        ts.Complete();
                    }
                    return retvalue
                }

var retvalue = getNext().Invoke(input, getNext);这句是调用被拦截的方法。即我们的商业方法。我们可以在拦截之前,即此语句之前做一些logging的工作,还可以在此语句之后做一些logging的工作。视具体要求而定。有了Exception处理,和相应的logging,还有数据库事务的处理。那么商务逻辑的类和相应的数据库访问的类就变得相对简单了。原来需要显式地创建事务对象,现在不需要了,现在的商务方法默认就是打开了事务管理的。在商务方法里的所有数据库操作都会被看成是同一个数据库事务。在商务方法结束以后会自动进行数据库事务的提交。

三层代码

代码7 抽象接口的代码,其引用了自定义的attribute "MyDBHandler",这个attribute会带来aop方式的Exception, logging, 和事务处理。

using System;
namespace BusinessLogic
{
    [MyDBHandler]
    public interface IBLLUserMenu
    {
        int AddUserMenu(DataEntity.UserMenu usermenu);
        int DeleteUserMenu(DataEntity.UserMenu usermenu);
        DataEntity.UserMenu FindAUserMenu(DataEntity.UserMenu usermenu);
        System.Collections.Generic.List<DataEntity.UserMenu> GetAllUserMenu();
        int SelectCountUserMenu();
        int SelectCountWhereClauseUserMenu(DataEntity.UserMenu usermenu);
        System.Collections.Generic.List<DataEntity.UserMenu> SelectGroupByPrimaryKeyUserMenu();
        System.Collections.Generic.List<DataEntity.UserMenu> SelectMenusByApplicationID(DataEntity.UserMenu usermenu);
        System.Collections.Generic.List<DataEntity.UserMenu> SelectOrderByPrimaryKeyUserMenu();
        System.Collections.Generic.List<DataEntity.UserMenu> SelectTopUserMenu();
        int UpdateUserMenu(DataEntity.UserMenu usermenu);
        object CONNECTION { get; set; }
        DataEntity.UserMenu USERMENU { get; set; }
        System.Collections.Generic.List<DataEntity.UserMenu> USERMENU_LIST { get; set; }
    }
}

代码8 商务类及其方法, 经过aop处理之后,每一个方法都有Exception的处理, logging, 和事务控制。

using System;
using System.Collections.Generic;
using System.Data;
using DataEntity;
using DataAccess;
using DataAccessCommon;
using CommonUtil;

namespace BusinessLogic
{
    internal class BLLUserMenu : BusinessLogic.IBLLUserMenu
    {
        private readonly DataAccess.DALUserMenu dal = new DataAccess.DALUserMenu();
        private object conn = null;
        private UserMenu usermenu;
        private List<UserMenu> usermenus;

        public object CONNECTION
        {
            get
            {
                return conn;
            }
            set
            {
                conn = value;
            }
        }

        public UserMenu USERMENU
        {
            get
            {
                return usermenu;
            }
            set
            {
                usermenu = value;
            }
        }

        public List<UserMenu> USERMENU_LIST
        {
            get
            {
                return usermenus;
            }
            set
            {
                usermenus = value;
            }
        }

        #region business logic method

        public int DeleteUserMenu(UserMenu usermenu)
        {
            return dal.DeleteUserMenu(conn,usermenu);
        }

        public int UpdateUserMenu(UserMenu usermenu)
        {
            return dal.UpdateUserMenu(conn,usermenu);
        }

        public int AddUserMenu(UserMenu usermenu)
        {
            return dal.AddUserMenu(conn,usermenu);
        }

        public List<UserMenu> GetAllUserMenu()
        {
            return dal.GetAllUserMenu(conn);
        }

        public UserMenu FindAUserMenu(UserMenu usermenu)
        {
            return dal.FindAUserMenu(conn,usermenu);
        }

        public System.Int32 SelectCountUserMenu()
        {
            return dal.SelectCountUserMenu(conn);
        }

        public System.Int32 SelectCountWhereClauseUserMenu(UserMenu usermenu)
        {
            return dal.SelectCountWhereClauseUserMenu(conn,usermenu);
        }

        public List<UserMenu> SelectTopUserMenu()
        {
            return dal.SelectTopUserMenu(conn);
        }

        public List<UserMenu> SelectOrderByPrimaryKeyUserMenu()
        {
            return dal.SelectOrderByPrimaryKeyUserMenu(conn);
        }

        public List<UserMenu> SelectGroupByPrimaryKeyUserMenu()
        {
            return dal.SelectGroupByPrimaryKeyUserMenu(conn);
        }

        public List<UserMenu> SelectMenusByApplicationID(UserMenu usermenu)
        {
            return dal.SelectMenusByApplicationID(conn, usermenu);
        }
        #endregion
    }
}

代码9 有多个数据库操作的商务方法, 上面的商务类及其方法是比较简单的,所以一个商务方法里只有一个数据库操作. 很多情况下是有多个的,甚至是比较复杂的。如下面的例子:

        public bool MoveUpItem(UserMenuItem usermenuitem)
        {
            usermenuitem = dal.FindAUserMenuItem(conn, usermenuitem);
            UserMenuItem previousMenuItem = dal.SelectPreviousMenuItem(conn, usermenuitem);
            int iTempOrdinal = usermenuitem.ORDINAL;
            usermenuitem.ORDINAL = previousMenuItem.ORDINAL;
            previousMenuItem.ORDINAL = iTempOrdinal;
            dal.UpdateUserMenuItem(conn, usermenuitem);
            dal.UpdateUserMenuItem(conn, previousMenuItem);
            return true;
        }

        public bool MoveDownItem(UserMenuItem usermenuitem)
        {
            usermenuitem = dal.FindAUserMenuItem(conn, usermenuitem);
            UserMenuItem nextMenuItem = dal.SelectNextMenuItem(conn, usermenuitem);
            int iTempOrdinal = usermenuitem.ORDINAL;
            usermenuitem.ORDINAL = nextMenuItem.ORDINAL;
            nextMenuItem.ORDINAL = iTempOrdinal;
            dal.UpdateUserMenuItem(conn, usermenuitem);
            dal.UpdateUserMenuItem(conn, nextMenuItem);
            return true;
        }

代码10, 数据访问的代码, 基本都是这个模式, 构造参数,CRUD的sql语句,然后调用db helper执行。这些数据访问的方法返回类型是这几种:int, 单个商务实体,商务实体的列表,bool. int 通常表示影响到的记录数,也可以是某个整形字段的值, 单个商务实体代表数据库里一条记录。商务实体的列表代表数据库里多个符合条件的记录。这些都转换成了商务实体类。

using System;
using System.Collections.Generic;
using System.Data;
using DataEntity;
using DataAccessCommon;

namespace DataAccess
{
    public class DALUserForm
    {
        #region data access methods

        public int DeleteUserForm(Object conn, UserForm userform)
        {
            List<MyStaticDBHelper.MyDBParameter> paras = new List<MyStaticDBHelper.MyDBParameter> {
                new MyStaticDBHelper.MyDBParameter("@FormID", DbType.Int32, userform.FORMID)
            };

            string strSQL = "DELETE FROM [UserForm]   WHERE   [FormID] = @FormID";

            int result = 0;
            result = MyStaticDBHelper.ExecuteNonQuery(conn, System.Data.CommandType.Text, strSQL, paras);
            return result;

        }

        public int UpdateUserForm(Object conn, UserForm userform)
        {
            List<MyStaticDBHelper.MyDBParameter> paras = new List<MyStaticDBHelper.MyDBParameter> {
                new MyStaticDBHelper.MyDBParameter("@FormName", DbType.String, userform.FORMNAME),
                new MyStaticDBHelper.MyDBParameter("@TableID", DbType.Int32, userform.TABLEID),
                new MyStaticDBHelper.MyDBParameter("@SingleOrList", DbType.Boolean, userform.SINGLEORLIST),
                new MyStaticDBHelper.MyDBParameter("@WithCRUD", DbType.Boolean, userform.WITHCRUD),
                new MyStaticDBHelper.MyDBParameter("@ApplicationID", DbType.Int32, userform.APPLICATIONID),
                new MyStaticDBHelper.MyDBParameter("@FormID", DbType.Int32, userform.FORMID)
            };

            string strSQL = "UPDATE [UserForm] SET   [FormName] = @FormName,  [TableID] = @TableID,  [SingleOrList] = @SingleOrList,  [WithCRUD] = @WithCRUD,  [ApplicationID] = @ApplicationID  WHERE   [FormID] = @FormID";

            int result = 0;
            result = MyStaticDBHelper.ExecuteNonQuery(conn, System.Data.CommandType.Text, strSQL, paras);
            return result;

        }

        public int AddUserForm(Object conn, UserForm userform)
        {
            List<MyStaticDBHelper.MyDBParameter> paras = new List<MyStaticDBHelper.MyDBParameter> {
                new MyStaticDBHelper.MyDBParameter("@FormName", DbType.String, userform.FORMNAME),
                new MyStaticDBHelper.MyDBParameter("@TableID", DbType.Int32, userform.TABLEID),
                new MyStaticDBHelper.MyDBParameter("@SingleOrList", DbType.Boolean, userform.SINGLEORLIST),
                new MyStaticDBHelper.MyDBParameter("@WithCRUD", DbType.Boolean, userform.WITHCRUD),
                new MyStaticDBHelper.MyDBParameter("@ApplicationID", DbType.Int32, userform.APPLICATIONID),
                new MyStaticDBHelper.MyDBParameter("@FormID", DbType.Int32, userform.FORMID)
            };

            string strSQL = "INSERT INTO [UserForm] (  [FormName] ,  [TableID] ,  [SingleOrList] ,  [WithCRUD] ,  [ApplicationID]  ) VALUES( @FormName, @TableID, @SingleOrList, @WithCRUD, @ApplicationID );  SELECT SCOPE_IDENTITY() as [FormID]";

            int result = 0;
            DataSet ds = null;
            ds = MyStaticDBHelper.ExecuteDataset(conn, System.Data.CommandType.Text, strSQL, paras);
            if (ds.Tables.Count > 0 && ds.Tables[0].Rows.Count > 0){
                userform.FORMID = Convert.ToInt32(ds.Tables[0].Rows[0][0]);
                result = 1;
            }
            return result;

        }

        public List<UserForm> GetAllUserForm(Object conn)
        {

            string strSQL = "SELECT * FROM [UserForm] ";

            DataSet ds = null;
            ds = MyStaticDBHelper.ExecuteDataset(conn, System.Data.CommandType.Text, strSQL);

            return DataMapper.MapDataTableToObjectList<UserForm>(ds.Tables[0]);

        }

        public UserForm FindAUserForm(Object conn, UserForm userform)
        {
            List<MyStaticDBHelper.MyDBParameter> paras = new List<MyStaticDBHelper.MyDBParameter> {
                new MyStaticDBHelper.MyDBParameter("@FormID", DbType.Int32, userform.FORMID)
            };

            string strSQL = "SELECT * FROM [UserForm]   WHERE   [FormID] = @FormID";

            DataSet ds = null;
            ds = MyStaticDBHelper.ExecuteDataset(conn, System.Data.CommandType.Text, strSQL, paras);

            return DataMapper.MapDataTableToSingleRow<UserForm>(ds.Tables[0]);

        }
        //省略了大部分
#endregion
    }
}

代码11  商务实体类的代码

using System;
using System.Collections.Generic;

namespace DataEntity
{
    public class UserMenu
    {
        #region private members
        private int _iMenuID;
        private string _strMenuName;
        private int _iApplicationID;
        private int _iMenuStyle;
        private int _iScheme;
        #endregion

        #region Properties
        public int MENUID
        {
            get
            {
                return _iMenuID;
            }
            set
            {
                _iMenuID = value;
            }
        }
        public string MENUNAME
        {
            get
            {
                return _strMenuName;
            }
            set
            {
                _strMenuName = value;
            }
        }
        public int APPLICATIONID
        {
            get
            {
                return _iApplicationID;
            }
            set
            {
                _iApplicationID = value;
            }
        }
        public int MENUSTYLE
        {
            get
            {
                return _iMenuStyle;
            }
            set
            {
                _iMenuStyle = value;
            }
        }
        public int SCHEME
        {
            get
            {
                return _iScheme;
            }
            set
            {
                _iScheme = value;
            }
        }
        #endregion
    }
}

如果不用TransactionScope

严格的说,TransactionScope有些局限性。人们已经发现不少的TransactionScope的局限(baidu, google搜搜就有好多)。不管是否分布式事务,只要是规模比较大,复杂度比较高,最好都不要用TransactionScope。数据库事务规模小,复杂度低,用TransactionScope还是不错的。一旦规模变大,复杂度变高,TransactionScope带来的问题会很棘手。最后就只有弃用TransactionScope。问题也来了,不用TransactionScope那用什么呢。TransactionScope还是带来编程的一些方便,写一个using子句就可以了,它可以管理非分布式数据库事务,也可以管理分布式数据库事务。大家可以去看园友artech的一篇文章: http://www.cnblogs.com/artech/archive/2012/01/05/custom-transaction-scope.html, 他们提出来一个类似于TransactionScope用法的类。不过他们提出的类暂时不支持分布式事务。如果是非分布式的,那么可以借用。另外需要说的是artech在这篇文章里贴的代码证明一例TransactionScope的问题。当插入记录到了100000条,一次性提交事务,TransactionScope居然挂了。这还只是单数据库,不知道更复杂的,更大的会如何。希望大家集思广益,早点找出一个完美代替TransactionScope的解决方案。

文章来源:asp.net mvc应用架构的思考--Unity的应用及三层代码

时间: 2024-11-05 12:09:23

asp.net mvc应用架构的思考--Unity的应用及三层代码的相关文章

全面解析ASP.NET MVC模块化架构方案

什么叫架构?揭开架构神秘的面纱,无非就是:分层+模块化.任意复杂的架构,你也会发现架构师也就做了这两件事. 本文将会全面的介绍我们团队在模块化设计方面取得的经验.之所以加了“全面”二字,是因为本文的内容将会涉及到:数据库.路由.C#.JavaScript.CSS.HTML等一个完整模块所需要的内容. 在阅读本文之前后,你也可以转到我们的开源项目:https://github.com/leotsai/mvcsolution.这个开源项目完整的总结了我们团队在ASP.NET MVC领域的分层架构思想

Asp.net mvc项目架构分享系列之架构搭建初步

copy to:http://www.cnblogs.com/ben121011/p/5014795.html 项目架构各部分解析 Core Models IDAL MSSQLDAL IBLL BLL WebHelper Web AdminLogic 5.项目架构初步搭建 1)      创建一个空白解决方案 2)     添加解决方案文件夹,初步分层UI.Service.Repository.Infrastructure 3)     创建项目(除Web项目外,其他均创建为类库项目) a)  

asp.net mvc 项目架构解析

请先看框架图: 从上图可知: 1.Controller控制器只是充当了管道的作用.只做任务的分发,不做请求中的具体业务处理. 2.Views视图充当了展示数据的作用.不做任何取数逻辑的处理,只是展示逻辑的处理. 3.Model实体包括了BLL.DAL.Model(Entity).API层. 4.BLL层为业务逻辑层. 5.请求的整个过程:BLL层接收Controller控制器的指令,处理具体的业务处理,如果需要数据库操作,则调用DAL层和Model(Entity):处理完后将数据返回给控制器,控

《ASP.NET MVC 5 框架揭秘》

<ASP.NET MVC 5 框架揭秘> 基本信息 作者: 蒋金楠 出版社:电子工业出版社 ISBN:9787121237812 上架时间:2014-8-1 出版日期:2014 年8月 开本:16开 页码:656 版次:1-1 所属分类:计算机 > 软件与程序设计 > .NET > ASP.NET 更多关于>>> <ASP.NET MVC 5 框架揭秘>   编辑推荐 如果你觉得自己对ASP.NET MVC 所知甚少,可利用本书来系统学习:如果你

Asp.Net Mvc通用后台管理系统,bootstrap+easyui+权限管理+ORM

产品清单: 1.整站源码,非编译版,方便进行业务的二次开发 2.通用模块与用户等基础数据的数据库脚本 3.bootstrap3.3.1 AceAdmin模板源码 4.easyui1.3.5源码 5.FCKEditor和Findor源码 6.ORM代码生成器一套,附源码,可进行个人习惯进行二次开发 7.本系统用了大量easyui的树形懒加载和动态查询示例,非常方便进行学习和企业开发 8.log4net 9.异常日志查看页面 产品功能清单: 后台页面自适应,兼容所有主流浏览器 多语言接口支持 系统配

ASP.NET MVC 4 中 Controller 与 ApiController 做读取、新增、更新、删除 ( CRUD )

在 ASP.NET MVC 4 架构上,WebApi ( ApiController ) 较适合做数据处理与提供的动作,而 MVC 4 Web ( Controller ) 内比较要配合 View 层数据显示而做异动,这时候如果要把 ApiController 和 Controller 切开来,那这两个部分的沟通就会很常使用了.如果你是用 MVVM 的架构,在 Model-View View-Model 这两段,若是一页搜集各数据表的某些资料,那在 View 那一段就必须要与 WebApi 沟通

ASP.NET MVC中的模型装配 封装方法 非常好用

我们知道在asp.net mvc中 视图可以绑定一个实体模型 然后我们三层架构中也有一个model模型 但是这两个很多时候却是不一样的对象来的 就拿微软的官方mvc例子来说明 微软的视图实体中 有loginmodel 有registermodel 等等 这些视图模型 都只是占用户实体的某几个字段而已, 那么这个时候 我们可以用下面两个方法来转换 自动赋值两个对象的 protected T AssembleInfo<T, T2>(T2 model)        {            Pro

MVC模块化架构

全面解析ASP.NET MVC模块化架构方案 什么叫架构?揭开架构神秘的面纱,无非就是:分层+模块化.任意复杂的架构,你也会发现架构师也就做了这两件事. 本文将会全面的介绍我们团队在模块化设计方面取得的经验.之所以加了“全面”二字,是因为本文的内容将会涉及到:数据库.路由.C#.JavaScript.CSS.HTML等一个完整模块所需要的内容. 在阅读本文之前后,你也可以转到我们的开源项目:https://github.com/leotsai/mvcsolution.这个开源项目完整的总结了我们

asp.net mvc 简单项目框架的搭建过程(一)对Bll层和Dal层进行充分解耦

学习asp.net 已经有近三个月的时间了,在asp.net mvc上花的时间最多,但个人真是有些菜,不得不说,asp.net mvc的水真的还是蛮深的.目前在公司实习,也见过公司几个项目的代码了.对项目的代码始终停留在一知半解的地步,能改一些简单的bug,但关于项目的来龙去脉始终云里雾里.对于asp.net mvc的架构始终看不懂.因此,照着传智博客的学习视频,学了一下简单的架构搭建.真个架构的搭建我看了将近两遍视频,才稍稍有些头绪,今天在这里记录一下,一方面加深理解,一方面如果以后忘记了,还