asp.net mvc за пределами hello world. Дятлов Александр d2d just.net

Post on 03-Mar-2017

438 Views

Category:

Technology

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

ASP.NET MVC за пределами Hello World

1

Дятлов Александр

О себеВеб-разработка около 4х лет

ASP.NET MVC более 3х лет

Благодаря ASP.NET влюбился в платформу .NET

Люблю выпить и поговорить про архитектуру :)

2

О чем доклад?Архитектура MVC

Организация бизнес логики приложения

Повторное использование кода

Немного о модульном тестировании

Обработка исключительных ситуаций

3

История паттерна MVC

Трюгве Миккель Хейердал Реенскауг

1979

Smalltalk

Xerox

4

Пассивная модель

5

Controller

View Model

Активная модель

6

Controller

View Model

Первые шаги в изученииМануалы

Сайт ASP.NETHabrahabr Tutorials...

Учебники по ASP.NET MVCАдам ФрименДжеффри Палермо

...

7

8

Проблемы понимания

Последствия

1. Бизнес-логика в контроллерах

9

public ActionResult GetByTagAndDate( string tagName, DateTime date, string authorName)

{

var posts = _dbContext.Posts.Where(p => p.Tags.Any(t => t.Name == tagName)

&& p.CreateOn < date

&& p.Author.Name == authorName);

if (!posts.Any())

return HttpNotFound();

return View(posts);

}

10

