惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Announcements
Recent Announcements
IT之家
IT之家
Google DeepMind News
Google DeepMind News
罗磊的独立博客
爱范儿
爱范儿
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
U
Unit 42
MongoDB | Blog
MongoDB | Blog
S
SegmentFault 最新的问题
B
Blog
博客园 - 叶小钗
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
C
Check Point Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - RedSoft

需求分析——你好,我好,大家好! PHP问题列表(持续更新) [收藏]mysql 性能的检查和调优方法 【收藏】hibernate 集合映射inverse和cascade详解 个人网站开通。 【原】轻量级的数据交换格式——初识Json(下) 【原】轻量级的数据交换格式——初识Json(上) 【原】初学Jquery 【原】初学Flex之简单图片查看器 JavaScript使用技巧精萃 WinForm UI设计与开发思路(转) C#编程风格约定 C#常用正则表达式 将目录下的图片文件写成一个二进制大文件 写了个MVC/多层的Demo…… EnableViewState,与TextBOx控件状态改变的关系 文本框+层模拟下拉框,并实现输入自动提示和过滤 软件史上最伟大的十大程序员(图文) sql 常用语句积累
【原】基于asp.net的Web开发架构探索
RedSoft · 2009-08-04 · via 博客园 - RedSoft

问题由来

最近在研究适合团队开发的web架构解决方案,该架构即要适合分工协作又要有一定扩展性,适合不同的数据库需要,因此我查阅了一些资料,初步构想出了一套架构,请各位多多指教。

探索

web开发架构最经典莫过于三层架构,表示层、逻辑层、数据处理层。

数据访问层:其功能主要是负责数据库的访问。

业务逻辑层:是整个系统的核心,它与这个系统的业务(领域)有关。

表示层:是系统的UI部分,负责使用者与整个系统的交互。理想的状态是表示层不应包括系统的业务逻辑。

这些是经典的解释,如果要适合不同的数据库则需要加入工厂模式,里面用面向接口的方式进行多态调用。是不是这有点像petshop了。所以架构的初步设想是这样:

clip_image001

下面以获取用户信息为例,简述这个架构的流程:(以下为类似petshop的经典做法,了解的可以略过)

step 1 、首先我们应该建立项目所需的实体模型,在这里新建用户信息的实体模式,UserInfo.cs。该类保存在Model项目里。

step 2 、我们再将项目的单元功能写到相关的接口中,这里以获取用户信息功能为例。在IDAL项目里新建IUser接口。

        //根据用户ID获取用户信息
        UserInfo GetUserById(int userId);

step 3、完成了接口,我们就要实现它,现在我们用sqlserver、oracle两种数据库访问方式来实现它。以下是SqlserverDAL中User类对接口的现实:

public class User:IUser
    {

       
        public UserInfo GetUserById(int userId)
        {
         //实现操作           

        }

    }

OracleDAL中现实方式类似。。。。

step 4、在此数据库访问层应该就基本写好了,下面应该给逻辑层调用了,但是两种实现方式怎么调用呢,或者说怎么有选择的调用它呢,petshop是这样处理的,在DALFactory中的DataAccess类,利用反射载入程序集从而实例化所需要的类:


        private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];
        public static IUser CreateUser()
        {  

            string className = path + ".User";
            return (IUser)Assembly.Load(path).CreateInstance(className);

        }

至于要选择哪个数据库访问层,在配置文件里配置一下WebDAL。如:<add key="WebDAL" value="SQLServerDAL"/>。

这样就基本解决了逻辑层和数据访问层的耦合。

step 5、下面就该写逻辑层了,在BLL里面创建User.cs类。大致如下:

public class User
   {
       private static readonly IUser dal = DALFactory.DataAccess.CreateUser();

       public UserInfo GetUserInfo(int userId) {
            return dal.GetUserById(userId);
        }

   }

是不是觉得BLL毫无意义,因为它只是对数据访问层方法的简单调用,但并不是这样的,这里只有一个简单的事例,在实际项目中一个BLL里面处理的可能是一个非常复杂的逻辑,而这个复杂逻辑的结果才提供给表示层显示。

