Данное руководство устарело. Актуальное руководство: Руководство по ASP.NET Core
Последнее обновление: 20.03.2018
Business Logic Layer или бизнес-уровень инкапсулирует всю бизнес-логику, все необходимые вычисления, получает объекты из уровня доступа к данным и передает их на уровень представления, либо, наоборот, получает данные с уровня представления и передает их на уровень данных.
Итак, добавим в решение новый проект по типу Class Library, который назовем NLayerApp.BLL . Поскольку бизнес-уровень будет использовать классы из уровня доступа к данным, то нам надо добавить на него ссылку:
Уровень представления не может напрямую получать данные из базы данных. В данном случае BLL будет выступать в роли посредника между двумя уровнями. Но также надо учитывать, что напрямую он не может передавать в контроллеры объекты Phone и Order, так как уровень представления не должен иметь доступ к функциональности уровня DAL. Поэтому нам нужны промежуточные сущности.
Бизнес-логика в веб-проекте. Проблема понимания бизнес-логики клиентских проектов. #bll #biz
Итак, добавим в проект BLL папку, которую назовем DTO. Определим в ней новый класс PhoneDTO:
namespace NLayerApp.BLL.DTO < public class PhoneDTO < public int Id < get; set; >public string Name < get; set; >public string Company < get; set; >public decimal Price < get; set; >> >
Через этот класс мы будем передавать объекты смартфонов между уровнями. Но хотя данный класс во многом похож по определению на класс Phone, это необязательное условие. Класс PhoneDTO должен содержать только те данные, которые мы собираемся передать на уровень представления или, наоборот, получить с этого уровня. То есть это то, что называется Data Transfer Object — специальная модель для передачи данных.
Подобным образом определим в той же папке класс OrderDTO:
using System; using NLayerApp.DAL.Entities; namespace NLayerApp.BLL.DTO < public class OrderDTO < public int Id < get; set; >public string PhoneNumber < get; set; >public string Address < get; set; >public int PhoneId < get; set; >public DateTime? Date < get; set; >> >
Для упрощения сопоставления классов моделей добавим в проект через NuGet библиотеку AutoMapper .
Кроме простых классов типа DTO BLL может содержать классы, которые описывают бизнес-логику. В частности, если мы вернемся к проекту с монолитной архитектурой, то там был небольшой функционал скидки. И в принципе скидку можно выделить в отдельный класс. Но для его хранения добавим в BLL новую папку BusinessModels. И в ней определим класс скидки Discount:
using System; namespace NLayerApp.BLL.BusinessModels < public class Discount < public Discount(decimal val) < _value = val; >private decimal _value = 0; public decimal Value < get < return _value; >> public decimal GetDiscountedPrice(decimal sum) < if(DateTime.Now.Day==1) return sum — sum * _value; return sum; >> >
Это бизнес-модель, которая не только хранит состояние, как классы DTO, но и может описывать некоторые действия. Выделение бизнес-моделей в проекте всецело индивидуально и зависит от конкретной ситуации.
Архитектура ПО, MVC и бизнес-логика. Критика Django
Большую роль в приложении играет валидация данных. По большей части за валидацию отвечает именно BLL. В контроллере мы легко можем провалидировать модель через объект ModelState и при необходимости возвратить в представление сообщения об ошибках. Но на уровне BLL ModelState недоступен. Однако мы все же можем использовать валидацию с передачей ошибок в уровень представления.
Итак, определим в BLL новый каталог Infrastructure и в него добавим новый класс ValidationException:
using System; namespace NLayerApp.BLL.Infrastructure < public class ValidationException : Exception < public string Property < get; protected set; >public ValidationException(string message, string prop) : base(message) < Property = prop; >> >
Класс ValidationException наследуется от базового класса исключений Exception и определяет свойство Property. Это свойство позволяет сохранить название свойства модели, которое некорректно и не проходит валидацию. И также передавая в конструктор базового класса параметр message , мы определяем сообщение, которое будет выводиться для некорректного свойства в Property.
Взаимодействовать между остальными двумя уровнями мы будем через специальный сервис. Опять же для большей гибкости вначале определим его интерфейс. Для хранения интерфейса добавим в BLL папку Interfaces и в нее положим интерфейс IOrderService:
using NLayerApp.BLL.DTO; using System.Collections.Generic; namespace NLayerApp.BLL.Interfaces < public interface IOrderService < void MakeOrder(OrderDTO orderDto); PhoneDTO GetPhone(int? id); IEnumerableGetPhones(); void Dispose(); > >
Интерфейс определяет 4 метода: получение всех смартфонов для выбора товара, выбор смартфона для заказа, оформление заказа и метод Dispose.
Для хранения реализаций интерфейса определим в проекте еще одну папку Services. Добавим в нее класс сервиса OrderService:
using System; using NLayerApp.BLL.DTO; using NLayerApp.DAL.Entities; using NLayerApp.BLL.BusinessModels; using NLayerApp.DAL.Interfaces; using NLayerApp.BLL.Infrastructure; using NLayerApp.BLL.Interfaces; using System.Collections.Generic; using AutoMapper; namespace NLayerApp.BLL.Services < public class OrderService : IOrderService < IUnitOfWork Database < get; set; >public OrderService(IUnitOfWork uow) < Database = uow; >public void MakeOrder(OrderDTO orderDto) < Phone phone = Database.Phones.Get(orderDto.PhoneId); // валидация if (phone == null) throw new ValidationException(«Телефон не найден»,»»); // применяем скидку decimal sum = new Discount(0.1m).GetDiscountedPrice(phone.Price); Order order = new Order < Date = DateTime.Now, Address = orderDto.Address, PhoneId = phone.Id, Sum = sum, PhoneNumber = orderDto.PhoneNumber >; Database.Orders.Create(order); Database.Save(); > public IEnumerable GetPhones() < // применяем автомаппер для проекции одной коллекции на другую var mapper = new MapperConfiguration(cfg =>cfg.CreateMap()).CreateMapper(); return mapper.Map, List>(Database.Phones.GetAll()); > public PhoneDTO GetPhone(int? id) < if (id == null) throw new ValidationException(«Не установлено id телефона»,»»); var phone = Database.Phones.Get(id.Value); if (phone == null) throw new ValidationException(«Телефон не найден»,»»); return new PhoneDTO < Company = phone.Company, Name = phone.Name, Price = phone.Price >; > public void Dispose() < Database.Dispose(); >> >
OrderService в конструкторе принимает объект IUnitOfWork , через который идет взаимодействие с уровнем DAL.
Метод MakeOrder() получает объект для сохранения с уровня представления и создает по нему объект Order и сохраняет его в базу данных.
Метод GetPhones() получает все смартфоны и с помощью автомаппера преобразует их в PhoneDTO и передает на уровень представления.
И метод GetPhone() передает отдельный смартфон на уровень представления.
Поскольку в данном случае мы не задаем в конструкторе явно объект IUnitOfWork, то нам надо использовать внедрение зависимостей для передачи конкретной реализации данного интерфейса в OrderService. Для этого добавим в проект через NuGet пакет Ninject:
Затем добавим в проект в ранее созданную папку Infrastructure следующий класс:
using Ninject.Modules; using NLayerApp.DAL.Interfaces; using NLayerApp.DAL.Repositories; namespace NLayerApp.BLL.Infrastructure < public class ServiceModule : NinjectModule < private string connectionString; public ServiceModule(string connection) < connectionString = connection; >public override void Load() < Bind().To().WithConstructorArgument(connectionString); > > >
ServiceModule представляет специальный модуль Ninject, который служит для организации сопоставления зависимостей. В частности, он устанавливает использование EFUnitOfWork в качестве объекта IUnitOfWork . Кроме того, здесь через конструктор передается название подключения, которое в итоге будет определяться в файле web.config проекта, представляющего уровень представления.
В итоге структура проекта будет выглядеть следующим образом:
Теперь создадим уровень представления.
Источник: metanit.com
2. Понятие бизнес-логики. Хранимые процедуры, триггеры, представления.
Хранимые процедуры – скомпилированный набор SQL предложений, сохраненный в базе данных как именованный объект и выполняющийся как единый фрагмент программного кода. Отдельные процедуры могут иметь параметры и возвращать значения. Созданная пользователем процедура компилируется сервером, а затем откомпилированный программный код может быть использован любым пользователем (рис.1)
В том случае если приложение использует данное предложение, сервер выполняет данную процедуру без перекомпиляции. Хранимые процедуры повышают производительность приложений:
Рис.1 Вызов хранимой процедуры клиентским приложением
- эти процедуры требуют меньше времени для подготовки и выполнения по сравнению с обычными SQL-запросами, посылаемыми из клиентских приложений;
- уменьшается сетевой трафик, т.к. по сети предается меньший объем информации;
- хранимые процедуры автоматически перекомпилируются в том случае, если объекты, входящие в состав процедуры, претерпевают изменения; т.о. хранимые процедуры всегда актуальны;
- возможно задание различных входных наборов данных для одной хранимой процедуры, если она имеет параметры;
- процедуры применяются для поддержки ограничений целостности и реализации бизнес-правил; это обеспечивает большую гибкость системе, т.к. при модификации бизнес-правил изменяются только процедуры, а не клиентские процедуры.
Кроме процедур, используемых в клиентских приложениях, СУБД имеет системные хранимые процедуры; они могут использоваться для выполнения следующих задач:
- вывод и изменения глобальных конфигураций сервера;
- получение сведений о поддерживаемых типах данных;
- получение сведений об объектах базы данных;
- вывод статистики СУБД;
- вывод сведений обо всех базах данных, доступных данному серверу.
Системные процедуры, также как и обычные процедуры могут использоваться клиентскими приложениями.
Триггеры
Триггер — специальный тип хранимой процедуры, которая вызывается в том случае, когда данные в определенной таблице добавляются, удаляются или изменяются с помощью соответствующих операторов SQL (рис.2).
Рис.2 Автоматический вызов триггера
Большинство СУБД позволяют создавать несколько триггеров для одного и того же события. Триггеры часто создают для поддержки ограничений целостности, каскадного удаления/изменения данных, для архивирования удаленных данных. Поскольку триггер вызывается автоматически самой СУБД, его нельзя вызвать их клиентского приложения – можно только инициировать действия, активизирующие триггер. Триггеры, опосредованно вызывающие другие триггеры, называются вложенными.
Триггер всегда выполняет некоторое действие и никогда не возвращает пользователю данные.
Источник: studfile.net
Программирование бизнес логика это
Ключевой вопрос: Из каких объектов, свойств, функций и взаимосвязей должен состоять продукт, чтобы с желаемым качеством удовлетворить потребности потребителей?
Непротиворечивость и полнота бизнес-логики продукта определяют его возможности по созданию, масштабированию и дистрибуции ценности до потребителя.
1. Артефакты и документы
Модель предметной области
Модель, определяющая сущности и их взаимосвязи, из которых состоит та или иная система. Чем сложнее продукт, амбиции по усилению ценности или масштабированию, тем большее значение принимает правильно выстроенная бизнес-логика этого продукта. Именно она является ограничителем роста и источником технического долга.
Нефункциональные требования
Описание требований к общим свойствам продукта или его частей, не связанных с пользовательскими функциями. Например, требования по доступности, совместимости, портируемости, надежности, масштабируемости, безопасности и т.д.
Перечень ключевых терминов продукта или элементов, из которых состоит технологическая система продукта, и их определений. Необходима для того, чтобы сотрудники компании разговаривали на одном языке, сокращая двусмыленность и неопределенность.
Дизайн система
Формализация предметной области продукта при помощи элементов пользовательского интерфейса. Определяет не только атомарные единицы, из которых состоит интерфейс (кнопки, цветовая палитра, шрифты, расстояния между элементами, комбинации из примитивов и т.д.), но и паттерны и метаформы взаимодействия пользователя с ним.
2. Модели и инструменты
Entities Analysis
Модель описания бизнес-логики продукта, представленная в виде перечня главных объектов системы (сущностей), их взаимосвязей и атрибутов. Правильный выбор сущностей и их взаимосвязей является ключевым фактором для построения масштабируемых, гибких и консистентных продуктов. Популярные типы связей между сущностями: ассоциация, генерализация, композиция, агрегация, абстракция. Для каждой связи определяется тип кратности. Для сущностей могут быть определены её атрибуты.
Sequence Diagrams
Диаграммы последовательности используются для отображения информации, которая передается между объектами или процессами системы при их взаимодействии во время выполнения сценария пользователя. Последовательность передачи сообщений реализована через временную шкалу.
Источник: productframework.ru