3层架构 - 需要一个例子

时间:2010-01-06 08:33:10

标签: asp.net architecture

目前我正在使用单层架构。现在我想学习如何使用3层架构编写代码。请问您能给我一个简单的例子吗?

9 个答案:

答案 0 :(得分:22)

维基百科有一个很好的解释:Multitier architecture

  

'三层'是一种客户端 - 服务器架构,其中用户界面,功能处理逻辑(“业务规则”),计算机数据存储和数据访问是作为独立模块开发和维护的,通常在不同的平台上。

alt text

  

网站开发使用

     

在网站开发领域,三层通常用于指代使用三层构建的网站,通常是电子商务网站:

     
    
        
  • 提供静态内容的前端Web服务器,可能还有一些缓存的动态内容。
  •     
  • 中间动态内容处理和生成级应用服务器,例如Java EE,ASP.net,PHP平台。
  •     
  • 后端数据库,包括数据集和数据库管理系统或RDBMS软件,用于管理和提供对数据的访问。
  •     
  

答案 1 :(得分:15)

这就是我项目中的内容。不仅仅是传统的3层架构。

1。) Application.Infrastructure

  • 所有业务对象,业务对象集合,数据访问类和我的自定义属性和实用程序的基类,作为扩展方法,通用验证框架。这决定了我最终的.net应用程序的整体行为组织。

2。) Application.DataModel

  • 数据库的类型化数据集。
  • TableAdapters扩展到包含我可能需要的交易和其他功能。

3。) Application.DataAccess

  • 数据访问类。
  • 使用基础类型化数据集查询数据库操作的实际位置。

4。) Application.DomainObjects

  • 业务对象和业务对象集合。
  • 枚举。

5.。 Application.BusinessLayer

  • 提供可从Presentation层访问的经理类。
  • HttpHandlers的。
  • 我自己的页面基类。
  • 更多的事情在这里..

6。) Application.WebClient Application.WindowsClient

  • 我的演示文稿图层
  • 从Application.BusinessLayer和Application.BusinessObjects。
  • 获取引用

Application.BusinessObjects在整个应用程序中使用,并且每当需要时它们都会遍历所有层[Application.DataModel和Application.Infrastructure]

我的所有查询都只定义了Application.DataModel。

Application.DataAccess返回或接受Business对象作为任何数据访问操作的一部分。业务对象是在反射属性的帮助下创建的。每个业务对象都标记有一个属性映射到数据库中的目标表,业务对象中的属性使用映射到相应数据库表中的目标列的属性进行标记。

我的验证框架允许我在指定的ValidationAttribute的帮助下验证每个字段。

我的framrwork大量使用Attributes来自动化大多数繁琐的任务,如映射和验证。我还可以将新功能作为框架中的新方面。

示例业务对象在我的应用程序中看起来像这样。

<强> User.cs

[TableMapping("Users")]
public class User : EntityBase
{
    #region Constructor(s)
    public AppUser()
    {
        BookCollection = new BookCollection();
    }
    #endregion

    #region Properties

    #region Default Properties - Direct Field Mapping using DataFieldMappingAttribute

    private System.Int32 _UserId;

    private System.String _FirstName;
    private System.String _LastName;
    private System.String _UserName;
    private System.Boolean _IsActive;

    [DataFieldMapping("UserID")]
    [DataObjectFieldAttribute(true, true, false)]
    [NotNullOrEmpty(Message = "UserID From Users Table Is Required.")]
    public override int Id
    {
        get
        {
            return _UserId;
        }
        set
        {
            _UserId = value;
        }
    }

    [DataFieldMapping("UserName")]
    [Searchable]
    [NotNullOrEmpty(Message = "Username Is Required.")]
    public string UserName
    {
        get
        {
            return _UserName;
        }
        set
        {
            _UserName = value;
        }
    }

    [DataFieldMapping("FirstName")]
    [Searchable]
    public string FirstName
    {
        get
        {
            return _FirstName;
        }
        set
        {
            _FirstName = value;
        }
    }