step 6、最后是表示层,好像没什么可说的,把从BLL取出来的数据绑定到你的页面就行了。

以上是仿petshop的架构设计,看起来没什么质疑的地方,毕竟是微软的经典案例。你可能抱怨的地方有两点,一是层是不是有点多,关系过于复杂;二如果我需要改变或增加一个数据库字段,那不是会很痛苦,因为要节联修改。这两个问题,我都没办法解决,一如果说过于层过于多而繁琐,那么下面我写的好像更为复杂,原谅。。。。二、鄙人觉得凡是分层开发,只要以数据库字段为依据的建立实体模型,都会存在节联修改的问题。除非全部用DataTable,那么在BLL、表示层调用的时候并不知道DataTable到底装有什么,这样无疑更加了调用的不便利。关于减少节联修改的问题,如有解决方法的请指教。

对以上架构的修改

我重点分析了以上架构的数据访问工厂的设计部分,即DALFactory中的DataAccess类。在此类中,实现了对不同数据库访问层的调用

。但如果现在有一个项目,里面有sqlserver又有oracle的现实,我们是不是要这样做:

private static readonly string path = ConfigurationManager.AppSettings["WebDAL"];//对sqlserver数据库访问层的调用

private static readonly string path2 = ConfigurationManager.AppSettings["WebDAL2"];//对oracel数据库访问层的调用

        public static IUser CreateUser()
        {  

            string className = path + ".User";
            return (IUser)Assembly.Load(path).CreateInstance(className);

        }

        public static IOrder CreateOrder()
        {  

            string className = path2 + ".Order";
            return (IUser)Assembly.Load(path2).CreateInstance(className);

        }

如果要创建其他的访问类,我们还要写CreateProduct(),CreateArticle,CreateMenu。。。。。那么这样的类会很繁琐,我们能不能

只做一个方法,其他的工作只需要开发人员通过配置文件来完成呢。我的解决方案有两个:

一、Spring.net

这个东西就是专门用来解耦合的,我们将它的相关程序集加载到DALFactory中,于是在DataAccess中,我们可以做:

private static readonly string configPath = HttpContext.Current.Request.PhysicalApplicationPath +

ConfigurationManager.AppSettings["objectconfig"];//这是spring.net的对象配置文件在服务器上的物理位置
        public static T CreateObject<T>()
        {

            IResource rs = new FileSystemResource(configPath);
            IObjectFactory factory = new XmlObjectFactory(rs);
            string id = typeof(T).FullName;
            return (T)factory.GetObject(id);

}

这里我们传入一个泛型,让spring.net在它的对象配置文件里面找到该类型的程序集并加载,创建出对应的对象。objectconfig文件

大致如下:

<?xml version="1.0" encoding="utf-8" ?>
<objects xmlns="http://www.springframework.net"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.net
http://www.springframework.net/xsd/spring-objects.xsd">

<object id="IDAL.IUser" type="SQLServerDAL.Function"></object>

</objects>

这样在BLL 就这样调用

private static readonly IUser dal = EtourAF.Shared.DALFactory.DataAccess.CreateObject<IUser>();

这样开发人员如果要加入一个对象就在object-config中加一段相关配置就行了。嘿嘿,这就变成了petshop+spring.net了,YY无极限。。。。

二、也是用反射

这里我们只是用了一个键值对的方式,照例在配置文件里配置相应的接口和对象,只是我们把他配置到了web.config当中:

<add key="IDAL.IUser" value="SQLServerDAL.Function" />

在DataAccess中,我们就这样写:

public static T CreateObject<T>()
        {
            string interfaceFullName = typeof(T).FullName;
            string className = ConfigurationManager.AppSettings[interfaceFullName];
            string nameSpace = className.Substring(0, className.LastIndexOf("."));
            return (T)Assembly.Load(nameSpace).CreateInstance(className);
        }

可能有人说

string nameSpace = className.Substring(0, className.LastIndexOf("."));

这里这个截取是不是觉得有点硬,我现在也只想到这个办法,但绝对不会有问题的。

好了,这些大概就是鄙人这两天的有些收获,请指教。