public ActionResult GetByTagAndDate(string tagName, DateTime date, string authorName) {

...

bool troll = (bool)Session["IsTroll"];

if (troll || _dbContext.Posts.Where(p => p.Author.Name == User.Identity.Name).SelectMany(p => p.Marks).Count(m => m.IsLike == true) > _dbContext.Marks.Count(m => m.Author.Name == User.Identity.Name && m.IsLike

== false))

ViewBag.IsTroll = true;

...

11

И еще немножко бизнес-логики

12 public class PostsV1Controller : Controller {

13 public ActionResult GetByTagAndDate(string tagName, DateTime date, string authorName) { … }

40 public ActionResult GetPostByTitle(string title) { … }

90 public ActionResult GetAll() { … }

1090 public ActionResult History() { … }

}12

И начинается АД

Последствия1. Бизнес-логика в контроллерах2. Использование динамических объектов для передачи данных

представлению

13

public ActionResult GetByTagAndDate(string tagName, DateTime date,

string authorName)

{

...

ViewBag.IsTroll = true;

return View(posts);

}

14

Потенциальное падение во время исполнения

Проверка на стороне представления

@{

var troll = false;

if (ViewBag.IsTroll != null)

troll = (bool)ViewBag.IsTroll;

}

@if (troll) {

<p>Ты мерзкий тролль!!!</p>

}

15

Последствия1. Бизнес-логика в контроллерах2. Использование динамической типизации для передачи данных

представлению3. Навешивание на бизнес-сущность атрибутов валидации

16

public class User_Entity {

[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

}

17

public class User_Entity {

[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

}

18

Последствия1. Бизнес-логика в контроллерах2. Использование динамической типизации для передачи данных

представлению3. Навешивание на бизнес-сущность атрибутов валидации4. Использование одной модели для отображения и получения

данных

19

20

User_Entity[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

Список пользователей

21

User_Entity[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

Список пользователей

Информация о пользователе

22

User_Entity[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

Список пользователей

Информация о пользователе

Сменить пароль

23

User_Entity[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[SecurePassword]

public string Password { get; set; }

Список пользователей

Информация о пользователе

Сменить пароль

Регистрация

Взаимодействия компонентов

24

Контроллер Модель

Представление

Хранение(обычно в реляционнойбазе данных)

Запрос HTTP

Ответ Модель представления

Взаимодействия компонентов

25

Контроллер Модель

Представление

Хранение(обычно в реляционнойбазе данных)

Запрос HTTP

Ответ Модель представления

Обязанности контроллера

26

Cache

Session

Cookies

Controller

Обязанности контроллера

27

Сервисы

Запросы

...

Команды

User.Identity.Name...

Controller

28

Тестирование контроллеров

public ActionResult GetByTagAndDate(string tagName, DateTime date, string authorName)

{

...

bool troll = (bool)Session["IsTroll"];

...

return View(posts);

}

29

Зависимость от сессии

Если необходимость в тестировании контроллеров осталась?

30

public ActionResult GetByTagAndDate(string tagName, DateTime date, string authorName,

Troll troll)

{

...

if (troll)

...

return View(posts);

}

31

Получение через параметры

public class TrollModelBinder : IModelBinder {public object BindModel(ControllerContext controllerContext,

ModelBindingContext bindingContext) {var troll =

(Troll)controllerContext.HttpContext.Session["IsTroll"];

if (troll == null) {troll = new Troll();controllerContext.HttpContext.Session["IsTroll"] = troll;

}return troll;

}}

32

Кастомный биндинг

Регистрация

protected void Application_Start()

{

...

ModelBinders.Binders.Add( typeof(Troll), new TrollModelBinder());

BundleTable.Bundles.EnableDefaultBundles();

...

}

33

Взаимодействия компонентов

34

Контроллер Модель

Представление

Хранение(обычно в реляционнойбазе данных)

Запрос HTTP

Ответ Модель представления

Модель / Виды

35

АМ~80%

БМ~20%

Личного опыт

АМ / БМАнемичная модель (бедная модель)

Сущности представляют данные

Сущности это плоские классы

Богатая модель

Единый язык между разработчиком и специалистом

Модель это дистиллированное знание36

Анемичная модель

37

CRUD_Service<T>

+Create()

+Read()

+Update()

+Delete()

Post

Topic

Tag

...

38

Единый механизм

В реальном мире

Интернет-блог

Каталог товаров

Сайты галереи

Сайты портфолио

Сайты визитки

и т.д.

39

В реальном мире

Интернет-блог

Каталог товаров

Сайты галереи

Сайты портфолио

Сайты визитки

и т.д.

40

Богатая модель / Кредит

41

Сredit_Entity

int DaysCountfloat InterestRatedecimal Sum

decimal Payment()

Богатая модель / Грузоперевозки

42

Shipping_Entity

float CargoTotalfloat CargoCurrentint OverflowRate

bool Add(float cargo)float FreePlace()

В реальном миреАвтоматизация банковских систем

Автоматизация транспортной логистики

Экспертные системы

и т.д.

43

В реальном миреАвтоматизация банковских систем

Автоматизация транспортной логистики

Экспертные системы

и т.д.

44

Доступ к данным

45

DAL / РекомендацииPersistence Ignorance

Сущности не должны зависеть от способа хранения данных

Использование паттерна Repository

46

Repository

47

CRUD_Repository<T>

+Create()

+Read()

+Update()

+Delete()

Post

Topic

...

CRUD_Service<T>

Troll_Detector

+ Detect()

DAL / Рекомендации

Persistence Ignorance

Сущности не должны зависеть от способа хранения данных

Использование паттерна Repository

Более гибкое решение:

Использование CQRS

48

Взаимодействия компонентов

49

Контроллер Модель

Представление

Хранение(обычно в реляционнойбазе данных)

Запрос HTTP

Ответ Модель представления

public class PostsGetByTagAndDateViewModel {

public IEnumerable<Post> Posts { get; set; }

public bool IsTroll { get; set; }

public PostsGetByTagAndDateViewModel (IEnumerable<Post> posts, bool isTroll) {

Posts = posts;

IsTroll = isTroll;

}

}50

Модель представления

Заполнение моделиpublic ActionResult GetByTagAndDate(string tagName, DateTime date,

string authorName, TrollState trollState)

{

...

if (!posts.Any())

return HttpNotFound();

return View(new PostsGetByTagAndDateViewModel(posts, trollState.IsTroll));

}

51

public class RegistrationViewModel {

[Required]

[StringLength(100)]

[Remote("CheckUserName", "Account")]

public string Name { get; set; }

[Required]

[StringLength(100)]

[SecurePassword]

public string Password { get; set; }

}

52

Классы помощникиpublic static class EmailHelpers {

public static IHtmlString Email(this HtmlHelper html, string address, string name = null) {

return new HtmlString($"<a href=\"mailto: { address }\"> { name ?? address } </a>");

}

}

<span>@Html.Email("google@gmail.com")</span>

<span>@Html.Email("google@gmail.com", "Отправить письмо")</span>

53

Классы помощники

@helper Email(string address, string name = null){

<a href="mailto:@(address)">@(name ?? address) </a>}

<span>@Helpers.Email("google@gmail.com")</span>

<span>@Helpers.Email("google@gmail.com", "Отправить письмо")</span>

54

App_Code\Helpers.cshtml

Классы помощники

@helper Email(string address, string name = null){

<a href="mailto:@(address)">@(name ?? address) </a>}

<span>@Helpers.Email("google@gmail.com")</span>

<span>@Helpers.Email("google@gmail.com", "Отправить письмо")</span>

55

App_Code\Helpers.cshtml

JavaScript код в представлениях

56

@model IEnumerable<Post>@{

Layout = "~/Areas/Admin/Views/Shared/_Layout.cshtml";var ajaxSave = new AjaxOptions {

Url = Url.Action("Edit"),OnSuccess = "ajaxSuccess"

};}

<table class="table-striped table-hover tablesorter table">...</table>

<script type="text/javascript" src="@Url.Content("~/Scripts/table.js")"></script><script type="text/javascript">

$(".tablesorter").tablesorter();$("#TableId").change(function () {

window.location.href = "/Posts/Edit/" + $("#PostId").val(); });

</script>

57

58

Вынос JS кода из представлений

App.views.Posts.Troll = ( function () {// private scope

return {init: function () {

// public API}

}})(jQuery);

59

Вызов в представленииPostsTroll.js

App.views.Posts.Troll = (function () {// private scope

return {init: function () {

// public API}

}})(jQuery);

<div> </div>

<script> App.views.Posts.Troll.Init();</script>

Проблема HTTP 1.0 / 1.1Дополнительные расходы на установку соединения для каждого запроса

Конвейерная передача HTTP

Параллельные HTTP соединения в современных браузерах от 4 до 8

60

Проблема HTTP 1.0 / 1.1Дополнительные расходы на установку соединения для каждого запроса

Конвейерная передача HTTP

Параллельные HTTP соединения в современных

браузерах от 4 до 8

61

МинификацияОбъединение JS в один файл при помощи bundle

62

public class BundleConfig {

public static void RegisterBundles(BundleCollection bundles) {

bundles.Add(new ScriptBundle("~/scripts/jquery").Include("~/Scripts/jquery-{version}.js").Include("~/Scripts/PostsTroll.js"));

}

}

МинификацияОбъединение JS в один файл при помощи bundle

Использование сторонних сборщиков

gulpgrunt...

63

public class BundleConfig {

public static void RegisterBundles(BundleCollection bundles) {

bundles.Add(new ScriptBundle("~/scripts/jquery").Include("~/Scripts/jquery-{version}.js").Include("~/Scripts/PostsTroll.js"));

}

}

Собрать части в целое

64

Архитектура современного веб-приложения

65

ВебUser Interface

Технические сервисы

Technical Services

Зави

сим

ости

Вспомогательная логикаServices

Бизнес-логика (М)Models

Dom

ain

Что делать если?

66

ВебUser Interface

Технические сервисы

Technical Services

Зави

сим

ости

Боле

е сп

ециф

ичес

кая

логи

ка

Вспомогательная логикаServices

Бизнес-логика (М)Models

Dom

ain

Инверсия управления (IoC)

67

ВебUser Interface

Технические сервисы

Technical Services

IPayService Зави

сим

ости

Боле

е сп

ециф

ичес

кая

логи

ка

Вспомогательная логикаServices

Бизнес-логика (М)Models

Dom

ain

Инверсия управления (IoC)

68

ВебUser Interface

Технические сервисы

Technical Services

IPayService

PayServiceIPayService

Зави

сим

ости

Боле

е сп

ециф

ичес

кая

логи

ка

Вспомогательная логикаServices

Бизнес-логика (М)Models

Dom

ain

Регистрация зависимостей

public class DIConfig : Module {

protected override void Load(ContainerBuilder builder) {

builder.RegisterType< PayService>().As<IPayService>();

base.Load(builder);

}

}

69

Что делать если что-то пошло не так?

70

Иерархия исключений .NET

71

Exception

ApplicationExceptionSystemException

Но не бывает так легко

72

Решение

73

DemoException

ApplicationException

Решение

74

DemoException

LogicExceptionFatalException

ApplicationException

Обрабатываем конкретные типы

75

try {

// Логика подтверждения оплаты

}

catch (PaymentNotVerifiedLogicException ex)

{

PaymentVerified = false;

_logger.Warning($"При оплате возникли проблемы { ex }");

}

Спасибо за внимание!

77

dyatlovall@gmail.comvk.com/dspro

top related