    [DataFieldMapping("LastName")]
    [Searchable]
    public string LastName
    {
        get
        {
            return _LastName;
        }
        set
        {
            _LastName = value;
        }
    }

    [DataFieldMapping("IsActive")]
    public bool IsActive
    {
        get
        {
            return _IsActive;
        }
        set
        {
            _IsActive = value;
        }
    }

    #region One-To-Many Mappings
    public BookCollection Books { get; set; }

    #endregion

    #region Derived Properties
    public string FullName { get { return this.FirstName + " " + this.LastName; } }

    #endregion

    #endregion

    public override bool Validate()
    {
        bool baseValid = base.Validate();
        bool localValid = Books.Validate();
        return baseValid && localValid;
    }
}

<强> BookCollection.cs

/// <summary>
/// The BookCollection class is designed to work with lists of instances of Book.
/// </summary>
public class BookCollection : EntityCollectionBase<Book>
{
    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection()
    {
    }

    /// <summary>
    /// Initializes a new instance of the BookCollection class.
    /// </summary>
    public BookCollection (IList<Book> initialList)
        : base(initialList)
    {
    }
}

答案 2 :(得分:10)

“层”是指软件堆栈中的“层”? “层”一词更适用于描述系统的物理组件。如果您使用的是ASP.NET,那么您可能已经拥有了“3层”系统 -

  1. 浏览器显示网页
  2. 托管您应用的IIS服务器
  3. 数据库服务器和您的数据库
  4. 但您可能将所有代码放入单个软件“层” - 特别是您的aspx页面的代码隐藏文件。您想要从单层移动到3层方法。经典的“3层”软件架构包括以下内容 -

    1. 表示层

    2. 业务逻辑层(BLL)

    3. 数据访问层(DAL)

    4. alt text
      (来源:asp.net

      对于典型的ASP.NET应用程序,您可以按如下方式应用它。首先,创建一个包含数据库访问对象的LINQ2SQL文件(.dbml)。这是您的数据访问层(DAL)。

      接下来,您可以创建一个DLL来包含业务逻辑层(BLL)。该层将通过DAL访问数据库,根据需要对其进行操作,然后通过简单的界面将其公开。例如,如果您的应用程序显示客户端列表,则您的BLL可能具有名为GetClientList()的公共函数,该函数返回客户端列​​表。

      最后,您将在文件后面设置代码以实例化BLL并将其连接到接口组件。这是您的表示层。例如,它可能需要从GetClientList()函数返回的数据并将其绑定到Web表单上的数据网格。我们的想法是让表示层尽可能地薄。

      这似乎有点冗长的描述,但是一旦你做了几次就很简单。您会发现将这样的应用程序分离出来会使维护更加容易,因为关注点分离会导致代码更清晰。您还会发现升级甚至更换表示层要容易得多,因为它包含非常少的智能。最后,您将获得一些可以在新应用程序中轻松使用的非常有用的BLL库,从而大大提高了工作效率。

答案 3 :(得分:4)

表示层:放置与用户界面相关的所有内容。 (用户看到的内容)

业务层:与应用程序逻辑相关的所有内容(如何处理来自表示层的信息)

数据层:提供基础数据源的抽象(存储来自/进入业务层的信息的位置和方式)

每一层应该尽可能少地了解另一层,它应该是一种自上而下的方法:

  • 数据层应该对业务和演示文稿一无所知
  • 业务层应该知道数据而不是关于表示
  • 演示应该了解业务,而不是数据

简单示例:

网站:

  • 演示文稿:所有图形内容,用户插入数据,菜单,图片等的字段
  • 业务:关于数据的所有约束(唯一名称,没有符号的名称,有效日期等),操作业务对象的方法(创建新用户,添加新订单等)
  • 数据:访问基础数据库的方法。

答案 4 :(得分:4)

3层架构根据上下文可能有不同的含义。通常,这意味着应用程序中的职责分为不同的层。通常,3层指的是:

  • 表示层“(实际用户界面)
  • 逻辑层(应用程序/业务逻辑)
  • 数据层(数据库,数据存储)

详细信息因应用程序而异。

像往常一样,维基百科有一个很好的概述:http://en.wikipedia.org/wiki/Multitier_architecture

一个简单的例子是典型的商业应用程序:

  • 演示文稿:浏览器或胖客户端
  • 逻辑层:业务逻辑,通常在应用服务器中(基于J2EE,ASP.NET或其他)
  • 数据层:数据库,通常是RDBMS,如MySQL或Oracle

答案 5 :(得分:2)

3层架构通常包含以下组件:

  1. 客户端浏览器
  2. 托管ASP.NET应用程序的Web服务器
  3. 某些后端存储,例如ASP.NET应用程序正在访问的数据库
  4. 因此,为了回答有关如何为3层体系结构编写代码的问题,您需要开发一个与数据存储通信的ASP.NET应用程序。

答案 6 :(得分:0)

一个很好的教程,完整的源代码控制下载一个编写良好的分层应用程序将在这里:

http://nerddinnerbook.s3.amazonaws.com/Intro.htm

这不是关于分层体系结构的教程,但它是一个编写良好的应用程序,可以让您深入了解为什么要考虑这种体系结构。

此外,正如上面仅简要介绍的那样,这是关于保持逻辑/存储/表示代码分离,因此如果您必须更改其中一个(例如从asp.net前端更改为桌面应用程序) ,这并不难做到。

答案 7 :(得分:0)

三层(层)是一种客户端 - 服务器架构,其中用户界面,业务流程(业务规则)以及数据存储和数据访问是作为独立模块开发和维护的,或者通常在不同的平台上。

基本上,有3层:

  • 第1层(表示层,GUI层)
  • 第2层(业务对象,业务逻辑层)
  • 第3层(数据访问层)。这些层可以单独开发和测试。

将代码划分为3层需要什么?将用户界面与业务逻辑和数据库访问分离具有许多优点。一些优点如下:

  

业务逻辑组件的可重用性导致快速   发展。假设我们有一个处理添加,更新的模块,   删除并查找系统中的客户。就像这个组件一样   开发和测试,我们可以在任何其他可能的项目中使用它   涉及维护客户。

     

系统转换很容易。既然业务逻辑是   与数据访问层分开,更改数据访问层   不会对业务逻辑模块产生太大影响。如果我们是,那就说吧   从SQL Server数据存储转移到Oracle应该没有任何   业务层组件和GUI中所需的更改   成分

     

系统的变更管理很容易。假设有一个未成年人   改变业务逻辑,我们不必安装整个   个人用户PC中的系统。例如。如果GST(税)从10%变更   到15%我们只需要更新业务逻辑组件   影响用户,没有任何停机时间。

     

具有单独的功能服务器允许并行开发   由应用专家提供的各个层级。

     

提供更灵活的资源分配。可以减少网络   通过使功能服务器将数据剥离到精确的流量   在将其发送给客户之前需要的结构。

答案 8 :(得分:0)

connection class
-----------------------

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web .UI.WebControls ;
/// <summary>
/// Summary description for conn
/// </summary>
namespace apm_conn
{
    public class conn
    {
        public SqlConnection getcon()
        {
            SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["connect"].ConnectionString );
            if (con.State == ConnectionState.Closed)
            {
                con.Open();
            }
            return con;
        }
        #region execute command
        public string  Executecommand(SqlParameter []sqlparm,string sp)
        {
            string r_val = "";
            try
            {

                SqlConnection con = new SqlConnection();
                con = getcon();
                SqlCommand cmd = new SqlCommand();
                cmd.Connection = con;
                cmd.CommandText = sp;
                cmd.CommandType = CommandType.StoredProcedure;
                foreach (SqlParameter loopvar_parm in sqlparm)
                {
                    cmd.Parameters.Add(loopvar_parm);

                }
                cmd.Parameters.Add("@Var_Output", SqlDbType.VarChar, 20).Direction = ParameterDirection.Output;
                cmd.ExecuteNonQuery();
                r_val = (string)cmd.Parameters["@Var_Output"].Value;
                con.Close();
            }
            catch { }
            return r_val;

        }

        #endregion
        #region Execute Dataset
         public DataSet ExeccuteDataset(SqlParameter[] sqlParm, string sp)
    {
        DataSet ds = new DataSet();
        try
        {
            SqlConnection con = new SqlConnection();
            con = getConn();
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = con;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandText = sp;
            foreach (SqlParameter LoopVar_param in sqlParm)
            {
                cmd.Parameters.Add(LoopVar_param);
            }
            cmd.ExecuteNonQuery();
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            da.Fill(ds);

        }
        catch
        { }
        return ds;
    }
        #endregion
        #region grid
        public void Bindgrid(DataSet ds,GridView g)
        {
            try
            {
                g.DataSource = ds.Tables[0];
                g.DataBind();

            }
            catch { }
        }
        #endregion
        #region Dropdownlist
        public void Binddropdown(DropDownList dl,DataSet ds,string text,string value)
        {
            try
            {
                dl.DataSource = ds.Tables[0];
                dl.DataTextField = text;
                dl.DataValueField = value;
                dl.DataBind();
            }
            catch
            {}

        }
        #endregion
        public conn()
        {
            //
            // TODO: Add constructor logic here
            //
        }
    }
}




