38
Темы лекции: ASP.NET. MVC. Часть 5. Практическое задание: ASP.NET. MVC. Тренер: Игорь Шкулипа, к.т.н. Разработка Веб-приложений на платформе Microsoft .NET Framework. Занятие 13

C# Web. Занятие 13

Embed Size (px)

Citation preview

Темы лекции: ASP.NET. MVC. Часть 5.

Практическое задание: ASP.NET. MVC.

Тренер: Игорь Шкулипа, к.т.н.

Разработка Веб-приложений на платформе Microsoft .NET Framework.

Занятие 13

http://www.slideshare.net/IgorShkulipa 2

Бандлы

Материал из Википедии — свободной энциклопедии

Бандл (от англ. bundle — охапка, вязанка, пакет) в игровой индустрии —комплект, состоящий из нескольких товаров, продаваемых как единоецелое.

Примеры бандлов:

Типичные и самые популярные бандлы — это так называемые игровыекомплекты:

• Игровая консоль + видеоигра• Видеокарта (или материнская плата) + компьютерная игра

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

http://www.slideshare.net/IgorShkulipa 3

Бандлы и минификацияВ ASP.NET MVC 4 была введена концепция бандлов, которая помогает организовать

файлы скриптов и стилей более эффективным путем для снижения издержек припередаче клиенту.

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

<head>

<meta name="viewport" content="width=device-width" />

<link type="text/css" rel="stylesheet" href="~/Content/Site.css" />

<script src="~/Scripts/jquery-1.7.1.js" type="text/javascript">

</script>

<title>Index</title>

</head>

Фреймворк MVC для настройки путей предлагает нам использовать URL-хелперы:

<head>

<meta name="viewport" content="width=device-width" />

<link type="text/css" rel="stylesheet"

href="@Url.Content("~/Content/Site.css")" />

<script

src="@Url.Content("~/Scripts/jquery-1.7.1.js")"

type="text/javascript"></script>

<title>Index</title>

</head>

http://www.slideshare.net/IgorShkulipa 4

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

Использование бандлов представляет совсем другой подход к использованиюскриптов и стилей. При создании нового проекта MVC4 по шаблону Basic илиInternet Application функциональность бандлов уже по умолчанию включается вприложение.

<!DOCTYPE html>

<html>

<head>

...

@Styles.Render("~/Content/css")

@Scripts.Render("~/bundles/modernizr")

</head>

<body>

@RenderBody()

@Scripts.Render("~/bundles/jquery")

@RenderSection("scripts", required: false)

</body>

</html>

В данном случае подключаются не конкретные скрипты и стили, а именно бандлы. Спомощью хелпера Styles.Render подключаются бандлы стилей, а с помощьюхелпера Scripts.Render. Эти хелперы принимают в качестве параметра имябандла.

http://www.slideshare.net/IgorShkulipa 5

BundleConfig.cs

По умолчанию проекты MVC4 (исключая проекты Empty) уже содержат регистрациюбандлов - в файле BundleConfig.cs, который находится в папке App_Start.

http://www.slideshare.net/IgorShkulipa 6

Регистрация бандлов

Метод RegisterBundles добавляет все создаваемые бандлы в коллекцию bundles.Объявление бандла выглядит следующим образом:

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

В конструктор ScriptBundle передается виртуальный путь бандла. А с помощью методаInclude уже включаются в данный бандл конкретные файлы скриптов.

В выражении "~/Scripts/jquery-{version}.js" параметр {version} являетсязаменителем для любого символьного обозначения версии скрипта. Это оченьудобно, поскольку через некоторое время мы можем поменять версию библиотеки,но при этом в коде нам ничего не придется менять, так как система ужеавтоматически примет новую версию.

Выражение "~/Scripts/jquery.validate*" с помощью знака звездочки заменяетостальную часть строки. Например, это выражение подключит в бандл сразу двафайла: jquery.validate.js и jquery.validate.unobtrusive.js (и ихминимизированные версии).

То же самое касается и создания бандлов стилей, только в этом случае используетсякласс StyleBundle.

