基于asp.net的Web开发架构探索(转)

问题由来

最近在研究适合团队开发的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("."));

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

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

转载于:https://www.cnblogs.com/aaa6818162/archive/2009/08/05/1539246.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/463357.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SkipList 以及高度的确定

转载&#xff1a;https://www.cnblogs.com/lnlvinso/p/8848883.html 结果&#xff1a;skiplist的高度是个随机值。 SkipList理解 记下自己对跳表SkipList的理解。 SkipList采用空间换时间的思想&#xff0c;通过增加数据间的链接&#xff0c;达到加快查找速度的目的。 数据库L…

IIS AppCreate子目录的错误(0x80020006)

这几天做了升级用的安装包,需要在原来的ASP 的虚拟目录下&#xff0c;再创建一个新的ASPNet 虚拟目录。上网查了C# iis设定的资料&#xff0c;按照上面一路做下来&#xff0c;还是无法成功过。 代码只有两行&#xff0c;如下&#xff1a;DirectoryEntry siteVDir new Director…

网络通信TCP协议三次握手

刚刚看linux公社看见里面一个讲TCP的文章&#xff0c;文章讲的很有意思生动形象&#xff0c;很有助于对TCP协议的理解和掌握&#xff0c;所以转载过来方便以后看一下HAHA~~~TCP是什么? TCP(Transmission Control Protocol 传输控制协议)是一种面向连接(连接导向)的、可靠的、 …

Android入门逆引手册 - 12 评分条(RatingBar)的使用

这里介绍评分条android.widget.RatingBar类的使用。 ● 评分&#xff08;星&#xff09;的最大数的设置&#xff0c;调用setNumStars()方法。● 现在的评分的设置&#xff0c;调用setRating()方法。 例程源码(Java)[java]RatingBar ratingBar (RatingBar)findViewById(id.rati…

数据库事务的四大特性以及事务的隔离级别

本篇讲诉数据库中事务的四大特性&#xff08;ACID&#xff09;&#xff0c;并且将会详细地说明事务的隔离级别。 如果一个数据库声称支持事务的操作&#xff0c;那么该数据库必须要具备以下四个特性&#xff1a; ⑴ 原子性&#xff08;Atomicity&#xff09; 原子性是指事务包含…

Paypal 在线支付接口应用从零开始,第2节,[支付API原理及流程]

今天看看Paypal支付流程和简单的认证原理,我画了一张图.应该能表达这两点意思了我们的站点名字,为了好理解,暂且就定为西狐的网站吧.点此查看清晰原图恩,理论知识很重要哈,先把这图理解了,下一步我们编程使用沙盒测试就很简单了.如果想更多研究一下还可直接查看Paypal官方提供的…

PLSQL DEVELOPER 使用技巧

为什么80%的码农都做不了架构师&#xff1f;>>> 1、右键菜单 在PL/SQL Developer&#xff08;下面简称PLD&#xff09;中的每一个文本编辑窗口&#xff0c;如SQL Window&#xff0c;Command Window和Porgram Window&#xff0c;右键点击某个对象名称&#xff0c;会…

Android Drawable绘图学习笔记

如何获取 res 中的资源 数据包package&#xff1a;android.content.res 主要类&#xff1a;ResourcesAndroid SDK中的简介&#xff1a;Class for accessing an application’s resources.Class for accessing an application’s resources. This sits on top of the asset mana…

C#.NET中的事件2

