Pergunta

Eu só comecei a programar em C # e estava lendo sobre dividir sua aplicação / website em três camadas diferentes foi a melhor prática, mas estou tendo dificuldade em entender exatamente como. Im trabalhando em um projeto de estimação a inclinar-se mais sobre C #, mas eu não quero começar em qualquer maus hábitos. você pode olhar para o que eu tenho e ver se eu estou fazendo este direito? Oferecer algumas sugestões dicas de como dividir tudo com as diferentes camadas?

Camada de Apresentação

<%@ 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>

Camada de Negócios

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);
    }
  }
}

Data Access Layer (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();
      }
    }
  }
}
Foi útil?

Solução

Jon,

Uma das primeiras coisas a compreender é que, se você pretende construir aplicações com base em camadas, então você não deve ser armazenar instruções SQL diretamente dentro páginas ASPX (como o SqlDataSource exige). O controle SqlDataSource foi construído para demonstrar como é fácil para ligar e atualizar um aplicativo com os dados do banco de dados e não se destina a ser usado em aplicações do mundo real, porque vence meio a finalidade de ter uma camada BL e DataLayer se você estiver indo para loja Select / Update / / declarações Delete Insert na página aspx.

A propósito de design do aplicativo com base em camadas é encapsular cada camada de modo que não há interseção. Cada interage camada com a interface pública das outras camadas e não sabe nada sobre a sua implementação interna.

A alternativa viável, por conseguinte, é utilizar o controlo ObjectDataSource. Este controle permite que você ligar diretamente para um DataLayer ou para uma camada lógica Biz que por sua vez pode chamar o DataLayer. Ligação a uma DataLayer diretamente tem a desvantagem de que você vai voltar estruturas de dados que expõem o esquema das tabelas de banco de dados (por exemplo, tabelas de dados ou DataViews).

Assim, o fluxo recomendado de lógica é a seguinte:

A página ASPX usa um controle DataSource para vincular a uma classe BL. Esta classe BL fornece funções adequadas, tais como GetData, UpdateData, DeleteData and InsertData (com quaisquer sobrecargas exigidas) e estas funções retornam objetos ou coleções que a ObjectDataSource pode trabalhar com e exibição rigidez. Cada função pública na classe BL chama internamente na DataLayer para selecionar / update / / exclusão de inserção de dados de / para o banco de dados.

Uma excelente introdução a este projeto base em camadas em ASP.NET é fornecido no Quickstarts

P.S : @Andy mencionado datalayers genéricos que funcionam com todos os cenários. Consulte esta questão para um exemplo do que ele seria semelhante.

Outras dicas

A maior explicação de camadas lógicas em aplicações ASP.NET vir de duas fontes. O primeiro é o próprio site do Microsoft ASP.NET escrito por Scott Mitchell ele fornece uma boa introdução para a separação da lógica. Os tutoriais são bastante prolixo, mas eu encontrei-os muito útil. A URL é http://www.asp.net/learn/data-access/.

O segundo recurso que eu achei muito útil seguiu-se a isso e foi escrito por Imar Spaanjaars e está disponível aqui . É um artigo muito mais técnico, mas proporciona uma ótima maneira de adicionar a estrutura de sua aplicação.

Espero que ajuda.

Ian.

Se você escrever seu código para ser, em última análise portátil, você vai achar que você terá 3 (ou mais!) As camadas na sua aplicação.

Por exemplo - em vez de fazer o seu trabalho Data Access Layer especificamente para esta aplicação um, escrevê-lo de modo que você nunca terá que escrevê-lo novamente. Certifique-se de todas as suas funções podem ser passadas variáveis ??e você não dependem de variáveis ??globais (ou tão pouco quanto possível). Quando chega a hora para o seu próximo projeto - copiar e colar o DAL e de repente você está instalado e funcionando novamente

.

E não termina aí - você pode querer escrever uma sub-camada para o seu DAL que interpreta entre MySQL e MSSQL (apenas como exemplo). Ou você pode ter uma biblioteca de funções comuns que você executa, como saneamento texto ou geração CSS ou algo assim.

Se você escrever seu código para que um dia, você se senta para escrever um aplicativo - e envolve principalmente cortando e colando código anterior - você alcançou programador nirvana. :)

A idéia por trás de camadas de uma aplicação é que cada camada não depende de detalhes de implementação da camada (s) abaixo. Por exemplo, em seu código que você tem uma declaração T-SQL dentro de sua camada de apresentação. Isso significa que você tem uma dependência direta de sua camada de apresentação em seu banco de dados (camada inferior). Se você fazer uma mudança em seu banco de dados, você também deve fazer uma mudança em sua camada de apresentação. Idealmente, isso não é o que você quer. A camada de apresentação só deve se preocupar com a apresentação de dados, e não sobre como recuperá-lo. Suponha que você mover todo o seu banco de dados em arquivos CSV (eu sei, ideia louca), então a sua camada de apresentação não deve estar ciente de tudo isso.

Assim, idealmente, você tem um método camada de negócios que retorna apenas os dados que você quer mostrar para o usuário. Você deve dar uma olhada ObjectDataSource vez de SqlDataSource. SqlDataSource é bom para projetos de prototipagem pequenas, mas você não deve usá-lo para qualquer projeto mais graves.

Entre camada de negócios e camada de dados, você deve ter uma separação similar. A camada de dados é responsável por obter os dados que você quer de algum local de armazenamento (banco de dados, arquivo CSV, serviço web, ...). Mais uma vez, de preferência, a camada de negócios não deve depender dos detalhes de implementação da camada de dados. Se você está falando com SQL Server por exemplo, você não deve retornar um instância SqlDataReader na sua camada de negócios. Ao fazer isso, você cria uma dependência de sua camada de negócios sobre um detalhe de implementação de sua camada de dados:. O banco de dados real que está recuperando seus dados contra

Na prática, você vê que a camada de negócios não depende de detalhes de implementação da camada de dados, de alguma forma ou de outra e, geralmente, isso não é uma coisa ruim. Quando foi a última vez que você decidiu mudar bases de dados? Mas eliminar dependências e isolar detalhes de implementação, tanto quanto possível quase sempre resulta em um aplicativo que é mais fácil de manter e compreender.

Você pode encontrar uma explicação semelhante aqui .

Como um aparte para o principal impulso da sua pergunta, eu recomendo que você olhar para aspnet_regsql para configurar seu banco de dados SQL para lidar com o .Net built-in capacidades de adesão / perfil / função. Seria remover um monte de shag e sem complicações para a criação / atualização de usuários, etc. Eu não usei perfil muita coisa, mas ele permite que você "tack on" atributos extras para o seu utilizador, por exemplo, AccessCode.

Se você está lidando com uma estrutura DB existente que já faz a autenticação do usuário etc., você pode criar um provedor de associação personalizado que iria alavancar as tabelas db existentes e procedimentos armazenados.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top