G+

Asp.net для начинающих: Архитектура сайта

Программирование Asp.net
Предыдущий Следующий

Архитектура сайта у всех компаний своя и все считают ее идеальной, и привыкать к чужому построению сайта весьма сложно. Расскажу, как распологаю файлы проекта я. Мое архитектурное решение не самое лучшее, по этому все предложения и критика по улучшению принаются.

Создаем Asp.Net MVC 3 Web Application с Unit Test Project. После этого у нас появиться один Solution и два проекта в нем (веб сайт и юнит тесты)

Следующим шагом создаем проект для связи с базой данных. Я использую ORM  Entity Framework. ORM лучше выносить в отдельный проект, что бы ее можно было легко менять или используват другие методы связи с БД или вообще использовать другое хранилище. Проект как правило я называю {MyProject}.Data Его тип будет "Class Library"

 asp.net

В созданом проекте удаляем файл Class1.cs, он нам не к чему. И добавляем ORM.

Для этого нажимаем на названии проекта и в контекстном меню выбираем пункт "Add"->"New Item...". Выбираем "ADO.NET Entity Data Model" Пишем имя нашей ORM

asp.net mvc

После этого нам откроется Wizard создания подключения к БД. На первом шаге выбираем "Generate from database". Дальше жмем кнопку "New Connection..." и указываем параметры подключения и нужную database.

asp.net connection

Жмем "OK". Выбираем параметр "Yes, include the sensitive data in the connection string" и жмем "Next>". На следующем шаге Вы должны выбрать таблицы, которые будут задействованы в проекте (если их нету, то прийдется создать, например табл. Persons и Blogs).  Одно из особенностей этой ORM заключается в том, что все таблицы имели primary key. Жмем Finish.  После этого в наш проект добавится два файла (*.edmx и App.Config). В файле App.Config находится строка подключения к базе.

asp.net connection string

Нужно скопировать строку:

<add name="dbItFreelanceEntities" connectionString="metadata=res://*/.................. providerName="System.Data.EntityClient" />

и вставить ее в файл Web.config сайта.

asp.net connection string

У нас теперь там будет две строки подключения. Вторую мы будем использовать для настройки авторизации пользователя (membership).

 Теперь создаем проект, в котором будет находится вся бизнес логика системы. Назовем проект {MyProject}.BL Его тип тоже будет "Class Library". Файл Class1.cs нужно удалить.

Додаем класс DataManager к проекту. Он будет урпавлять (а точнее хранить) бизнес объекты системы (repository)

asp.net connection string

asp.net connection string

В этом классе пишем конструктор, в котором мы будет инициализировать объект ORM. С помощью этого объекта мы будем получать доступ к базе данных:

public class DataManager
    {
        private dbItFreelanceEntities datacontext;
        public DataManager()
        {
            datacontext = new dbItFreelanceEntities();
        }
    }

 

Теперь сделаем так что бы проекты узнали друг про друга. Для этого додаем Reference проекта "{MyProject}.Data" в "{MyProject}.BL". А Reference "{MyProject}.BL" в проект нашего сайта. Таким образом получается связь Data->BL->Сайт. Обратите внимание, что Сайт ничего не знает про Data, и будет общаться с ней через BL.

Для добавление Reference, нужно нажать мышкой на название проекта и в контекстному меню выбрать пункт "Add Reference...". В появившимся окне на вкладке Projects нужно выбрать нужный проект (для {MyProject}.BL додаем {MyProject}.Data, а для сайта {MyProject}.BL)

asp.net connection string

Запускаем Solution (F5) смотрим что все работает. (Скорее всего в проект {MyProject}.BL вам нужно будет добавить Reference "System.Data.Entity" из закладки ".NET")

Теперь создаем главный котнролер, он будет делать общие действия для всех контролеров (например, узнавать информацию о авторизированом пользователе, устанавливать нужную локацию, или вести какую-то статистику). От этого контролера будут наследоваться все остальные контролеры.

Жмем правой клавишей мышки на папке Controllers и добавляем контролер с названием ControllerMain.

controller

Удаляем action Index и переопределяем метод Initialize. Этот метод будет вызыватся каждый раз при инициализации контролера, похоже на конструктор. Так же в этом контроллере будет свойство DataManager, с помощью него мы будем получать доступ к базе данных. Вот код