dal
---------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_conn;
using System.Data.SqlClient;
using apm_ent;

/// <summary>
/// Summary description for Class1
/// </summary>
namespace apm_dal
{
    public class dal
    {
        conn ob_conn = new conn();
        public dal()
        {
            //
            // TODO: Add constructor logic here
            //
        }
        public string insert(ent obj_ent)
        {
            SqlParameter[] sqlparm =
        {
            new SqlParameter ("@Var_Action",obj_ent.Var_Action),
            new SqlParameter ("@Int_Id",obj_ent.Int_Id ),
             new SqlParameter ("@Var_Product",obj_ent.Var_Product ),
              new SqlParameter ("@Dc_Price",obj_ent.Var_Price ),
              new SqlParameter ("@Int_Stat",obj_ent.Int_Stat ),

                               };
            return ob_conn.Executecommand(sqlparm, "Proc_product");
        }
        public string ins(ent obj_ent)
        {
            SqlParameter[] parm =
        {
            new SqlParameter ("@Var_Action",obj_ent .Var_Action),
            new SqlParameter ("@Int_Id",obj_ent .Int_Id),
                            };
            return ob_conn.Executecommand(parm, "Proc_product");
        }
    }

}

bal
-------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using apm_ent;
using apm_dal;

/// <summary>
/// Summary description for bal
/// </summary>
namespace apm_Bal
{