http://www.slideshare.net/IgorShkulipa 7

Регистрация бандлов

Однако само объявление бандлов в файле BundleConfig.cs еще не подключаетавтоматически их в проект.

Для этого в файле Global.asax используется соответствующая директива:

public class MvcApplication1 : System.Web.HttpApplication

{

protected void Application_Start()

{

...

BundleConfig.RegisterBundles(BundleTable.Bundles);

}

}

Таким образом, мы и регистрируем бандлы для нашего приложения.

http://www.slideshare.net/IgorShkulipa 8

Минификация

Ключевым моментом концепции бандлов является минификация. Ее сутьсостоит в том, что при развертывании приложения клиенту отдается неполная, а минимизированная версия скриптов или стилей. За счет чегоэкономятся ресурсы сервера, так как идет отдача файла с меньшимобъемом.

Таким образом, использование бандлов в проектах MVC4 повышаетэффективность веб-приложения.

Кроме того, для минимизации скриптов и стилей существует большоеколичество утилит, которые можно дополнительно использовать.Например, очень неплохая утилита по минимизации скриптовMicrosoft Ajax Minifier, позволяющая ужать скрипты в среднем до50%, а иногда и больше.

http://www.slideshare.net/IgorShkulipa 9

Создание бандловpublic class BundleConfig {

public static void RegisterBundles(BundleCollection bundles) {

...

bundles.Add(

new ScriptBundle("~/bundles/myscripts").Include(

"~/Scripts/MyScripts/*.js"));

...

} } }

Выражение "~/Scripts/MyScripts/*.js" подключит в бандл все файлы js, которые естьв каталоге Scripts/MyScripts.

Далее, в разметке подключаем новый бандл:

<body>

...

@Scripts.Render("~/bundles/myscripts")

...

</body>

</html>

И после этого бандл будет подключаться в приложение. При подключении бандлов нестоит забывать об очередности: если у вас есть бандлы, файлы которыхзависят от других файлов других бандлов, например, от jquery, то, зависимыебандлы надо подключать после основных.

http://www.slideshare.net/IgorShkulipa 10

CDN

Обычным делом на сегодняшний день является подключение различныхпопулярных библиотек javascript из сетей CDN.

Сеть доставки (и дистрибуции) контента (англ. Content DeliveryNetwork или Content Distribution Network, CDN) — географическираспределённая сетевая инфраструктура, позволяющаяоптимизировать доставку и дистрибуцию контента конечнымпользователям в сети Интернет.

Использование контент-провайдерами CDN способствует увеличениюскорости загрузки интернет-пользователями аудио-, видео-,программного, игрового и других видов цифрового контента в точкахприсутствия сети CDN.

http://www.slideshare.net/IgorShkulipa 11

Подключение библиотек из сетей CDN

Если мы хотим подключить, например, библиотеку jquery не со своего приложения, ас какой-нибудь сети CDN, то мы должны включить поддержку CDN в бандлах вфайле BundleConfig.cs:

public class BundleConfig

{

public static void RegisterBundles(BundleCollection bundles) {

...

bundles.UseCdn = true;

var jqueryCdnPath =

"http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.1.min.js";

bundles.Add(new ScriptBundle("~/bundles/jquery",

jqueryCdnPath).Include(

"~/Scripts/jquery-{version}.js"));

...

} } }

Далее подключаем бандл обычным способом.

http://www.slideshare.net/IgorShkulipa 12

Real-time веб приложения

Основной отличительной способностью сервисов, которые можно назватьreal-time веб-приложениями является то, что они “ломают” привычнуюнам всем модель работы в вебе – запрос-ответ, благодаря чемупользователи видят обновление данных сразу же, как только онипоявляются на сервере.

Если не знать, насколько далеко вперед шагнули технологии запоследние несколько лет, то можно предположить, что все подобныеприложения реализованы при помощи периодического опрашиваниясервера обычными Ajax-запросами, т.н. polling. Выглядит похоже, ноэто не совсем так.