public class ControllerMain : Controller
{
    private DataManager _dm;
    public DataManager dm { get { return _dm; } }

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);
        _dm = new DataManager();
    }
}
 

Перейдем к работе с базой данных. 

Мы будем использовать базу данных для получения имени и фамилии пользователя Выгdm.Persons.GetInfoUser(UserID)) Для реализации этого мы добавим класс Persons_Repository в проект {MyProject}.BL. Для каждого логического объекта системы будем создаваться похожий класс, главное что бы этот класс имел методы, которые относятся только к нужному объекту.

В этом классе реализуем конструктор, который будет принимать dbItFreelanceEntities datacontext и DataManager dm, это нужно для того что бы класс имел доступ к базе:

public class Persons_Repository
{
    private Data.dbItFreelanceEntities datacontext;
    private DataManager dm;
    public Persons_Repository(Data.dbItFreelanceEntities datacontext, DataManager dataManager)
    {
        this.datacontext = datacontext;
        this.dm = dataManager;
    }
}
 

Теперь будем добавлять в  этот класс методы для работы с объектом Person. Главный критерий, который нужно поддерживать, это не выносить классы, которые создала ORM за пределы проекта {MyProject}.BL. Это означает что проект mvc-сайта не должен использовать классы созданые ORM, если нужно передать какую-то информацию то для нее создаем отдельный класс.

Для примера реализуем метод GetInfoUser. Сначала создаем в проекте папку {MyProject}.BL ViewModels. В ней и будут хранится наши классы для обмена информации между проеками и контролерами и Views. В этой папке создаем новую папку Person, это нужно для удобной группировки классов. И уже в  эту папку додаем класс TPersonInfo.

controller

Теперь напишем метод, который будет возращать этот класс, так же добавим необходимые свойства в класс:

public TPersonInfo GetInfoUser(Guid? UserID)
{
    var data = datacontext.Persons.Where(pr => pr.PersonID == UserID && !pr.IsDelete)
        .Select(l => new TPersonInfo()
    {
        PersonID = l.PersonID,
        RoleID = l.Users.Roles.Select(r => r.RoleId).FirstOrDefault(),
        FirstName = l.FirstName,
        LastName = l.LastName,
        IsDelete = l.IsDelete,
    }).FirstOrDefault();
    return data;
}
 

Следующим шагом откроем класс DataManager и добавим там свойство Persons

public class DataManager
{
    private dbItFreelanceEntities datacontext;
    public DataManager()
    {
        datacontext = new dbItFreelanceEntities();
    }

    private Persons_Repository _Persons;
    public Persons_Repository Persons
    {
        get
        {
            if (_Persons == null)
                _Persons = new Persons_Repository(datacontext, this);
            return _Persons;
        }
    }
}
 

Итак, что мы имеем. Во первых, у нас есть класс DataManager, который имеет ссылки на классы для работы с объектами (пример такого класса Persons_Repository). Эти классы имеют методы с помощью которых мы можем добавлять/удалять/изменять/получать данные с базы данных (пример метода GetInfoUser в котором мы получаем информацию о пользователе). Во вторых, у нас есть главный контролер (ControllerMain) от него будут наследоваться все контролеры системы, и в себе он будет иметь ссылку на объект типа DataManager.

Теперь откроем контролер HomeController. Сделаем, что бы он наследовался от класса ControllerMain. В action Index мы получим информацию о пользователе с ИД {90A793FD-5391-41AE-8A5F-8A5C92091136} (такого пользователя нету, ничего страшного):

public class HomeController : ControllerMain
{
    public ActionResult Index()
    {
        ViewBag.Message = "Welcome to ASP.NET MVC!";

        var Users = dm.Persons.GetInfoUser(new Guid("{90A793FD-5391-41AE-8A5F-8A5C92091136}"));

        return View();
    }
}
 

Теперь получим информацию о зарегистрированом пользователе. Поскольку это нужно знать на всех страничках, то эту информацию будем получать в методе Initialize нашего контролера.

Создаем класс UserLoginInfo (правой клавишей на папке Models и в контекстном меню выбираем "Add"->"Class..." и пишем название UserLoginInfo) (для того что бы понять где какие файлы находяться смотри рисунок выше)

Этот класс будет иметь такие свойства (это общая информация о пользователе):

public System.Web.Security.MembershipUser User { get; private set; }
public Guid? UserID { get; private set; }
public string UserName { get; private set; }
public Guid RoleID { get; private set; }