/** Created by SharpDevelop. * User: noo * Date: 2009-8-17 * Time: 15:34 * * 事件2 */usingSystem ;usingSystem .Windows .Forms ;classTest { staticvoidMain()//入口函数{ Form frmnewForm ();//新建一窗体frm.Text "我的窗体"; …

HTML学习之基础

HTML是网页的标记语言不是编程语言&#xff0c;有一些标记段组成。大小写不敏感&#xff0c;可以用常用的编辑器软件编写用浏览器打开即可 有不同的版本<!DOCTYPE html> <meta charset"utf-8">在<title>前为了能正常显示中文。 超链接&#xff1a;…

Varint

什么是Varint Varint 是一种紧凑的表示数字的方法。它用一个或多个字节来表示一个数字&#xff0c;值越小的数字使用越少的字节数。这能减少用来表示数字的字节数。 比如对于 int32 类型的数字&#xff0c;一般需要 4 个 byte 来表示。但是采用 Varint&#xff0c;对于很小的 …

Ubuntu 17.10安装Qt 5.10环境与Qt Creator 4.5开发工具(转自linux公社)

记录下在Ubuntu 17.10搭建Qt环境与安装Qt Creator开发工具的过程。机器装的Linux是Ubuntu 17.10&#xff0c;16.04与17.04的应该也相同。Qt 5.10和Qt 3D Studio发布 http://www.linuxidc.com/Linux/2017-12/149267.htm 1&#xff0c;Qt安装 1.1 下载Qt 这里提供Qt Creator的下…

C#基础(201)--常量枚举

本文知识点&#xff1a; 1.掌握常量的定义和使用方法 2.理解枚举的作用和特点 3.掌握枚举的使用方法 1.1.常量的定义语法 const 数据类型 常量名称 值&#xff1b; 1.2.常见错误 1.3常量的使用时机 经常使用并且值不变的变量&#xff0c;可以定义为常量 2.1枚举的作用及其…

unbuntu使用经典界面

为什么80%的码农都做不了架构师&#xff1f;>>> 昨天升级到UBUNTU 11.04, 发现新的Unity界面很不适应&#xff0c;于是将其恢复到旧式经典界面&#xff0c;具体操作模式方法如下&#xff1a; 在已经登录的状态下&#xff0c;选择 [注销]然后在重新登录的时候&#…

c++入门基础知识

命名空间刚开始接触c&#xff0c;我们会发现与C语言相比不光头文件有所不同&#xff0c;还会发现using namespce std&#xff1b;这句话&#xff0c;其实这就是c的命名空间。 (1) 概念命名空间是为了防止名字冲突提供更加可控的机制。命名空间分割了全局命名空间&#xff0c;其…

读书笔记之《得未曾有》

作者 安妮宝贝&#xff0c;2014年笔名改为“庆山” 感想 第一次读庆山的作品&#xff0c;可以书名来总结的一下&#xff0c;得未曾有——获得了一种未曾有过得感受。 一、感受作者 高晓松老师的节目里说过一句话&#xff0c;写作需要长时间的观察人性、需要极强的观察能力。庆山…

linux驱动简单介绍

linux驱动简单介绍 驱动基本介绍 驱动。顾名思义就是“驱使硬件设备行动”。设备驱动与底层硬件之间打交道&#xff0c;按照硬件设备的具体操作方式来读写设备寄存器&#xff0c;最终完成一系列操作。 设备 驱动充当了应用程序和应用软件直接的纽带&#xff0c;它使得应用软件只…

C语言 scanf()和gets()函数的区别

C语言 scanf()和gets()函数的区别 1.相同点&#xff1a;scanf( )函数和gets( )函数都可用于输入字符串 2.不同点&#xff1a;两者在功能上有所区别,具体区别如下&#xff1a; 要实现如下需求“从控制台输入字符串”有如下两种实现方式&#xff1a; 1>使用gets()函数实现使用…

Uoj 441 保卫王国

Uoj 441 保卫王国 动态 \(dp\) .今天才来写这个题.设 \(f[u][0/1]\) 表示子树 \(u\) 中不选/选 \(u\) 时的最小权值和,显然有:\(f[u][0]\sum f[v][1] ,f[u][1]w[u]\sum \min(f[v][0],f[v][1])​\) .现在要资瓷修改 \(x\) 的点权 \(w[x]\) ,容易发现修改后只会影响 \(x\) 到根节…

行存和列存的区别

写入&#xff1a; 行存储的写入是一次完成&#xff0c;数据的完整性因此可以确定。 列存储需要把一行记录拆分成单列保存&#xff0c;写入次数明显比行存储多。 行存储在写入上占有很大的优势 数据修改&#xff1a; 行存储是在指定位置写入一次&#xff0c;列存储是将磁盘定位…