http://www.slideshare.net/IgorShkulipa 13

Способы реализации

Техника Описание Преимущества Недостатки

Polling Постоянный опрос сервера Ajax-запросами

+ простота реализации+ поддержка во всех современных браузерах

- задержка в результатах- при уменьшении задержки существенно увеличивается нагрузка на сервер

Long Polling

Ajax-запросы, идущие один за другим, но каждый запрос держится открытым в течение нескольких минут

+ сниженная нагрузка на сервер по сравнению с обычным Polling+ уменьшенный трафик+ поддержка во всех современных браузерах

- больше одновременно открытых соединений, т.к. каждый запрос живет дольше

http://www.slideshare.net/IgorShkulipa 14

Способы реализации

Техника Описание Преимущества Недостатки

Server-Sent Events

Новый стандарт HTML5, работающий поверх HTTP. Позволяет создавать долгоживущее соединение с сервером, чтобы сервер мог отправлять данные на клиент

+ нет необходимости постоянно пересоединяться с сервером+ нет изменений на стороне сервера, поэтому работает на всех современных веб-серверах

- не поддерживается в IE (даже в IE10)- работает только в направлении сервер –> клиент (на сервер можно отправлять обычные Ajax запросы)

WebSockets Новый протокол (ws:// и wss://), работающий поверх TCP на одном уровне с HTTP. Позволяет создавать двустороннее долгоживущее соединение с клиентом

+ нет необходимости постоянно пересоединяться с сервером+ работает в двустороннем режиме

- поддерживается не во всех веб-серверах (IIS8)- поддерживается не во всех браузерах (в IE7-9, Android)

http://www.slideshare.net/IgorShkulipa 15

SignalR

Для упрощения работы с коммуникациями реального времени быласоздана специальная библиотека под названием SignalR.

SignalR предоставляет простой API для создания функционала, которыйпозволяет вызывать функции JavaScript на стороне клиента изсерверного кода, написанного с помощью языков платформы .NET.

SignalR значительно упрощает работу с коммуникациями реальноговремени. Библиотека обрабатывает все подключения и автоматическирассылает сообщения всем подключенным клиентам, либо каким-нибудь специфическим клиентам.

При этом SignalR является библиотекой, предназначенной не только дляиспользования в ASP.NET MVC. Ее также можно использовать и в веб-формах, а также в консольных приложениях, десктопных приложенияи в WPF.

Фактически библиотека SignalR состоит из API серверной стороны,который применяется в коде на C#, и из клиентских библиотекJavaScript.

http://www.slideshare.net/IgorShkulipa 16

Ссылки

SignalR – это open source библиотека, которая находится на GitHub.

SignalR был придуман и реализован двумя разработчиками Microsoft:Damian Edwards и David Fowler. В своих твиттерах они часто пишутполезную информацию о SignalR и сообщают о новостях. Также DavidFowler ведет блог, в котором описывает все изменения в новыхверсиях.

Ссылка на библиотеку:https://github.com/SignalR

Ссылка на описание:https://github.com/SignalR/SignalR/wiki

Ссылка на описание объекта connection:https://github.com/SignalR/SignalR/wiki/SignalR-JS-Client

http://www.slideshare.net/IgorShkulipa 17

Поддерживаемые платформы

SignalR поддерживается наиболее распространенными серверными платформами набазе ОС Windows:

• Windows Server 2012• Windows Server 2008 r2• Windows 8• Windows 7• Windows Azure

Для работы на стороне сервера, также необходима .NET Framework 4.0 и выше.

Поддерживаемые клиентские платформы (браузеры):

• Microsoft Internet Explorer 8, 9 и 10. Версии Modern, Desktop и Mobile• Mozilla Firefox: как на ОС Windows, так и на Mac ОС• Google Chrome: как на ОС Windows, так и на Mac ОС• Safari: как на ОС Windows, так и на Mac ОС• Opera: ОС Windows• Android-браузер

Также следует учитывать, что браузер должен поддерживать библиотекуjQuery 1.6.4 или более поздние версии.

http://www.slideshare.net/IgorShkulipa 18

Модели SignalR

SignalR предоставляет разработчикам две модели: постоянныеподключения (Persistent Connection) и хабы (Hubs).

• Постоянные подключения (Persistent Connection API) представляютразработчикам прямой доступ к низкоуровневому протоколукоммуникации. Подключения в этой модели представляют конечнуюточку, к которой подключаются клиенты, наподобие моделиподключений в WCF.

• Хабы же предоставляют протокол взаимодействия более высокогоуровня. Они представляют верхний слой над Persistent ConnectionAPI и позволяют клиенту и серверу напрямую вызывать методы другдруга.

Если вы будете работать с SignalR, то скорее всего будетепреимущественно использовать хабы, как более удобныеинструменты.

http://www.slideshare.net/IgorShkulipa 19

Архитектура

На сервере реализованы 2 вида API: низкоуровневый (PersistentConnection API) и высокоуровневый (Hub API), причем Hub опираетсяна Persistent Connection.

http://www.slideshare.net/IgorShkulipa 20

Транспортный уровень

SignalR – это абстракция над набором транспортов. Когда пользовательоткрывает страницу, работающую с SignalR, браузер опрашиваетсервер на предмет поддержки разных транспортов и затем пытаетсяподсоединиться по самому оптимальному для данного случаятранспорту. Приоритет выглядит следующим образом:

http://www.slideshare.net/IgorShkulipa 21

Возможности SignalR

SignalR реализует следующие сценарии:

• клиент вызывает метод на сервере• сервер вызывает метод на клиенте/клиентах• передача состояния с клиента на сервер и обратно• поддержка передачи сложных объектов (JSON сериализация)• определение соединения, отсоединения и пересоединения

клиентов• обращение к клиентам извне хаба при помощи специального

интерфейса (то есть любой код на сервере может оповеститьклиентов о событии)

• асинхронные сценарии

http://www.slideshare.net/IgorShkulipa 22

Добавление SignalR в проект

http://www.slideshare.net/IgorShkulipa 23

Пример. Чат.

Сначала создаем свой хаб ChatHub, который наследуется от класса Hub.

Далее определяем методы Send и Connect, которые предназначены для отправкисообщений и добавления новых клиентов.

Формат вызова методов клиента:• Вызов метода на всех клиентах: Clients.All.addMessage(name, message);

• Вызов метода только на текущем клиенте, который обратился к серверу:Clients.Caller.addMessage(name, message);

• Вызов метода на всех клиентах, кроме того, который обратился к серверу:Clients.Others.addMessage(name, message);

• Вызов метода только у клиента с определенным id:Clients.Client(Context.ConnectionId).addMessage(name, message);

• Вызов метода на всех клиентах, кроме клиента с определенным id:Clients.AllExcept(connectionId).addMessage(name, message);

• Вызов метода на всех клиентах указанной группы:Clients.Group(groupName).addMessage(name, message);

• Вызов метода на всех клиентах указанной группы, за исключением клиента, укоторого id - connectionId: Clients.Group(groupName,

connectionId).addMessage(name, message);

• Вызов метода на всех клиентах указанной группы, за исключениемобратившегося к серверу клиента:Clients.OthersInGroup(groupName).addMessage(name, message);

В зависимости от того, кому надо передать сообщение, можно выбрать один извариантов.

http://www.slideshare.net/IgorShkulipa 24

Пример. Хаб

public class ChatUser {

public string ID { get; set; }

public string Name { get; set; }

}

public class ChatHub: Hub {

static List<ChatUser> Users = new List<ChatUser>();

public void Send(string name, string message) {

Clients.All.addMessage(name, message);

Clients.All.addNewMessageToPage(name, message);

}

public void Connect(string userName) {

var id = Context.ConnectionId;

if (Users.Count(x => x.ID == id) == 0) {

Users.Add(new ChatUser { ID = id, Name = userName });

Clients.Caller.onConnected(id, userName, Users);

Clients.AllExcept(id).onNewUserConnected(id, userName);

}

}

}

http://www.slideshare.net/IgorShkulipa 25

Пример. Контроллер

public class HomeController : Controller {

public ActionResult Index() {

ViewBag.Message =

"Modify this template to jump-start your ASP.NET

MVC application.";

return View();

}

public ActionResult About() {

ViewBag.Message = "Your app description page.";

return View();

}

public ActionResult Contact() {

ViewBag.Message = "Your contact page.";

return View();

}

}

http://www.slideshare.net/IgorShkulipa 26

Пример. Index.cshtml

@section scripts {

<script src="~/Scripts/jquery.signalR-1.1.4.min.js">

</script>

<script src="~/signalr/hubs">

</script>

<script src="~/Scripts/MyScripts/chatscript.js">

</script>

}

<div id="globalChatDiv">

</div>

<script>

$(document).ready(function () {

ChatEngine.ShowUI(“#globalChatDiv”);

ChatEngine.Run();

});

</script>

http://www.slideshare.net/IgorShkulipa 27

Пример. chatscript.js. Строки

ChatEngine = {

// Ссылка на ChatHub

ChatHub: $.connection.chatHub,

// Имя пользователя и ID

UserName: "",

UserID: "",

// Айдишники элементов интерфейса

GlobalChatDivID: "",

WelcomeHeaderID: "#welcomeHeader",

LoginDivID: "#loginDiv",

LoginTextBoxID: "#usernameText",

LoginButtonID: "#connectButton",

MainChatDivID: "#mainChatDiv",

InputMessageDivID: "#inputMessageDiv",

InputMessageTextBoxID: "#inputMessageText",

InputMessageButtonID: "#inputMessageButton",

MessagesDivID: "#messagesDiv",

MessagesListID: "#messagesList",

//Заголовки

MainHeaderText: "Chat",

ConnectButtonText: "Connect",

SendButtonText:"Send",

http://www.slideshare.net/IgorShkulipa 28

Пример. chatscript.js. Строки

// Сообщения

UserConnectedMessageText: "New User {0} Connected!",

UserDisconnectedMessageText: "User {0} Disonnected.",

WelcomeMessageText: "Welcome, {0}!",

NewUserConnectedMessageText: "New User {0} Connected!",

ConnectedToHubMessageText: "Connected to Hub!",

InputNameMessageText: "You must input the name!",

InputMessageMessageText: "You must input message!",

http://www.slideshare.net/IgorShkulipa 29

Пример. chatscript.js. Методы генерации элементов HTML

// Генерация пользовательского интерфейса

GetWelcomeHeader: function () {

return String.format("<h2 id=\"{0}\">{1}</h2>",

ChatEngine.WelcomeHeaderID.replace("#", ""),

ChatEngine.MainHeaderText);

},

GetLoginDiv: function () {

return String.format("<div id=\"{0}\" class=\"container\">" +

"<input type=\"text\" id=\"{1}\" />" +

"<input type=\"button\" id=\"{2}\" value=\"{3}\" /></div>",

ChatEngine.LoginDivID.replace("#", ""),

ChatEngine.LoginTextBoxID.replace("#", ""),

ChatEngine.LoginButtonID.replace("#", ""),

ChatEngine.ConnectButtonText.replace("#", ""));

},

http://www.slideshare.net/IgorShkulipa 30

Пример. chatscript.js. Методы генерации элементов HTML

GetMainChatDiv: function () {

return String.format(

"<div id=\"{0}\"><div id=\"{1}\" class=\"container\">" +

"<input type=\"text\" id=\"{2}\" />" +

"<input type=\"button\" id=\"{3}\" value=\"{4}\" /></div>" +

"<div id=\"{5}\" class=\"container\">" +

"<ul id=\"{6}\"></ul\></div></div>",

ChatEngine.MainChatDivID.replace("#", ""),

ChatEngine.InputMessageDivID.replace("#", ""),

ChatEngine.InputMessageTextBoxID.replace("#", ""),

ChatEngine.InputMessageButtonID.replace("#", ""),

ChatEngine.SendButtonText.replace("#", ""),

ChatEngine.MessagesDivID.replace("#", ""),

ChatEngine.MessagesListID.replace("#", ""));

},

// Добавление сообщения

AddMessageToLog: function (name, message) {

$(ChatEngine.MessagesListID).append(String.format(

"<li><strong>{0}</strong>: {1}</li>", name, message));

},

ShowUI: function (divID) {

ChatEngine.GlobalChatDivID = divID;

$(ChatEngine.GlobalChatDivID).html(ChatEngine.GetWelcomeHeader() +

ChatEngine.GetLoginDiv() + ChatEngine.GetMainChatDiv());

},

http://www.slideshare.net/IgorShkulipa 31

Пример. chatscript.js. Метод запуска движка чата

// Запуск "движка"

Run: function () {

$(ChatEngine.MainChatDivID).hide();

$(ChatEngine.LoginDivID).show();

ChatEngine.ChatHub.client.addMessage = ChatEngine.AddMessageToLog;

ChatEngine.ChatHub.client.onConnected = ConnectClient;

ChatEngine.ChatHub.client.onNewUserConnected = UserConnected;

ChatEngine.ChatHub.client.onUserDisconnected = UserDisconnected;

$(ChatEngine.LoginButtonID).click(LoginButtonClick);

$(ChatEngine.InputMessageButtonID).click(SendMessageButtonClick);

}

};

http://www.slideshare.net/IgorShkulipa 32

Пример. chatscript.js. Функции чата

function ConnectClient(id, userName, allUsers) {

$(ChatEngine.LoginDivID).hide();

$(ChatEngine.MainChatDivID).show();

ChatEngine.UserID = id;

ChatEngine.UserName = userName;

$(ChatEngine.WelcomeHeaderID).text(

String.format(ChatEngine.WelcomeMessageText, ChatEngine.UserName));

}

function UserConnected(id, name) {

alert(String.format(ChatEngine.UserConnectedMessageText, name));

}

function UserDisconnected(id, name) {

alert(String.format(UserDisconnectedMessageText, name));

}

http://www.slideshare.net/IgorShkulipa 33

Пример. chatscript.js. Функции чата

function LoginButtonClick() {

ChatEngine.UserName = $(ChatEngine.LoginTextBoxID).val();

if (ChatEngine.UserName.length > 0) {

$.connection.hub.start().done(function () {

ChatEngine.ChatHub.server.connect(ChatEngine.UserName);

alert(ChatEngine.ConnectedToHubMessageText);

});

}

else {

alert(ChatEngine.InputNameMessageText);

}

}

function SendMessageButtonClick() {

var message = $(ChatEngine.InputMessageTextBoxID).val();

if (message.length > 0) {

ChatEngine.ChatHub.server.send(ChatEngine.UserName, message);

$(ChatEngine.InputMessageTextBoxID).val("");

}

else {

alert(ChatEngine.InputMessageMessageText);

}

}

http://www.slideshare.net/IgorShkulipa 34

Пример. chatscript.js. Функция форматирования строк

String.format = function () {

// The string containing the format items (e.g. "{0}")

// will and always has to be the first argument.

var theString = arguments[0];

// start with the second argument (i = 1)

for (var i = 1; i < arguments.length; i++) {

// "gm" = RegEx options for Global search (more than one instance)

// and for Multiline search

var regEx = new RegExp("\\{" + (i - 1) + "\\}", "gm");

theString = theString.replace(regEx, arguments[i]);

}

return theString;

}

Взята отсюда http://jsfiddle.net/joquery/9KYaQ/

http://www.slideshare.net/IgorShkulipa 35

Результат

http://www.slideshare.net/IgorShkulipa 36

Результат

http://www.slideshare.net/IgorShkulipa 37

Результат

http://www.slideshare.net/IgorShkulipa 38

Лабораторная работа № 13.

Лабораторной работе по ASP.NET MVC добавить real-time активность (чат,игра или т.п.).