public bool IsAdmin { get { return false; } }
public bool IsAutoriaze { get { return UserID != Guid.Empty; } }

public string FirstName { get; private set; }
public string LastName { get; private set; }

Теперь реализуем в этом классе статический метод с помощью, которого будем получать этот класс

public static UserLoginInfo GetAccountInfo(DataManager dm)
        {
            if (dm == null)
                dm = new DataManager();
            return new UserLoginInfo(dm);
        }

В этом методе используется контруктор, давайте реализуем.

public UserLoginInfo(DataManager dm)
{
    this.User = System.Web.Security.Membership.GetUser();
    if (this.User == null)
        return;

    this.UserName = User.UserName;
    this.UserID = (Guid)User.ProviderUserKey;
    var InfoUset = dm.Persons.GetInfoUser(UserID);

    if (InfoUset == null)
        return;

    this.UserID = InfoUset.PersonID;
    this.FirstName = InfoUset.FirstName;
    this.LastName = InfoUset.LastName;
    this.RoleID = InfoUset.RoleID;
}
 

В этом конструкторе мы получаем Ид пользователя(UserID) с помощью стандартных методов Membership.

Теперь перейдем к методу Initialize гланого контролера (ControllerMain). В нем мы будем получать инфу о текущем пользователи и хранить ее в HttpContext.Items["_AccountInfo"]. Смотрим код:

public class ControllerMain : Controller
{
    private DataManager _dm;
    public DataManager dm { get { return _dm; } }
    private UserLoginInfo _AccountInfo;
    public UserLoginInfo AccountInfo { get { return _AccountInfo; } }

    protected override void Initialize(System.Web.Routing.RequestContext requestContext)
    {
        base.Initialize(requestContext);
        _dm = new DataManager();

        if (requestContext.HttpContext.Items["_AccountInfo"] == null)
        {
            _AccountInfo = UserLoginInfo.GetAccountInfo(dm);
            //можем получит инфу о текущем пользователе, обратившись к HttpContext.Items["_AccountInfo"]

            requestContext.HttpContext.Items.Add("_AccountInfo", AccountInfo);
            //InitCulture(requestContext.RouteData, requestContext);
        }
        _AccountInfo = (UserLoginInfo)requestContext.HttpContext.Items["_AccountInfo"];
        ViewBag.AccountInfo = AccountInfo;
    }
}
 

Теперь напишем пару методов, которые мы будем использовать на вющках (Views) для получение инфы о авторизированом пользователе:

namespace System.Web.Mvc
{
    public static class UserLoginInfoWork
    {
       
        public static UserLoginInfo GetUserLoginInfo(this System.Web.Mvc.UrlHelper url)
        {
            return (UserLoginInfo)url.RequestContext.HttpContext.GetUserLoginInfo();
        }
        
        public static UserLoginInfo GetUserLoginInfo(this System.Web.Mvc.HtmlHelper url)
        {
            var account = (UserLoginInfo)url.ViewContext.Controller.ViewBag.AccountInfo;
            return account ?? (UserLoginInfo)url.ViewContext.HttpContext.GetUserLoginInfo();
        }
       
        public static UserLoginInfo GetUserLoginInfo(this HttpContextBase url)
        {
            var AccountInfo = (UserLoginInfo)url.Items["_AccountInfo"];
            if (AccountInfo == null)
            {
                AccountInfo = new UserLoginInfo(null);
            }
            return AccountInfo;
        }
    }
}

 

Теперь еще раз откроем action Index Home-контроллера и получим там инфу о пользователе:

public ActionResult Index()
{
    ViewBag.Message = "Welcome to ASP.NET MVC!";

    var Users = dm.Persons.GetInfoUser(new Guid("{90A793FD-5391-41AE-8A5F-8A5C92091136}"));

    var ThisUser = AccountInfo;

    return View();
}
 

 Исходный код можно скачать здесь

Asp.net для начинающих. Содержание.

 

Комментарий:
  • В 30.10.2012 14:12:21, Аноним

    Спасибо, познавательно. Сейчас как раз делаю программу управления заданиями, архитектуру сделаю как у Вас, с разделением на проекты.

  • В 05.02.2016 8:22:52, Jean R

    Очень интересно. Только не понятно, как работать с хранимками. И как строку подключения к ORM перенести из библиотеке в сам проект.

Самостоятельный отпуск Опыт заказа вывоза мусора в Киеве