プレゼンテーション、ビジネス、データ層
-
03-07-2019 - |
質問
私はC#でプログラミングを始めたばかりで、アプリケーション/ウェブサイトを3つの異なるレイヤーに分割することをお勧めしましたが、それがどのようになっているかを正確に理解するのに苦労しています。私はC#についてもっと学習するためにペットプロジェクトに取り組んでいますが、悪い習慣から始めたくはありません。私が持っているものを見て、私がこれを正しくやっているかどうかを確認できますか?すべてを異なるレイヤーに分解する方法に関するヒントを提供しますか?
プレゼンテーション層
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Project: Ruth</title>
<link href="CSS/StyleSheet.css" rel="stylesheet" type="text/css" />
</head>
<body>
<form id="form1" runat="server">
<div class="Body">
<div class="Header">
<div class="Nav">
<img src="images/Header_Main.gif" alt="" width="217" height="101" />
<div class="Menu">
<a href="Default.aspx">
<img src="images/Header_Home-Off.gif" alt="" /></a>
<a href="Default.aspx">
<img src="images/Header_About-Off.gif" alt="" /></a>
<a href="Register.aspx">
<img src="images/Header_Register-Off.gif" alt="" /></a>
<a href="Default.aspx">
<img src="images/Header_Credits-Off.gif" alt="" /></a>
</div>
</div>
</div>
<div class="Content">
<div class="CurrentlyListening">
<asp:Label ID="lblCurrentListen" runat="server" Text="(Nothing Now)" CssClass="Txt"></asp:Label>
</div>
<asp:GridView ID="gvLibrary" runat="server" AutoGenerateColumns="False" DataKeyNames="lib_id" DataSourceID="sdsLibrary" EmptyDataText="There are no data records to display." Width="760" GridLines="None">
<RowStyle CssClass="RowStyle" />
<AlternatingRowStyle CssClass="AltRowStyle" />
<HeaderStyle CssClass="HeaderStyle" />
<Columns>
<asp:BoundField DataField="artist_name" HeaderText="Artist" SortExpression="artist_name" HeaderStyle-Width="200" />
<asp:BoundField DataField="album_title" HeaderText="Album" SortExpression="album_title" HeaderStyle-Width="200" />
<asp:BoundField DataField="song_title" HeaderText="Track" SortExpression="song_title" HeaderStyle-Width="200" />
<asp:TemplateField HeaderText="DL">
<ItemTemplate>
<a href="http://####/Proj_Ruth/Data/<%# Eval("file_path") %>" class="lnk">Link</a>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="sdsLibrary" runat="server" ConnectionString="<%$ ConnectionStrings:MusicLibraryConnectionString %>" DeleteCommand="DELETE FROM [Library] WHERE [lib_id] = @lib_id" InsertCommand="INSERT INTO [Library] ([artist_name], [album_title], [song_title], [file_path]) VALUES (@artist_name, @album_title, @song_title, @file_path)" ProviderName="<%$ ConnectionStrings:MusicLibraryConnectionString.ProviderName %>" SelectCommand="SELECT [lib_id], [artist_name], [album_title], [song_title], [file_path] FROM [Library] ORDER BY [artist_name], [album_title]" UpdateCommand="UPDATE [Library] SET [artist_name] = @artist_name, [album_title] = @album_title, [song_title] = @song_title, [file_path] = @file_path WHERE [lib_id] = @lib_id">
<DeleteParameters>
<asp:Parameter Name="lib_id" Type="Int32" />
</DeleteParameters>
<InsertParameters>
<asp:Parameter Name="artist_name" Type="String" />
<asp:Parameter Name="album_title" Type="String" />
<asp:Parameter Name="song_title" Type="String" />
<asp:Parameter Name="file_path" Type="String" />
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="artist_name" Type="String" />
<asp:Parameter Name="album_title" Type="String" />
<asp:Parameter Name="song_title" Type="String" />
<asp:Parameter Name="file_path" Type="String" />
<asp:Parameter Name="lib_id" Type="Int32" />
</UpdateParameters>
</asp:SqlDataSource>
</div>
</div>
</form>
</body>
</html>
ビジネスレイヤー
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
public class User
{
DA da = new DA();
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string Password { get; set; }
public string AccessCode { get; set; }
public User(string firstName, string lastName, string emailAddress, string password, string accessCode)
{
FirstName = firstName;
LastName = lastName;
EmailAddress = emailAddress;
Password = password;
AccessCode = accessCode;
}
public void CreateUser(User newUser)
{
if (da.IsValidAccessCode(newUser.AccessCode))
{
da.CreateUser(newUser);
}
}
}
データアクセスレイヤー(DAL)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Data.SqlTypes;
using System.Data.SqlClient;
using System.Configuration;
public class DA
{
public DA()
{
}
public bool IsValidAccessCode(string accessCode)
{
bool isValid = false;
int count = 0;
using (SqlConnection sqlCnn = new SqlConnection(ConfigurationManager.ConnectionStrings["MusicLibraryConnectionString"].ConnectionString))
{
sqlCnn.Open();
using (SqlCommand sqlCmd = new SqlCommand(String.Format("SELECT COUNT(*) FROM [AccessCodes] WHERE [accessCode_accessCode] = '{0}';", accessCode), sqlCnn))
{
count = (int)sqlCmd.ExecuteScalar();
if (count == 1)
{
isValid = true;
}
}
}
return isValid;
}
public void CreateUser(User newUser)
{
using (SqlConnection sqlCnn = new SqlConnection(ConfigurationManager.ConnectionStrings["MusicLibraryConnectionString"].ConnectionString))
{
sqlCnn.Open();
using (SqlCommand sqlCmd = new SqlCommand(String.Format("INSERT INTO [Users] (user_firstName, user_lastName, user_emailAddress, user_password, user_accessCode) VALUES ('{0}', '{1}', '{2}', '{3}', '{4}');", newUser.FirstName, newUser.LastName, newUser.EmailAddress, newUser.Password, newUser.AccessCode), sqlCnn))
{
sqlCmd.ExecuteNonQuery();
}
}
DeleteAccessCode(newUser.AccessCode);
}
public void DeleteAccessCode(string accessCode)
{
using (SqlConnection sqlCnn = new SqlConnection(ConfigurationManager.ConnectionStrings["MusicLibraryConnectionString"].ConnectionString))
{
sqlCnn.Open();
using (SqlCommand sqlCmd = new SqlCommand(String.Format("DELETE FROM [AccessCodes] WHERE [accessCode_accessCode] = '{0}';", accessCode), sqlCnn))
{
sqlCmd.ExecuteNonQuery();
}
}
}
}
解決
ジョン、
最初に理解すべきことの1つは、レイヤーベースのアプリケーションを構築する場合、SQLステートメントをASPXページ内に直接保存しないことです( SqlDataSource
が必要)。 SqlDataSource
コントロールは、データベースデータを使用してアプリケーションを簡単にバインドおよび更新できることを示すために構築されたもので、BLレイヤーを持つ目的をやや損なうため、実際のアプリケーションで使用することは意図されていませんASPXページにSelect / Update / Delete / Insertステートメントを保存する場合はDatalayer。
レイヤーベースのアプリケーション設計の全体的な目的は、交差しないように各レイヤーをカプセル化することです。各レイヤーは他のレイヤーのパブリックインターフェイスと対話し、内部実装については何も知りません。
したがって、実行可能な代替手段は、 ObjectDataSource
コントロールを使用することです。このコントロールを使用すると、DataLayerまたはBizロジックレイヤーに直接バインドして、データレイヤーを呼び出すことができます。データレイヤーに直接バインドすると、データベーステーブルのスキーマを公開するデータ構造(たとえば、DataTablesやDataViews)を返すという欠点があります。
したがって、推奨されるロジックのフローは次のとおりです。
ASPXページは、DataSourceコントロールを使用してBLクラスにバインドします。
このBLクラスは、 GetData、UpdateData、DeleteData、InsertData
などの適切な関数(必要なオーバーロードを含む)を提供し、これらの関数は、 ObjectDataSource
が処理できる強く型付けされたオブジェクトまたはコレクションを返しますそして表示。
BLクラスの各パブリック関数は、DataLayerを内部的に呼び出して、データベースとの間でデータを選択、更新、削除、挿入します。
PS :@Andyは、すべてのシナリオで機能する一般的なデータレイヤーについて言及しました。その例については、この質問をご覧ください次のようになります。
他のヒント
ASP.NETアプリケーションのロジックレイヤーの最大の説明は、2つのソースから来ています。 1つ目は、Scott Mitchellによって書かれたMicrosoft独自のASP.NET Webサイトであり、ロジックの分離に関する優れた入門書です。チュートリアルは非常に冗長ですが、非常に有用であることがわかりました。 URLは http://www.asp.net/learn/data-access/。
私が非常に有用だと思った2番目のリソースはその後に続き、Imar Spaanjaarsによって作成され、こちら。これははるかに技術的な記事ですが、アプリケーションに構造を追加する優れた方法を提供します。
お役に立てば幸いです。
イアン。
最終的に移植可能になるようにコードを書くと、アプリケーションに3つ(またはそれ以上)のレイヤーがあることに気付くでしょう。
たとえば、データアクセスレイヤーをこの1つのアプリケーション専用に機能させるのではなく、もう一度記述しなくても済むように記述します。すべての関数に変数を渡すことができ、グローバル変数に依存しない(または、できるだけ少ない)ことを確認してください。次のプロジェクトの時間になったら、DALをコピーして貼り付けてください。突然、再び実行されます。
それで終わりではありません-MySQLとMSSQLの間で解釈するDALのサブレイヤーを作成することもできます(例として)。または、テキストサニテーションやCSS生成など、実行する一般的な機能のライブラリがある場合があります。
いつかコードを書くと、座ってアプリを書くことになります-そして、ほとんどの場合、以前のコードをカットして貼り付ける必要があります-あなたはプログラマのnに到達しました。 :)
アプリケーションの階層化の背後にある全体的な考え方は、各層が下の層の実装の詳細に依存しないということです。たとえば、コードでは、プレゼンテーションレイヤー内にT-SQLステートメントがあります。これは、データベースのプレゼンテーション層(最下層)に直接依存していることを意味します。データベースを変更する場合は、プレゼンテーションレイヤーも変更する必要があります。理想的には、これはあなたが望むものではありません。プレゼンテーション層は、データの表示方法のみを考慮し、データの取得方法については考慮しません。データベース全体をCSVファイルに移動するとします(私が知っている、おかしなアイデアです)。プレゼンテーションレイヤーはこれをまったく認識しないはずです。
理想的には、ユーザーに表示したいデータだけを返すビジネスレイヤーメソッドがあります。 ObjectDataSource
をご覧ください。 SqlDataSource
の代わりに。 SqlDataSource
は小規模なプロトタイピングプロジェクトには適していますが、それ以上の深刻なプロジェクトには使用しないでください。
ビジネス層とデータ層の間には、同様の分離が必要です。データレイヤーは、何らかの保存場所(データベース、CSVファイル、Webサービスなど)から必要なデータを取得します。繰り返しますが、理想的には、ビジネス層はデータ層の実装の詳細に依存すべきではありません。たとえば、SQL Serverと通信している場合、 SqlDataReader
インスタンスをビジネスレイヤーに追加します。これを行うことで、データ層の実装の詳細にビジネス層の依存関係を作成します:データを取得する実際のデータベース。
実際には、ビジネス層は何らかの形でデータ層の実装の詳細に依存していることがわかりますが、通常それは悪いことではありません。最後にデータベースを切り替えることにしたのはいつですか?ただし、依存関係を排除し、実装の詳細を可能な限り分離することで、ほとんどの場合、アプリケーションの保守と理解が容易になります。
同様の説明をこちらで見つけることができます。 。
彼の質問の主な目的は別として、ASPNET_REGSQLを見て、.Netの組み込みのメンバーシップ/プロファイル/ロール機能を処理するようにSQLデータベースを構成することをお勧めします。ユーザーを作成/更新するための多くのシャグと手間を削除します。プロファイルはあまり使用していませんが、「タックオン」することができます。ユーザーの追加属性、例: AccessCode。
すでにユーザー認証などを行う既存のDB構造を扱っている場合、既存のdbテーブルとストアドプロシージャを活用するカスタムメンバーシッププロバイダーを作成できます。