    public class bal
    {
        dal ob_dal = new dal();
        string r_val = "";
        public bal()
        {
            //
            // TODO: Add constructor logic here
            //
        }
        public string insert(ent obj_ent)
        {
            return ob_dal.insert(obj_ent);
        }
    }
}



Ent
------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Summary description for ent
/// </summary>
namespace apm_ent
{
    public class ent
    {
        public ent()
        {
            //
            // TODO: Add constructor logic here
            //
        }
        #region Ent
        public int Int_Id { get; set; }
        public string  Var_Action { get; set; }
        public string Var_Product { get; set; }
        public decimal  Var_Price { get; set; }
        public int Int_Stat { get; set; }
        #endregion
    }
}



page code
--------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using apm_conn;
using apm_ent;
using apm_Bal;
using apm_conn;
public partial class _Default : System.Web.UI.Page
{
    conn obj_conn = new conn();
    ent obj_ent = new ent();
    bal obj_bal = new bal();
    string r_val = "";
    protected void Page_Load(object sender, EventArgs e)
    {

    }
    protected void btnsub_Click(object sender, EventArgs e)
    {
        obj_ent.Var_Action = "INS";
        obj_ent.Var_Product = txtproduct.Text;
        obj_ent.Var_Price = Convert.ToDecimal (txtprice.Text);
        r_val = obj_bal.insert(obj_ent);
        if (r_val == "1")
        {
            Response.Write("<script>alert('Inserted Sucessfully')</script>");
        }
    }
}