Что такое код asp accessnoremoteexecute


Содержание

Состояние сеанса

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

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

Но за использование состояния сеанса необходимо платить свою цену. Хотя оно решает многие из проблем, которые возникают в случае применения других технологий управления состояниями, его использование вынуждает веб-сервер сохранять дополнительную информацию в памяти. Необходимость в использовании дополнительных ресурсов памяти сервера, пусть даже в небольшом объеме, очень быстро может достичь угрожающего производительности уровня, когда к сайту начнут получать доступ тысячи клиентов.

Архитектура сеанса

Управление сеансом не является частью HTTP-стандарта. Поэтому для отслеживания информации сеанса и ее привязки к соответствующему ответу ASP.NET приходится выполнять дополнительную работу.

ASP.NET отслеживает каждый сеанс с помощью уникального 120-битового идентификатора. Для генерации этого значения ASP.NET использует патентованный алгоритм, что, согласно статистике, обеспечивает гарантию того, что число будет уникальным и достаточно случайным для того, чтобы злоумышленник не смог воссоздать или угадать идентификатор сеанса, которым будет пользоваться данный клиент. Этот идентификатор является единственным фрагментом информации, который передается между вебсервером и клиентом.

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

При каждом новом запросе ASP.NET генерирует новый идентификатор сеанса до тех пор, пока состояние сеанса не будет фактически использовано для сохранения какой-то информации. Такое поведение позволяет немного увеличить производительность. Коротко это можно объяснить так: зачем тратить время на сохранение идентификатора сеанса, если он не используется?

Когда ASP.NET обрабатывает HTTP-запрос, тот проходит через конвейер различных модулей, которые могут реагировать на события приложения. Одним из модулей в этой цепочке является SessionStateModule (который находится в пространстве имен System.Web.SessionState). Этот модуль генерирует идентификатор сеанса, извлекает из внешних поставщиков состояния данные сеанса и затем привязывает эти данные к контексту вызовов запроса. Он также сохраняет данные состояния сеанса, когда обработка страницы завершается.

Однако важно понимать, что модуль SessionStateModule фактически не хранит данные сеанса. Вместо этого состояние сеанса сохраняется во внешних компонентах, которые называются поставщиками состояния:

Состояние сеанса представляет собой еще один пример сменной архитектуры ASP.NET. Поставщиком состояния может быть любой класс, который реализует интерфейс IHttpSessionState, а это значит, что способ работы состояния сеанса можно настроить, просто создав (или купив) новый .NET-компонент. ASP.NET включает три готовых поставщика состояния, которые позволяют сохранять информацию внутри процесса, в отдельной службе и в базе данных SQL Server.

Чтобы механизм состояния сеанса работал, клиент вместе с каждым запросом должен предоставлять соответствующий идентификатор сеанса. Финальным фрагментом данной головоломки является способ отслеживания этого идентификатора сеанса от одного запроса к другому. Это можно делать двумя способами:

С применением cookie-наборов. В этом случае идентификатор сеанса передается в специальном cookie-наборе (по имени ASP.NET_SessionId), который ASP.NET создает автоматически, когда используется коллекция сеанса. Он применяется по умолчанию и соответствует способу из более ранних версий ASP.

С помощью измененных URL-адресов. В этом случае идентификатор сеанса передается в специально измененном URL-адресе. Это дает возможность создавать приложения, которые используют состояние сеанса для клиентов, не поддерживающих cookie-наборы.

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

Взаимодействовать с состоянием сеанса можно с помощью класса System.Web.SessionState.HttpSessionState, который на веб-странице ASP.NET доступен в виде встроенного объекта Session. Синтаксис для добавления элементов в эту коллекцию и их извлечения выглядит практически так же, как и синтаксис, который используется для добавления элементов в состояние представления страницы.

Например, вот как сохранить объект DataSet в памяти сеанса:

После этого его можно извлечь с помощью соответствующей операции преобразования:

Контекст состояния сеанса охватывает все приложение и является глобальным для текущего пользователя. Данные состояния сеанса могут быть утеряны в следующих случаях:

Если пользователь закрывает и заново запускает браузер.

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

Если сеанс завершается из-за отсутствия активности со стороны пользователя. По умолчанию сеанс автоматически завершается после 20 минут простоя.

Если программист завершает сеанс вызовом метода Session.Abandon().

В первых двух случаях данные состояния сеанса фактически остаются в памяти сервера, потому что веб-сервер не разбирается в том, закрыл клиент окно браузера или открыл новое. Они будут продолжать находиться там, оставаясь недоступным, до тех пор, пока не истечет срок их хранения.

Вдобавок данные состояния сеанса также будут утеряны и в случае повторного создания домена приложения. Этот процесс происходит автоматически при обновлении веб-приложения либо изменении конфигурационных параметров. Домен приложения также может создаваться заново через определенные промежутки времени для поддержания приложения в нормальном работоспособном состоянии. Если такое поведение приводит к возникновению проблем, данные состояния сеанса можно хранить вне процесса. В таком случае они не потеряются даже в результате завершения домена приложения.

В таблице ниже перечислены основные методы и свойства класса HttpSessionState:

Методы и свойства класса HttpSessionState

Метод или свойство Описание
Count Количество элементов в коллекции текущего сеанса
IsCookieless Указывает, как отслеживается этот сеанс: с помощью cookie-набора или с использованием измененных URL-адресов
IsNewSession Указывает, был ли данный сеанс только что создан для текущего запроса. Если в состоянии сеанса на текущий момент не содержится никакой информации, ASP.NET не будет беспокоиться ни об отслеживании сеанса, ни о создании cookie-набора сеанса. Вместо этого сеанс будет воссоздаваться заново при каждом запросе
Mode Предоставляет перечислимое значение, которое объясняет, как ASP.NET хранит информацию о состоянии сеанса. Этот режим хранения определяется на основе указанных в файле web.config конфигурационных настроек
SessionID Предоставляет строку с уникальным идентификатором сеанса для текущего клиента
StaticObjects Предоставляет коллекцию элементов сеанса, предназначенных только для чтения, которые были объявлены в global.asax с помощью дескрипторов . В основном эта технология не используется и является пережитком ASP-программирования; она поддерживается для обратной совместимости
Timeout Текущее количество минут, которое должно пройти, прежде чем текущий сеанс будет завершен при условии отсутствия запросов от клиента. Это значение может изменяться программно, что дает возможность при необходимости продлевать срок жизни коллекции сеанса для более важных операций
Abandon() Немедленно завершает текущий сеанс и освобождает все занятые им ресурсы памяти. Такая технология полезна на автономных страницах, поскольку позволяет освобождать ресурсы памяти сервера настолько быстро, насколько возможно
Clear() Удаляет все элементы сеанса, но не изменяет идентификатор текущего сеанса

Конфигурирование состояния сеанса

Сконфигурировать состояние сеанса можно с помощью элемента в файле web.config. Ниже показаны все доступные параметры настройки, которые можно применять:

Атрибуты сеанса подробно описаны в последующих разделах.

Параметр настройки состояния сеанса Mode позволяет указать, какой поставщик состояния сеанса должен использоваться для хранения данных состояния сеанса между запросами. Допустимые значения перечислены ниже:

Off

Установка значения Off отключает управление состоянием сеанса для всех страниц в приложении. Это может немного увеличить производительность веб-сайтов, которые не используют состояние сеанса.

InProc

Установка значения InProc напоминает подход, который использовался для хранения состояния сеанса в классической версии ASP. Это значение указывает ASP.NET хранить информацию в текущем домене приложения, что обеспечивает наилучшую производительность, но наименьший срок хранения: если вы перезапустите сервер, данные состояния будут утеряны.

Значение InProc используется по умолчанию и подходит для большинства веб-сайтов небольшого размера. Однако в сценарии веб-фабрики от него не будет никакого толку. Чтобы состояние сеанса совместно использовалось множеством серверов, необходимо применять внепроцессный поставщик или службу состояний SQL Server.

Еще одна причина, по которой установка значения InProc может быть нежелательной, состоит в том, что она приводит к получению более «хрупких» сеансов. В ASP.NET домены приложений создаются заново в ответ на различные действия, включая изменения конфигурационных настроек, обновления страниц, а также достижение определенных пороговых значений (независимо от того, произошла ошибка или нет). Если вы обнаружите, что домен приложения часто перезапускается, что приводит к преждевременному завершению сеансов, можете воспользоваться одним из более надежных поставщиков состояния сеанса.

StateServer

В случае установки этого значения ASP.NET будет использовать для управления состоянием отдельную Windows-службу. Даже при запуске на том же самом веб-сервере эта служба будет загружаться за пределами главного процесса ASP.NET, что обеспечивает для нее базовый уровень защиты, когда возникает необходимость перезапуска процесса ASP.NET. Недостаток такого подхода в том, что из-за передачи данных состояния между двумя процессами увеличивается время задержки. Если доступ к данным сеанса получается часто, и они часто изменяются, работа может существенно замедлиться.

Выбрав режим StateServer, обязательно следует указать значение для параметра stateConnectionString. Эта строка сообщает TCP/IP-адрес компьютера, на котором запускается служба StateServer, и номер его порта (который определяется ASP.NET и который обычно изменять не нужно), что позволяет обслуживать службу StateServer на другом компьютере. Если не изменить значение этого параметра, использоваться будет локальный сервер (с адресом 127.0.0.1).

Разумеется, эта служба должна быть запущена, чтобы приложение могло с ней взаимодействовать. Проще всего это сделать с помощью консоли управления Microsoft (Microsoft Management Console). Выберите в меню Start (Пуск) пункт Programs Administrative Tools Computer Management (Все программы Администрирование Управление компьютером) или же откройте окно панели управления, щелкните на значке Administrative Tools (Администрирование), а затем на значке Computer Management (Управление компьютером). В появившемся диалоговом окне Computer Management (Управление компьютером) разверните узел Services and Applications (Службы и приложения) и щелкните на элементе Services (Службы). В правой части окна появится список служб: отыщите в нем службу по имени ASP.NET State Service:

Отыскав службу в списке, вы можете вручную запустить или остановить ее с помощью щелчка правой кнопкой мыши. Обычно имеет смысл сконфигурировать ОС Windows так, чтобы эта служба запускалась автоматически. Для этого щелкните на имени службы правой кнопкой мыши, в появившемся контекстном меню выберите пункт Properties (Свойства). После этого в списке Startup Type (Тип запуска) выберите значение Automatic (Автоматически), как показано на рисунке ниже. Далее щелкните на кнопке Start (Запустить), чтобы запустить эту службу немедленно.

Используя режим StateServer, можно также установить значение для необязательного атрибута stateNetworkTimeout, задающего максимальное количество секунд, в течение которых должен ожидаться ответ от службы, прежде чем запрос будет отменен. По умолчанию это значение равно 10 секунд.

SQLServer

Это значение заставляет ASP.NET использовать для хранения информации о сеансе базу данных SQL Server, применяя параметры, определенные в атрибуте sqlConnectionString. Такой способ управления состоянием является наиболее удобным, но пока что самым медленным. Чтобы его можно было использовать, на сервере должна быть установлена система SQL Server.

Установка значения для атрибута sqlConnectionString выполняется по схеме, подобной той, что применяется для получения доступа к данным ADO.NET. В целом это подразумевает указание источника данных (адреса сервера), имени пользователя и пароля, если только не используется интегрированная система безопасности SQL.

Вдобавок также должны быть установлены специальные хранимые процедуры и временные базы данных сеансов. Эти хранимые процедуры будут отвечать за сохранение и извлечение данных сеанса. В состав ASP.NET входит утилита командной строки, позволяющая выполнять эту задачу автоматически. Называется она aspnet_regsql.exe и находится в каталоге c:\Windows\Microsoft.NET\Framework\[Версия].


Удобнее всего запускать ее в окне командной строки Visual Studio (выберите в меню Start (Пуск) пункт Programs Microsoft Visual Studio 2012 Visual Studio Tools Visual Studio 2012 Command Prompt. Затем можно сразу же вводить команду aspnet_regsql.exe независимо от того, в каком каталоге она открыта.

Утилита aspnet_regsql.exe может применяться для решения нескольких связанных с базами данных задач. Чтобы использовать ее для создания базы данных с хранилищем сеансов, нужно указать параметр -ssadd. Кроме того, параметр -S позволяет указать имя сервера базы данных, а параметр -Е — что для подключения к этой базе данных должна использоваться учетная запись текущего пользователя Windows.

Ниже показана команда, которая создает базу данных для хранения данных сеанса на текущем компьютере, используя для нее стандартное имя ASPState:

В этой команде используется псевдоним localhost, который указывает aspnet_regsql.exe подключаться к серверу баз данных на текущем компьютере. Но вместо этого псевдонима может использоваться имя любого другого компьютера, на котором находится нужный сервер баз данных.

После создания базы данных состояния сеанса необходимо указать ASP.NET ее использовать, внеся соответствующие изменения в раздел файла web.config. Если для хранения информации о состоянии сеанса была создана база данных ASPState (это принято по умолчанию), тогда предоставлять ее имя в разделе не нужно. Вместо этого следует указать место размещения сервера и тип аутентификации, который ASP.NET должна применять для подключения к этому серверу:

На этом процедура настройки завершена. Однако если нужно использовать постоянные сеансы или специальную базу данных, эти шаги могут быть немного изменены, как будет показано далее.

Для удаления базы данных ASPState используйте параметр -ssremove.

Обычно при управлении состоянием с помощью SQL Server по-прежнему действует стандартный параметр тайм-аута состояния сеанса. Причина в том, что утилита aspnet_regsql.exe также создает для SQL Server новое задание по имени ASPState_Job_DeleteExpiredSessions. До тех пор, пока работает служба SQLServerAgent, это задание будет выполняться каждую минуту.

Кроме того, при каждом перезапуске сервера SQL Server, независимо от значения тайм-аута сеанса, будут удаляться таблицы данных состояния. Дело в том, что таблицы информации о состоянии создаются в базе данных tempdb, которая является всего лишь временным хранилищем. Если такое поведение не подходит, можно указать утилите aspnet_regsql.exe установить в базе данных ASPState постоянные таблицы данных состояния. Для этого понадобится использовать параметр -sstype p (где p означает «persisted» (постоянный)). Ниже показана модифицированная версия предыдущей команды:

Теперь записи сеанса будут оставаться в базе данных даже в случае перезапуска SQL Server.

И, наконец, последний вариант: утилиту aspnet_regsql.exe также можно применять для создания таблиц данных состояния в какой-то другой базе данных (отличной от ASPState). Для этого применяется параметр -sstype c (где c означает «custom» (специальный)) и указывается имя базы данных в параметре -d:

При таком подходе таблицы данных сеанса будут сразу же созданы как постоянные, так что содержащиеся в них записи будут оставаться даже после перезапуска SQL Server.

В случае использования специальной базы данных также потребуется выполнить две конфигурационные настройки в разделе файла web.сonfig. Во-первых, необходимо установить атрибут allowCustomSqlDatabase в true. Во-вторых, понадобится добавить в строку соединения параметр InitialCatalog с именем используемой базы данных. Ниже показан должным образом настроенный элемент :

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

Custom

Выбор специального (Custom) режима требует указания используемого поставщика хранилища данных о состоянии сеанса с помощью атрибута customProvider. В атрибуте customProvider может быть задано как имя класса, являющегося частью веб-приложения и хранящегося в каталоге App_Code, так и имя класса, входящего в состав скомпилированной сборки и хранящегося в каталоге Bin или в глобальном кэше сборок (GAC).

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

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

Сжатие

В ASP.NET доступно средство сжатия, которое позволяет сократить размер сериализируемых данных сеанса. Если установить атрибут enableCompression в true, данные сеанса перед отправкой за пределы процесса будут сжиматься (с использованием класса System.IO.Compression.GZipStream). Параметр enableCompression действует только при использовании внепроцессного хранилища состояния сеанса, поскольку только в такой ситуации данные сериализируются.

Для сжатия и восстановления данных сеанса веб-сервер должен выполнять дополнительную работу. Однако обычно это никакой проблемы не представляет, т.к. сжатие применяется лишь в тех сценариях, когда веб-серверы имеют массу лишнего времени ЦП, но ограничены по каким-то другим показателям. Сжатие данных состояния сеанса имеет смысл в описанных двух ключевых ситуациях:

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

При сохранении данных состояния сеанса данных на другом компьютере. В некоторых веб-приложениях с высокой степенью масштабируемости состояние сеанса сохраняется за пределами процесса (обычно в базе данных SQL Server) или на отдельном компьютере. Из-за этого среда ASP.NET должна передавать информацию сеанса туда и обратно через сетевое соединение. Очевидно, что при таком проектном решении показатели производительности будут значительно ниже, чем при сохранении состояния сеанса на компьютере веб-сервера. Однако для некоторых веб-приложений, с высоким трафиком и большими потребностями в плане сохранения данных состояния сеанса это решение все равно может быть лучшим компромиссом.

В первом случае сжатие позволяет жертвовать ресурсами ЦП во имя экономии памяти веб-сервера, а во втором — ради сокращения нагрузки на сетевое соединение. Степень сжатия существенно варьируется в зависимости от типа данных, но во время тестирования клиентам Microsoft удавалось достигать сокращения размеров данных на 30-60% , что гарантирует значительный выигрыш в производительности.

Cookieless

Параметр Cookieless может быть установлен в любое из значений перечисления HttpCookieMode. С помощью атрибута cookieName можно указать имя, используемое для cookie-набора. Если оно не указано, для имени cookie-набора принимается значение по умолчанию, которое выглядит как ASP.NET_SessionId.

Значения, доступные в перечислении HttpCookieMode

Значение Описание
UseCookies Cookie-наборы используются всегда, даже если браузер или устройство не поддерживает их или если они были отключены. Это значение устанавливается по умолчанию. Если устройство не поддерживает cookie-наборы, информация сеанса будет утрачиваться при последующих запросах, потому что каждый запрос будет получать новый идентификатор
UseUriCookie Cookie-наборы не используются никогда, независимо от возможностей браузера или устройства. Вместо этого идентификатор сеанса сохраняется в URL-адресе
UseDeviceProfile ASP.NET решает, какие сеансы использовать (с поддержкой cookie-наборов или без), анализируя содержимое объекта BrowserCapabilities. Недостаток такого подхода заключается в том, что этот объект указывает, что устройство должно поддерживать: он не учитывает того факта, что пользователь мог отключить cookie-наборы в браузере, который в принципе их поддерживает
AutoDetect ASP.NET пытается определить, поддерживает ли браузер cookie-наборы, пробуя установить и извлечь cookie-набор. Эта широко используемая технология позволяет точно определить, когда браузер поддерживает cookie-наборы, но это средство было отключено, указывая ASP.NET применять режим без поддержки cookie-наборов

Ниже приведен пример принудительного применения режима без поддержки cookie-наборов (что удобно для целей тестирования):

В режиме без поддержки cookie-наборов идентификатор сеанса будет автоматически вставляться в URL-адрес. Получив запрос, ASP.NET будет удалять идентификатор, извлекать коллекцию сеанса и направлять запрос в соответствующий каталог. Измененный URL-адрес показан ниже:

Поскольку идентификатор сеанса вставляется в текущий URL-адрес, все относительные ссылки также автоматически получают этот идентификатор сеанса. Другими словами, если пользователь на текущий момент находится на странице Page1.aspx и щелкает на относительной ссылке, указывающей на страницу Page2.aspx, эта относительная ссылка будет включать текущий идентификатор сеанса как часть URL-адреса. То же самое произойдет и если вызвать метод Response.Redirect() с относительным URL-адресом.

Единственное реальное ограничение режима без поддержки cookie-наборов состоит в том, что с ним нельзя применять абсолютные ссылки, потому что они не будут содержать идентификатора сеанса. Например, выполнение следующего оператора приведет к утрате пользователем всей информации о сеансе:

По умолчанию ASP.NET допускает повторное использование идентификатора сеанса. Например, если делается запрос и строка запроса содержит просроченный сеанс, ASP.NET создает новый сеанс и использует этот же идентификатор сеанса. Проблема в том, что идентификатор сеанса может случайно появиться в каком-то публичном месте, например, на странице результатов в поисковой службе. Это может привести к тому, что множество пользователей получат доступ к серверу с одним и тем же идентификатором сеанса и затем присоединятся к одному и тому же сеансу с теми же самыми разделяемыми данными.

Во избежание такой потенциальной угрозы безопасности, рекомендуется включать в код необязательный атрибут regenerateExpiredSessionId и устанавливать его в true при использовании сеансов без cookie-наборов. В этом случае при подключении пользователя с просроченным идентификатором сеанса будет генерироваться новый идентификатор сеанса.

Единственный недостаток такого подхода состоит в том, что он подразумевает утерю всех данных состояния представления и формы на текущей странице, т.к. для обеспечения нового идентификатора сеанса ASP.NET выполняет переадресацию браузера.

Чтобы выяснить, используется ли в текущий момент сеанс без cookie-наборов, необходимо проверить свойство IsCookieless объекта Session.

Timeout

Еще одним важным параметром настройки состояния сеанса в файле web.config является Timeout. Он указывает количество минут, в течение которых ASP.NET будет находиться в режиме ожидания (не получая запрос), прежде чем завершит сеанс:

Илон Маск рекомендует:  Что такое код fbsql_list_tables

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

Значение параметра Timeout можно также изменять в коде. Например, если известно, что сеанс содержит чрезвычайно большое количество информации, время хранения сеанса лучше ограничить. Для этого можно отобразить пользователю соответствующее предупредительное сообщение и затем просто изменить значение свойства Timeout. Следующая строка кода ограничивает время тайм-аута до 10 минут:

Обеспечение безопасности состояния сеанса

Данные в состоянии сеанса хорошо защищены, т.к. они хранятся исключительно на сервере. Однако cookie-набор и идентификатор сеанса крайне уязвимы. Это означает, что злоумышленник может похитить cookie-набор и инициировать сеанс на другом компьютере.

Существует несколько подходов, позволяющих обойти эту проблему. Наиболее распространенный из них — воспользоваться специальным модулем сеанса, выполняющим проверку на наличие изменений в IP-адресе клиента. Однако единственным действительно безопасным подходом является разрешение доступа к cookie-наборам сеанса только из тех разделов веб-сайта, где используется SSL-шифрование. В таком случае cookie-набор сеанса шифруется и, следовательно, становится бесполезным на других компьютерах.

Если решено воспользоваться этим подходом, также имеет смысл пометить cookie-набор как безопасный, чтобы он пересылался только через SSL-соединения. Это не позволит пользователям изменять URL-адрес с https:// на http:// и, следовательно, пересылать cookie-набор без SSL-шифрования. Ниже показан необходимый код:

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

При использовании сеансов без cookie-наборов существует еще одна потенциальная угроза нарушения системы безопасности. Даже если идентификатор сеанса зашифрован, применив прием социальной инженерии, сообразительный пользователь может вынудить другого пользователя подключиться к определенному сеансу. Все, что злоумышленнику понадобится — это подсунуть другому пользователю URL-адрес с действительным идентификатором сеанса. Щелкнув на ссылке, этот пользователь сразу же подключится к такому сеансу. Хотя с этого момента идентификатор сеанса будет защищаться, атакующему уже известно, какой идентификатор сеанса используется, поэтому он сможет позже взломать этот сеанс.

Чтобы снизить возможность такой атаки, необходимо выполнить ряд определенных шагов. Во-первых, при использовании сеансов без cookie-наборов всегда устанавливайте атрибут regenerateExpiredSessionId в true. Это не позволит злоумышленнику предоставлять просроченный идентификатор сеанса. Во-вторых, явно прекращайте текущий сеанс перед входом в систему нового пользователя.

ASP.NET Core — Написание ясного кода в ASP.NET Core с использованием встраивания зависимостей

Эта статья основана на ASP.NET Core 1.0 предварительной версии RC1. Некоторая информация может быть изменена при выпуске версии RC2.


Продукты и технологии:

ASP.NET Core 1.0

В статье рассматриваются:

  • примеры жесткого связывания;
  • написание «честных» классов;
  • встраивание зависимостей в ASP.NET Core;
  • код с возможностью модульного тестирования;
  • тестирование обязанностей контроллера.

ASP.NET Core 1.0 является полностью переписанной ASP.NET, и одной из основных целей в этой новой инфраструктуре является более модульная архитектура. То есть приложения должны иметь возможность использовать только те части инфраструктуры, которые им нужны, причем инфраструктура предоставляет зависимости по мере того, как они запрашиваются. Более того, разработчики, создающие приложения на основе ASP.NET Core, должны иметь возможность использовать ту же функциональность, чтобы поддерживать свои приложения свободно связанными и модульными. С появлением ASP.NET MVC группа ASP.NET значительно улучшила поддержку со стороны инфраструктуры в написании свободно связанного кода, но все равно было очень легко попасть в ловушку жесткого связывания, особенно в классах контроллеров.

Жесткое связывание

Жесткое связывание (tight coupling) хорошо подходит для демонстрационного программного обеспечения. Если вы посмотрите на типичное приложение-пример, показывающее, как создавать сайты на основе ASP.NET MVC (версий 3–5), то скорее всего найдете код, подобный следующему (взят из класса DinnersController приложения-примера NerdDinner, использующего MVC 4):

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

Этот тип кода очень сложен в модульном тестировании, потому что NerdDinnerContext создается в процессе конструирования класса и требует подключения к базе данных. Неудивительно, что такие демонстрационные приложения нечасто включают какие-либо модульные тесты. Однако ваше приложение может выиграть от нескольких модульных тестов, даже если вы не занимаетесь разработкой на основе тестов, так что было бы лучше писать код, который можно было бы протестировать. Более того, этот код нарушает принцип Don’t Repeat Yourself (DRY) (принцип «не повторяйся»), поскольку каждый класс контроллера, так или иначе обращающийся к данным, содержит один и тот же код для создания EF-контекста базы данных (Entity Framework). Это делает внесение будущих изменений более дорогостоящим и подверженным ошибкам, особенно по мере развития приложения в течение длительного времени.

Глядя на код, чтобы оценить степень его связывания, помните фразу «new является связующим». То есть везде, где экземпляр класса создается с помощью ключевого слова new, ваша реализация связывается конкретно с этим кодом реализации. Dependency Inversion Principle (принцип инверсии зависимостей) (bit.ly/DI-Principle) утверждает: «Абстракции не должны зависеть от деталей — детали должны зависеть от абстракций». В этом примере детали того, как контроллер извлекает данные для передачи представлению, зависят от деталей того, как эти данные извлекаются, а именно от EF.

Вдобавок к ключевому слову new «статическое сцепление» является еще одним источником жесткого связывания, которое затрудняет тестирование и сопровождение приложений. В предыдущем примере имеется зависимость от системных часов компьютера в виде вызова DateTime.Now. Это связывание усложнило бы создание набора тестовых Dinners для использования в некоторых модульных тестах, так как их свойства EventDate пришлось бы устанавливать относительно текущему показанию часов. Это связывание можно было бы удалить из данного метода несколькими способами, самый простой из которых — переложить заботу об этом на какую-то новую абстракцию, возвращающую Dinners, чтобы это больше не было частью метода. В качестве альтернативы я мог бы сделать значение параметром, чтобы метод возвращал все Dinners после предоставленного параметра DateTime вместо использования только DateTime.Now. Наконец, можно было бы создать абстракцию для текущего времени и ссылаться на текущее время через эту абстракцию. Это может оказаться хорошим подходом, если приложение часто ссылается на DateTime.Now. (Кроме того, заметьте, что, поскольку эти обеды [dinners] предположительно происходят в разных часовых поясах, тип DateTimeOffset может быть более эффективным выбором в реальном приложении.)

Будьте честны

Другая проблема с сопровождением кода вроде этого — он нечестен со взаимодействующими с ним объектами. Вы должны избегать написания классов, экземпляры которых можно создавать в недопустимых состояниях, так как это является частым источником ошибок. Таким образом, все, что необходимо вашему классу для выполнения своих задач, должно предоставляться через его конструктор. Как утверждает Explicit Dependencies Principle (принцип явных зависимостей) (bit.ly/ED-Principle), «методы и классы должны явным образом требовать любые взаимодействующие объекты (collaborating objects), нужные им для корректной работы». Класс DinnersController имеет лишь конструктор по умолчанию, а это подразумевает, что ему не надо взаимодействовать с какими-либо объектами для корректной работы. Но что будет, если вы подвергнете его тесту? Что сделает этот код, если вы запустите его из нового консольного приложения, которое ссылается на MVC-проект?

Первое, что не удастся в этом случае, — попытка создать экземпляр EF-контекста. Код сгенерирует исключение InvalidOperationException: «No connection string named ‘NerdDinnerContext’ could be found in the application config file.» (в конфигурационном файле приложения не найдена строка подключения с именем ‘NerdDinnerContext’). Меня обманули! Для работы этому классу нужно больше, чем заявляет его конструктор! Если классу необходим какой-то способ доступа к наборам экземпляров Dinner, он должен запрашивать их через свой конструктор (или как параметры в своих методах).

Встраивание зависимостей

Встраивание зависимостей (dependency injection, DI) относится к передаче зависимостей класса или метода в виде параметров вместо «зашивания» в код этих связей через new или статические вызовы. Это набирающий популярность метод в .NET-разработке из-за обеспечения им разъединения приложений, в которых он применяется. В ранних версиях ASP.NET преимущества DI не использовались, и, хотя в ASP.NET MVC и Web API наблюдается прогресс в отношении его поддержки, ни одна из инфраструктур до сих пор не предоставляет полной поддержки, в том числе контейнер для управления зависимостями и жизненными циклами их объектов. В ASP.NET Core 1.0 DI не просто полностью поддерживается — оно повсеместно применяется в самом продукте.

В ASP.NET Core 1.0 DI не просто полностью поддерживается — оно повсеместно применяется в самом продукте.

ASP.NET Core не только поддерживает DI, но и включает DI-контейнер, также называемый контейнером Inversion of Control (IoC) или контейнером сервисов. Каждое приложение ASP.NET Core конфигурирует свои зависимости, используя этот контейнер, в методе ConfigureServices класса Startup. Данный контейнер обеспечивает необходимую базовую поддержку, но может быть заменен пользовательской реализацией, если в этом есть потребность. Более того, EF Core также имеет встроенную поддержку DI, поэтому ее конфигурирование в приложении ASP.NET Core сводится к простому вызову метода расширения. Для этой статьи я создал ответвление NerdDinner с именем GeekDinner. EF Core конфигурируется, как показано ниже:

После этого довольно легко запросить через DI экземпляр GeekDinnerDbContext от класса контроллера вроде DinnersController:

Заметьте, что нет ни одного экземпляра ключевого слова new; все зависимости, нужные контроллеру, передаются через его контроллер, и заботится об этом за меня DI-контейнер ASP.NET. В процессе написания приложения мне незачем беспокоиться об инфраструктуре, участвующей в разрешении зависимостей, запрашиваемых моими классами через свои конструкторы. Конечно, при желании можно изменить это поведение, даже заменить контейнер по умолчанию другой реализацией. Поскольку теперь мой класс контроллера следует принципу явных зависимостей, я знаю, что для его работы нужно предоставить экземпляр GeekDinnerDbContext. Выполнив небольшую подготовку для DbContext, я могу создать экземпляр контроллера сам по себе, как демонстрирует это консольное приложение:

При конструировании DbContext в EF Core требуется несколько больше работы, чем в EF6, где просто принималась строка подключения. Дело в том, что, как и ASP.NET Core, EF Core спроектирован в расчете на большую модульность. Обычно вам не понадобится иметь дело напрямую с DbContextOptionsBuilder, так как он используется «за кулисами», когда вы конфигурируете EF через методы расширения вроде AddEntityFramework и AddSqlServer.

А можно ли это протестировать?

Тестирование приложения вручную является важным — вам нужна возможность запустить его и убедиться, что оно действительно запускается и дает ожидаемый вывод. Но поступать так всякий раз, когда вносится какое-то изменение, — пустая трата времени. Одно из значимых преимуществ свободно связанных приложений в том, что они, как правило, лучше поддаются модульному тестированию, чем жестко связанные. Еще важнее, что ASP.NET Core и EF Core гораздо проще в тестировании, чем их предшественники. Для начала я напишу простой тест, который напрямую передает в контроллер какой-то DbContext, который был сконфигурирован на использование хранилища в памяти. Я настрою GeekDinnerDbContext, используя параметр DbContextOptions, который предоставляется этим контекстом через конструктор:

Сконфигурировав это в тестовом классе, легко написать тест, показывающий, что Model в ViewResult возвращает корректные данные:

Конечно, здесь пока что мало логики для тестирования, поэтому данный тест ничего особенного и не проверяет. Критики возразили бы, что этот тест малозначим, и я согласился бы с ними. Однако это отправная точка для будущего теста, когда появится больше логики, что и будет сделано в самом ближайшем будущем. Но сначала, хоть EF Core и поддерживает модульное тестирование в памяти, я все же позабочусь о предотвращении прямого связывания с EF в своем контроллере. Нет никаких причин для связывания обязанностей UI с обязанностями инфраструктуры доступа к данным — по сути, это нарушило бы другой принцип, Separation of Concerns (принцип разделения обязанностей).

Избегайте зависимости от того, что не используется

Принцип отделения интерфейса (Interface Segregation Principle) (bit.ly/LS-Principle) утверждает, что классы должны зависеть только от той функциональности, которую они действительно используют. В случае нового DinnersController с поддержкой DI тот по-прежнему зависит от всего DbContext. Вместо склеивания реализации контроллера с EF можно было бы задействовать некую абстракцию, которая предоставляла бы необходимую функциональность.

Что на самом деле нужно этому методу действия (action method) для должного функционирования? Определенно не весь DbContext. Ему даже не требуется доступ к полному свойству Dinners контекста. Ему достаточно возможности отображать экземпляры Dinner соответствующей страницы. Простейшая .NET-абстракция, представляющая это, — IEnumerable . Поэтому я определю интерфейс, который просто возвращает IEnumerable , и это удовлетворит (большую часть) требований метода Index:

Я называю это репозитарием, поскольку он следует такому шаблону: он абстрагирует доступ к данным интерфейсом, подобным набору. Если по какой-то причине вам не нравится шаблон репозитария или имя, вы можете назвать его IGetDinners, IDinnerService или как угодно иначе (мой рецензент предложил ICanHasDinner). Независимо от того, как вы назовете этот тип, он будет служить той же цели.

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

Покончив с этим, теперь подстроим DinnersController для приема IDinnerRepository в качестве параметра конструктора вместо GeekDinnerDbContext и вызова метода List вместо прямого обращения к Dinners DbSet:

К этому моменту можно скомпилировать и запустить ваше веб-приложение, но вы столкнетесь с исключением, если перейдете к /Dinners: InvalidOperationException («Unable to resolve service for type ‘GeekDinner.Core.Interfaces.IdinnerRepository’ while attempting to activate GeekDinner.Controllers.DinnersController.») («Не удалось разрешить сервис для типа ‘GeekDinner.Core.Interfaces.IdinnerRepository’ при попытке активировать GeekDinner.Controllers.DinnersController.»). Я пока что не реализовал интерфейс, и, как только это будет сделано, мне также понадобится сконфигурировать свою реализацию для использования, когда DI будет выполнять запросы к IDinnerRepository. Реализация этого интерфейса тривиальна:

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

Чтобы сконфигурировать ASP.NET Core на встраивание правильной реализации, когда классы запрашивают IDinnerRepository, нужно добавить следующую строку кода в конец ранее показанного метода ConfigureServices:

Это выражение инструктирует DI-контейнер ASP.NET Core использовать экземпляр DinnerRepository всякий раз, когда требуется разрешить тип, зависимый от экземпляра IDinnerRepository. Scoped означает, что для каждого веб-запроса, обрабатываемого ASP.NET, будет использоваться один экземпляр. Также можно добавлять сервисы, указывая жизненные циклы Transient или Singleton. В данном случае подходит Scoped, поскольку мой DinnerRepository зависит от DbContext, который тоже использует жизненный цикл Scoped. Вот краткое описание доступных сроков жизни объектов.

  • Transient Используется новый экземпляр типа всякий раз, когда запрашивается этот тип.
  • Scoped При первом запросе в рамках данного HTTP-запроса создается новый экземпляр типа, а затем он повторно используется для всех последующих типов, разрешаемых при этом HTTP-запросе.
  • Singleton Единственный экземпляр типа создается один раз и используется всеми последующими запросами для этого типа.

Встроенный контейнер поддерживает несколько способов конструирования типов, которые он будет предоставлять. Самый типичный случай — простая передача типа контейнеру, после чего тот попытается создать экземпляр этого типа, предоставляя ему любые зависимости, которые тип запрашивает по мере выполнения. Вы также можете указать лямбда-выражение для конструирования типа или — в случае жизненного цикла Singleton — передать полностью сконструированный экземпляр в ConfigureServices при его регистрации.

После подключения DI приложение выполняется, как и раньше. Теперь, как показано на рис. 1, я могу тестировать его с применением новой абстракции, используя имитацию или заглушку реализации интерфейса IDinnerRepository вместо того, чтобы напрямую полагаться на EF в коде теста.

Рис. 1. Тестирование DinnersController, используя имитирующий объект

Этот тест работает независимо от того, откуда берется список экземпляров Dinner. Вы могли бы переписать код для доступа к данным, чтобы использовать другую базу данных, Azure Table Storage или XML-файлы, а контроллер все равно работал бы точно так же. Конечно, в данном случае он не делает ничего особенного, поэтому вам, возможно, интересно…

А как насчет реальной логики?

До сих пор я не реализовал никакой реальной бизнес-логики — у меня были лишь простые методы, возвращающие несложные наборы данных. Истинная ценность тестирования проявляется только при наличии логики и особых случаев, в которых вы должны убедиться, что приложение будет вести себя ожидаемым образом. Чтобы продемонстрировать это, я добавлю некоторые требования к своему сайту GeekDinner. Сайт будет предоставлять API, который позволит кому угодно отвечать на приглашение на обед. Однако для числа приглашаемых будет дополнительно задан максимум, и количество ответов на приглашение (RSVP) не должно превышать этот максимум. Пользователи, запрашивающие RSVP, когда максимум уже достигнут, должны добавляться в список ожидания. Наконец, желающие пообедать могут указывать крайний срок относительно их начального времени, по истечении которого они не станут принимать приглашения.

Я мог бы закодировать всю эту логику в метод действия (action), но считаю, что тогда на один метод было бы возложено слишком много обязанностей, особенно на UI-метод, который должен концентрироваться на задачах, связанных с UI, а не на бизнес-логике. Контроллер должен проверять, что ему передаются допустимые входные аргументы, и гарантировать возврат ответов, подходящих для клиента. Решения, выходящие за рамки этих обязанностей, и особенно бизнес-логика не относятся к компетенции контроллеров.

Лучшее место для размещения бизнес-логики — модель предметной области приложения, которая не должна зависеть от обязанностей инфраструктуры (вроде работы с базами данных или UI). Класс Dinner подходит для управления RSVP, описанными в требованиях, поскольку он будет хранить максимальное количество участников мероприятия и знать, сколько RSVP было выдано на данный момент. Однако часть логики также зависит от того, когда появляется RSVP (до или после крайнего срока), поэтому методу понадобится доступ к текущему времени.

Я мог бы просто использовать DateTime.Now, но это затруднило бы тестирование моей логики и связало бы модель предметной области с системными часами. Другой вариант — задействовать абстракцию IDateTime и встроить ее в сущность Dinner. Однако, как показывает мой опыт, лучше всего сохранять сущности вроде Dinner свободными от зависимостей, особенно если вы планируете применять какое-то O/RM-средство наподобие EF для извлечения этих сущностей с уровня хранения. В связи с этим я не хочу заполнять сущности зависимостями, да и EF определенно не смогла бы иметь с этим дело без дополнительного кода с моей стороны. Распространенный подход — изъятие логики из сущности Dinner и перенос ее в какой-либо сервис (вроде DinnerService или RsvpService), в который можно легко встраивать зависимости. Однако это обычно приводит к антишаблону анемичной модели предметной области (anemic domain model antipattern) (bit.ly/anemic-model), в которой сущности имеют очень мало логики (или вообще не имеют ее) и являются просто контейнерами состояния. Нет, в данном случае решение прямолинейное: метод может просто принимать текущее время как параметр и позволять вызывающему коду передавать его.

При таком подходе логика добавления RSVP проста (рис. 2). Для этого метода есть ряд тестов, которые демонстрируют, что он ведет себя, как ожидалось; тесты доступны в проекте-примере, сопутствующем этой статье.


Рис. 2. Бизнес-логика в модели предметной области

Переместив эту логику в модель предметной области, я добился того, что API-метод моего контроллера останется компактным и сконцентрированным на собственных обязанностях. В итоге можно легко протестировать, что контроллер делает то, что ему положено, поскольку через этот метод проходит сравнительно немного путей выполнения.

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

Часть обязанностей контроллера — проверка ModelState и обеспечение его допустимости. Для ясности я делаю это в методе действия, но в более крупном приложении я исключил бы этот повторяющийся код в каждом методе действия, используя Action Filter:

Предполагая, что ModelState допустим, метод действия должен извлечь соответствующий экземпляр Dinner по идентификатору, переданному в запросе. Если метод не может найти экземпляр Dinner с совпадающим идентификатором, он должен вернуть результат Not Found:

По завершении этих проверок метод действия может делегировать бизнес-операцию, представленную запросом, модели предметной области, вызвав метод AddRsvp класса Dinner, который вы видели ранее, и сохранив обновленное состояние модели предметной области (в данном случае экземпляр dinner и его набор RSVP); после этого он возвращает ответ OK:

Вспомните: я решил, что у класса Dinner не должно быть зависимости от системных часов, и предпочел передавать текущее время в его метод. В контроллере я передаю _systemClock.Now как параметр currentDateTime. Это локальное поле, заполняемое через DI, что избавляет и контроллер от жесткого связывания с системными часами. Использовать DI в контроллере вполне разумно в противоположность сущности предметной области, так как контроллеры всегда создаются контейнерами сервисов ASP.NET; это подключает любые зависимости, объявленные контроллером в его конструкторе. Поле _systemClock имеет тип IDateTime, что определяется и реализуется всего несколькими строками кода:

Конечно, мне также нужно сконфигурировать контейнер ASP.NET так, чтобы он использовал MachineClockDateTime всякий раз, когда классу требуется экземпляр IDateTime. Это делается в ConfigureServices класса Startup, и, хотя подойдет любой жизненный цикл объекта, в данном случае я предпочел использовать Singleton, так как один экземпляр MachineClockDateTime будет обслуживать все приложение:

Включив эту простую абстракцию, я могу тестировать поведение контроллера в зависимости от того, передан ли крайний срок для RSVP, и гарантировать возврат корректного результата. Поскольку у меня уже есть тесты для метода Dinner.AddRsvp, проверяющие корректность его поведения, мне не понадобится очень много тестов для проверки того же поведения через контроллер, чтобы быть уверенным, что при совместной работе контроллер и модель предметной области функционируют правильно.

Следующие шаги

Скачайте сопутствующий этой статье проект-пример и посмотрите модульные тесты для Dinner и DinnersController. Помните, что свободно связанный код, как правило, гораздо проще в модульном тестировании, чем жестко связанный код, напичканный ключевыми словами new или вызовами статических методов, зависящих от обязанностей инфраструктуры. «New является связующим», так что ключевое слово new следует использовать в приложении осознанно, а не по воле случая. Узнать больше о ASP.NET Core и ее поддержке встраивания зависимостей можно на docs.asp.net.

Стив Смит (Steve Smith) — независимый тренер, преподаватель и консультант, а также обладатель звания ASP.NET MVP. Написал десятки статей для официальной документации ASP.NET Core (docs.asp.net) и работает с группами, осваивающими эту технологию. С ним можно связаться через сайт ardalis.com, также следите за его заметками в Twitter (@ardalis).

Выражаю благодарность за рецензирование статьи эксперту Microsoft Дугу Бантингу (Doug Bunting).

HTTP сессия. Session. Состояние сеанса. Работа с сессиями в ASP.NET MVC

Давайте рассмотрим такое понятие как сессия (HTTP-сессия, Session). Или по-другому, сеанс пользователя. Почему важно понимать механизм работы сессий. И посмотрим, как можно работать с состояниями сеансов на платформе ASP.NET.

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

Одной из основных особенностей протокола HTTP является то, что он не обязывает сервер сохранять информацию о клиенте между запросами, то есть идентифицировать клиента. Это так называемый stateless-протокол. Связь между клиентом и сервером заканчивается как только завершается обработка текущего запроса. Каждый новый запрос к серверу подразумевается как абсолютно уникальный и независимый, даже если он был отправлен повторно от одного и того же источника.

Илон Маск рекомендует:  Что такое код ccvs_reverse

Что, если оставить stateless-природу протокола HTTP и не идентифицировать пользователя? Без состояний сеанса можно легко обойтись, если на вашем сайте представлена статичная (обезличенная) информация, например, новостная статья, состоящая из текста и изображений. В таком контексте совершенно необязательно ассоциировать несколько запросов с одним пользователем. Ведь содержание статьи никак не изменится, будь то десять запросов с одного устройства, либо десять запросов от разных людей с разных устройств.

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

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

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

Например, при совершении покупки в онлайн магазине персональная информация пользователя сохраняется в сессии, пока он путешествует по сайту. Это выбранные товары в корзине, адрес доставки, контактные данные и так далее.

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

  1. скрытые поля на HTML-форме (hidden form fields)
  2. куки (cookies)
  3. сессия (session, session State)

Попробуем их реализовать, используя платформу ASP.NET. Давайте кратко рассмотрим первые два механизма, и особое внимание уделим третьему, как более надежному, удобному и безопасному.

Скрытые поля на HTML-форме (hidden form fields)

Суть данного подхода состоит в том, что мы обеспечиваем навигацию по сайту при помощи стандартных html-форм. И при каждом следующем запросе мы сохраняем данные из предыдущего в скрытых полях на форме. Например:

В данном примере мы на первой html-форме получаем имя пользователя. Далее в контроллере в методе Forms2() мы извлекаем это значение из коллекции Form и передаем в представление посредством объекта ViewBag. В этом представлении генерируется код новой формы и в скрытом поле сохраняется имя пользователя. Таким образом, значение имени пользователя будет передано уже на третью формы вместе с дополнительной информацией — значением поля с именем «foodName». И так далее.

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

  • Во-первых, этот вариант не будет работать, если html-формы на наших страницах статичны, то есть жестко закодированы. И чтобы это исправить, чтобы повлиять на html-разметку мы прибегаем к помощи какой-нибудь серверной технологии (в данном случае механизм ViewBag);
  • Это безопасность. Хоть вводимые нами данные не передаются через url-параметры в адресной строке и визуально не видны на странице, мы с легкостью можем их получить или подменить или удалить или украсть просто изучив исходный код страницы или структуру запроса;

Куки (cookies)

В данном подходе мы не храним сессионные данные непосредственно на форме, вместо этого используется стандартный механизм работы cookies между клиентом и сервером. В cookies и хранятся все пользовательские данные.

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

Серверный механизм управления сессией (Session, SessionState)

Разберем, как работает механизм сессии со стороны сервера и со стороны клиента.

При стандартных настройках работы состояния сеанса для отслеживания серии запросов от одного клиента используется т.н. сессионная куки (session cookie). Алгоритм следующий:

  1. Абсолютно для каждого нового запроса на сервер (неважно, разные это клиенты или один) ASP.NET генерирует уникальный идентификатор сессии.
    Идентификатор сессии представляет собой случайно сгенерированное число, закодированное с помощью специального алгоритма в строку длиной 24 символа. Строка состоит из литералов от A до Z в нижнем регистре, а также чисел от 0 до 5. Пример идентификатора — hjnyuijl1pam3vox2h5i41in
  2. Если в течение текущего запроса данные клиента НЕ сохраняются для дальнейшей работы с ним, то и время жизни сессии этого клиента заканчивается (фактически не начавшись). При этом ранее сгенерированный идентификатор сессии становится недействительным (так как не был использован). В ответ на такой запрос клиент не получает ничего, чтобы связало его с новой сессией.
  3. Если же данные клиента (например, имя, адрес доставки товара) сохраняются на сервере, ASP.NET связывает сохраненные данные с ранее сгенерированным идентификатором сессии. Далее создается специальная сессионная куки, и в нее записывается также этот идентификатор. Эта куки добавляется в ответ на запрос и сохраняется в браузере клиента. Таким образом, создается связь клиента и его персонализированной информации на сервере. Новая сессия для данного клиента создана.
  4. При каждом следующем запросе клиент передает на сервер персональный идентификатор сессии через куки. Сервер сопоставляет идентификаторы и «узнает» клиента в рамках текущей сессии.
  5. До тех пор пока клиент передает свой персональный ключ, сессия считается активной. Сессия может закончиться по разным причинам, например, вручную на стороне сервера или по истечении какого-то установленного времени (таймаут).

От теории перейдем к практике. Давайте запрограммируем данный алгоритм и посмотрим, как он выполняется. Для этого используем специальный класс HttpSessionState . При работе в контроллере можно воспользоваться свойством HttpContext.Session . Работать с сессией очень просто, как с любой NameValueCollection :

В этом участке кода мы записываем в состояние сеанса имя пользователя. Это имя мы забираем с html-формы, которую он нам отправил. Дополнительно через свойства мы узнаем, создана ли эта сессия только что, то есть в рамках текущего запроса (если да, то и значение свойства IsNewSession будет равняться true), и уникальный идентификатор сессии. Этот идентификатор после обработки запроса будет автоматически записан в сессионную куки (если еще нет) и отправлен в ответе клиенту.

В браузере клиента можно наблюдать соответствующую куки и идентификатор его сессии:

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

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

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

Item[index] – возвращает элемент данных по его индексу
Item[key] – возвращает элемент данных по его ключу
Remove(index) – удаляет элемент данных по его индексу
Remove(key) – удаляет элемент данных по его ключу
Clear() – удаляет все данные
Count – возвращает общее количество элементов данных для текущей сессии
Abandon() – принудительно завершить сессию
SessionID — возвращает идентификатор текущей сессии
IsNewSession – возвращает true если сессия была создана в рамках текущего запроса
Timeout – возвращает число минут, допустимое между запросами, перед тем как сессия завершится по причине таймаута (по умолчанию, 20 минут)

Изменить настройки для сессии можно либо программно в коде посредством членов класса HttpSessionState , либо через конфигурацию приложения (файл web.config). Например:


В конфигурации выше мы указали, что таймаут сессии будет 40 минут, сессионные данные пользователя будут храниться в оперативной памяти, будут использоваться сессионные куки, также поменяли стандартное название такой куки на собственное.

Пишем свой первый RESTful веб-сервис на ASP.NET

Что такое RESTful веб-сервис?

REST используется для создания легковесных, поддерживаемых и масштабируемых веб-сервисов. Сервис, построенный на REST архитектуре, называется RESTful-сервисом. REST использует HTTP — базовый сетевой протокол.

Ключевые составляющие RESTful

Веб-сервисы прошли долгий путь с момента их появления. В 2002 году W3C выпустил определения WSDL и SOAP веб-сервисов. Это сформировало стандарт по созданию веб-сервисов.

В 2004 году W3C выпустил определение ещё одного стандарта под названием RESTful. В последние годы этот стандарт стал довольно популярным. На данный момент он используется многими известными сайтами по всему миру, в число которых входят Facebook и Twitter.

20 ноября в 18:30, Москва, беcплатно

REST — это способ получить доступ к ресурсам, которые находятся в определённой среде. Например, у вас может быть сервер с важными документами или фотографиями. Всё это — ресурсы. Если клиенту, скажем, веб-браузеру, нужны какие-то из этих ресурсов, ему необходимо отправить запрос на сервер для получения доступа к ним. REST определяет, как может осуществляться доступ к этим ресурсам.

Ключевые составляющие реализации RESTful:

  1. Ресурсы. Допустим, у нас есть сервер с записями о сотрудниках, а адрес веб-приложения — http://server.com. Чтобы получить доступ к записи сотрудника, мы можем выполнить команду http://server.com/employee/1, которая говорит серверу предоставить запись сотрудника под номером 1.
  2. Методы запросов. Они говорят, что вы хотите сделать с ресурсом. Браузер использует метод GET, чтобы проинформировать удалённую сторону о том, что он хочет получить данные. Кроме GET есть много других методов вроде POST, PUT и DELETE. В примере с http://server.com/employee/1 выше браузер на самом деле использует метод GET, поскольку он хочет получить данные о сотруднике.
  3. Заголовки запроса. Это дополнительные инструкции, посылаемые вместе с запросом. Они могут определять тип необходимого ресурса или подробности авторизации.
  4. Тело запроса. Это данные, отправляемые вместе с запросом. Данные обычно отправляются, когда выполняется POST-запрос к REST веб-сервису. Зачастую в POST-запросе клиент говорит серверу, что он хочет добавить на него ресурс. Следовательно, тело запроса содержит подробную информацию о ресурсе, который необходимо добавить на сервер.
  5. Тело ответа. Это основная часть ответа. В нашем примере на запрос http://server.com/employee/1 сервер мог бы прислать XML-документ с данными о сотруднике в теле ответа.
  6. Коды ответа. Эти коды возвращаются сервером вместе с ответом. Например, код 200 обычно означает, что при отправке ответа не произошло никакой ошибки.

Методы RESTful

Представим, что у нас есть RESTful веб-сервис по адресу http://server.com/employee/. Когда клиент делает запрос к нему, он может указать любой из обычных HTTP-методов вроде GET, POST, DELETE и PUT. Ниже указано, что могло бы произойти при использовании соответствующего метода:

  • POST — с его помощью можно создать новую запись сотрудника;
  • GET — с его помощью можно запросить список сотрудников;
  • PUT — с его помощью можно обновить данные сотрудников;
  • DELETE — с его помощью можно удалять записи сотрудников.

Посмотрим на это с точки зрения одной записи. Допустим у нас есть запись сотрудника под номером 1. Вот какое значение могли бы иметь следующие действия:

  • POST — этот метод нельзя применить, так как сотрудник с номером 1 уже существует;
  • GET — этот метод можно использовать для получения данных о сотруднике под номером 1;
  • PUT — этот метод можно использовать для обновления данных сотрудника под номером 1;
  • DELETE — этот метод можно использовать для удаления записи сотрудника под номером 1.

Почему RESTful

В основном популярность RESTful обусловлена следующими причинами:

1. Разнородные языки и среды — это одна из основных причин:

  • У веб-приложений, написанных на разных языках, есть возможность взаимодействовать друг с другом;
  • Благодаря RESTful эти приложения могут находиться в разных средах, будь то Windows или Linux.

Представим, что для работы с такими сайтами как Facebook, Twitter, Google и т. д. клиентскому приложению нужно знать, на каких языках и на какой платформе они написаны. Основываясь на этих знаниях, мы могли бы написать код для взаимодействия с ними, однако это превратилось бы в сущий ад.

Facebook, Twitter и Google дают доступ к их функциональности посредством RESTful веб-сервисов. Это даёт возможность любому клиентскому приложению взаимодействовать с этими сервисами с помощью REST.

2. Технологический бум – сегодня всё должно работать на разнообразных устройствах, будь то смартфон, ноутбук или кофеварка. Представляете, каких бы усилий стоило наладить взаимодействие этих устройств с помощью обычных веб-приложений? RESTful API делают эту задачу гораздо проще, поскольку, как было упомянуто выше, вам не нужно знать, что у устройства «под капотом».

3. Появление облачных сервисов — всё переезжает в облако. Приложения медленно перемещаются в облачные системы вроде Azure или Amazon, которые предоставляют большое количество API на основе RESTful архитектуры. Следовательно, приложения должны разрабатываться таким образом, чтобы они были совместимы с облаком. Так как все облачные архитектуры работают на основе REST, логично разрабатывать веб-сервисы тоже на REST-архитектуре, чтобы извлечь максимум пользы из облачных сервисов.

RESTful архитектура

Приложение или архитектура считается RESTful, если ей присущи следующие характеристики:

  1. Состояние и функциональность представлены в виде ресурсов — это значит, что каждый ресурс должен быть доступен через обычные HTTP-запросы GET, POST, PUT или DELETE. Так, если кто-то хочет получить файл на сервере, у них должна быть возможность отправить GET-запрос и получить файл. Если он хочет загрузить файл на сервер, то у него должна быть возможность использовать POST или PUT-запрос. Наконец, если он хочет удалить файл, должна быть возможность отправить запрос DELETE.
  2. Архитектура клиент-сервер, отсутствие состояния (stateless) и поддержка кеширования:
    • Клиент-сервер — обычная архитектура, где сервером может быть веб-сервер, на котором, на котором размещено приложение, а клиентом — обычный веб-браузер;
    • Архитектура без сохранения состояния означает, что состояние приложения не сохраняется в REST. Например, если вы удалили ресурс с сервера командой DELETE, то даже при получении положительного кода ответа нет гарантий, что он действительно был удалён. Чтобы убедиться, что ресурс удалён, необходимо отправить GET-запрос. С его помощью можно запросить ресурсы, чтобы посмотреть, присутствует ли там удалённый.

Принципы и ограничения RESTful

Архитектура REST основывается на нескольких характеристиках, которые описаны ниже. Любой RESTful веб-сервис должен им соответствовать, чтобы называться таковым. Эти характеристики также известны как принципы проектирования, которым нужно следовать при работе с RESTful-сервисами.

RESTful клиент-сервер

Это самое важное требование REST-архитектуры. Оно означает, что на сервере располагается RESTful веб-сервис, который предоставляет необходимую функциональность клиенту. При отправке клиентом запроса к веб-сервису сервер должен либо отклонить его, либо принять и предоставить соответствующий ответ.

Отсутствие состояния

Эта концепция означает, что задачей именно клиента является убедиться, что серверу передаются все необходимые данные. Это нужно для того, чтобы сервер мог составить ответ должным образом. Это простая независимая последовательность вопросов-ответов. Клиент задаёт вопрос, сервер отвечает соответствующим образом. Затем клиент задаёт другой вопрос, однако сервер не помнит, что было до этого, поэтому отвечает на него независимо.

Концепция кеша помогает нивелировать проблему отсутствия состояния. Так как каждый запрос клиента независим по своей природе, порой клиент может повторно отправить какой-нибудь запрос. Запрос придёт на сервер, и сервер отправит ответ. Это увеличивает сетевой трафик. Кеш позволяет клиенту хранить прежде отправленные запросы и ответы. Поэтому при повторной отправке запроса он не будет отправлен серверу; вместо этого необходимые данные будут взяты из кеша.

Многослойная система

Суть этой концепции заключается в том, что любой дополнительный слой вроде промежуточного (слой, в котором создаётся бизнес-логика; это может быть дополнительный сервис, с которым клиент взаимодействует до сервера) можно поместить между клиентом и сервером, на котором располагается RESTful веб-сервис. Однако этот слой должен быть внедрён прозрачно, чтобы он не нарушил взаимодействия клиента и сервера.

Единообразие интерфейса

Это фундаментальное требование дизайна RESTful-сервисов. RESTful работает на уровне HTTP и использует нижеприведённые методы для работы с ресурсами на сервере:

  • POST — для создания ресурса;
  • GET — для его получения;
  • PUT — для его обновления;
  • DELETE — для его удаления.

Создаём свой первый RESTful веб-сервис с ASP.NET

Веб-сервисы можно создавать на множестве языков. Многие IDE можно использовать для создания REST-сервисов.

Мы напишем REST-приложение на .NET, используя Visual Studio.


Наш сервис будет работать со следующим набором данных «туториалов»:

TutorialId TutorialName
Arrays
1 Queues
2 Stacks

Мы реализуем следующие RESTful методы:

  • GET Tutorial — при его вызове клиент получает все доступные TutorialName;
  • GET Tutorial/TutorialId — при его вызове клиент получает TutorialName, соответствующее переданному TutorialId;
  • POST Tutorial/TutorialName — при его вызове клиент отправляет запрос на добавление туториала с переданным TutorialName;
  • DELETE Tutorial/TutorialId — при его вызове клиент отправляет запрос на удаление туториала с TutorialName, соответствующему переданному TutorialId.

Теперь создадим шаг за шагом наш веб-сервис.

Шаг первый

Нам нужно создать пустое ASP.NET веб-приложение. Для этого откройте Visual Studio и создайте новый проект:

После выбора этой опции должно появиться новое диалоговое окно, о котором мы поговорим в следующем шаге.

Шаг второй

В открывшемся окне перейдите по вкладкам C# → Веб. Выберите опцию «Веб-приложение ASP.NET (.NET Framework)» и введите необходимые данные проекта вроде названия и каталога:

Если далее у вас появилось следующее окно, выбирайте вариант «Пустой»:

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

Шаг третий

Теперь нужно создать файл нашего RESTful веб-сервиса. Для этого сначала нажмите Ctrl+Shift+A, либо кликните правой кнопкой по файлу проекта Webservice.REST и выберите опции Добавить → Создать элемент…:

В открывшемся окне найдите опцию «Служба WCF (с поддержкой технологии AJAX)» и дайте ей имя TutorialSevice.svc:

Прим. перев. Если вы не можете найти эту опцию, то попробуйте открыть Visual Studio Installer и загрузить часть среды, ответственную за работу с ASP.NET:

После выбора опции «Служба WCF (с поддержкой технологии AJAX)» Visual Studio создаст код, который будет основой для реализации веб-сервиса. WCF (Windows Communication Foundation) — библиотека, необходимая для налаживания взаимодействия между приложениями с помощью разных протоколов вроде TCP, HTTP и HTTPS. AJAX позволяет асинхронно обновлять веб-страницы, обмениваясь небольшими объёмами информации с сервером.

Шаг четвёртый

Теперь нам нужно внести изменения в конфигурационный файл Web.config. Он содержит настройки, необходимые для правильной работы приложения. Наше изменение позволит приложению отправлять и принимать данные как RESTful веб-сервис.

Откройте конфигурационный файл:

В открывшемся файле найдите строку и замените её на .

Шаг пятый

Пора приниматься за код. Откройте файл TutorialService.svc. Сначала добавим код для отображения наших данных. Создадим список со строками «Arrays», «Queues» и «Stacks». Они будут отражать имена доступных туториалов:

Шаг шестой

Теперь напишем код для нашего метода GET в том же файле. Этот метод будет запускаться при каждом вызове сервиса из браузера. Он будет использоваться для получения доступных туториалов:

Строка [WebGet(UriTemplate=»/Tutorial»)] — самая важная. Она нужна для определения того, как мы будем вызывать этот метод по URL. Если наш сервис расположен по адресу http://localhost:52645/TutorialService.svc и в его конец мы добавим «/Tutorial» и получим http://localhost:52645/TutorialService.svc/Tutorial, то будет вызван вышеприведённый код. Атрибут WebGet является параметром, который позволяет GetAllTutorials() быть RESTful-методом, который можно вызвать GET-запросом.

В самом методе GetAllTutorials() находится код, который собирает все названия туториалов и возвращает их в одной строке.

Шаг седьмой

Код, показанный ниже, нужен для того, чтобы вернуть соответствующий TutorialName при получении GET-запроса с TutorialId :

Как и в предыдущем примере, первая строка — самая важная, так как определяет то, как мы будем вызывать этот метод. Если мы сделаем запрос http://localhost:52645/TutorialService.svc/Tutorial/1, то веб-сервис должен вернуть TutorialName , соответствующий TutorialId с индексом 1.

Метод GetTutorialByID() реализует описанную логику. Обратите внимание на то, что мы приводим TutorialId к типу Integer . Это связано с тем, что всё передаваемое в адресную строку браузера является строкой. А поскольку индексом списка не может быть строка, мы добавляем код, необходимый для преобразования в число.

Шаг восьмой

Настала очередь кода для метода POST, который будет вызываться каждый раз, когда мы захотим добавить строку в наш список туториалов с помощью POST-запроса:

На первой строке находится атрибут WebInvoke , прикреплённый к нашему методу, что позволяет вызывать его с помощью POST-запроса. Для атрибутов RequestFormat и ResponseFormat мы указываем JSON, так как именно с этим форматом работает RESTful веб-сервис.

Шаг девятый

Осталось добавить метод для работы с DELETE-запросами. Он будет вызываться каждый раз, когда мы будем пытаться удалить существующее значение из списка с помощью DELETE-запроса:

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

В самом методе DeleteTutorial() мы приводим переданный TutorialId к типу Integer и удаляем из списка соответствующий элемент.

В итоге код должен выглядеть так (не учитывая элементов, которые были там изначально):

Запускаем наш веб-сервис

Мы создали наш веб-сервис, пора его запустить.

Сначала кликните правой кнопкой по файлу проекта Webservice.REST и выберите опцию «Назначить автозагружаемым проектом», чтобы Visual Studio запустила этот проект при запуске всего решения:

Теперь осталось запустить проект. Рядом с кнопкой запуска будет указано имя браузера, в котором будет запускаться проект. Автоматически будет предложен браузер по умолчанию, однако вам ничто не мешает выбрать другой:

После запуска должно открыться окно браузера. Перейдите по адресу http://localhost:51056/TutorialService.svc/Tutorial и в зависимости от выбранного браузера вы увидите что-то такое:

Прим. перев. В вашем случае сервис может запуститься на localhost с другим портом. Далее в статье мы будем использовать значение 51056, однако не забывайте заменять его на своё, когда будете пытаться запускать примеры.

В этом примере браузер делает GET-запрос и тем самым вызывает написанный нами метод GetAllTutorials() , который возвращает список со всеми туториалами.

Тестируем веб-сервис


Выше мы увидели, как браузер делает GET-запрос для вызова GetAllTutorials() . Давайте проверим другие сценарии.

1. GET Tutorial/TutorialId — при вызове этого RESTful API клиент должен получить TutorialName , соответствующий переданному TutorialId .

Для вызова просто добавьте строку «/1» в конце URL, чтобы получить http://localhost:51056/TutorialService.svc/Tutorial/1. После перехода по этой ссылке вы должны увидеть следующее:

В этот раз был вызван метод GetTutorialByID() , который вернул туториал с индексом 1 — «Queues».

2. POST Tutorial/TutorialName — при вызове этого API клиент отправляет запрос на добавление переданного TutorialName , который сервер должен добавить в список. В этот раз нам понадобится инструмент Fiddler, который можно бесплатно скачать с официального сайта.

Запустите Fiddler и выполните следующие действия:

  1. Переключитесь на вкладку Composer. Она используется для создания запросов, которые можно отравить любому веб-приложению;
  2. Установите тип запроса равным «POST», а в URL вставьте адрес сервиса, в нашем случае это http://localhost:51056/TutorialService.svc/Tutorial;
  3. В окне, где уже есть строка «User-Agent: Fiddler» добавьте строку «Content-Type: application/json». Наш сервис работает только с данными в формате JSON, помните?
  4. Осталось ввести данные в поле «Request Body». Наш метод для POST-запросов принимает параметр str . Передавая строку <"str": "Trees">, мы указываем, что хотим добавить в список значение «Trees».

Нажмите на кнопку «Execute». После этого нашему сервису будет отправлен запрос на добавление «Trees».

Чтобы убедиться, что всё прошло как надо, получим список всех туториалов, перейдя по ссылке http://localhost:51056/TutorialService.svc/Tutorial. Вы должны увидеть следующее:

3. DELETE Tutorial/TutorialId — при вызове этого API клиент отправит запрос на удаление из списка TutorialName , которое соответствует переданному TutorialId .

Запустите Fiddler и выполните следующие действия:

  1. Переключитесь на вкладку Composer;
  2. Установите тип запроса равным «DELETE», а в URL вставьте адрес сервиса вместе с id элемента, который хотите удалить. Если мы хотим удалить второй элемент, то адрес будет http://localhost:51056/TutorialService.svc/Tutorial/1.

Нажмите на кнопку «Execute», чтобы отправить DELETE-запрос на удаление элемента «Queues».

Если мы опять запросим список всех туториалов, мы увидим, что их стало меньше на один:

Путь ASP.NET Core [уровень 1] Основы

ASP.NET Core — новейший фреймворк для кроссплатформенной веб разработки. Пока его популярность (как и количество вакансий) только начинает набирать обороты самое время узнать о нем побольше. Ну а для того, чтобы все знания не испарились сразу после прочтения — добавим существенную практическую часть. Создадим простое приложение, для тестирования прочитанного.

Если вы считаете, что уже достаточно круты в новом фреймворке — можете попробовать пройти тест до того, как прочтете статью. Линк. Весь код проекта можно посмотреть на гитхабе.

Первая часть включает:

  • Что такое .NET Core и ASP.NET Core?
  • Основы создания приложения и его структура
  • Добавление новых элементов, скаффолдинг
  • Основы встроенного Dependency Injection
  • Деплоймент в Azure

Разберемся в терминах. Один из наиболее не понятных моментов — это зависимость между старым фреймворком ASP.NET MVC и новым ASP.NET Core, а также в чем отличия .NET и .NET Core. Начнем с последнего. .NET Core — это общая платформа для разработки программного обеспечения. Фактически это еще одна реализация стандарта .NET (другие реализации — .NET, Mono). Отличия и особенности этой реализации (.NET Core) в том, что она:

  • С открытым исходным кодом
  • Кроссплатформенная
  • Гибкая в установке — может быть внутри приложения и можно поставить несколько версий на одной и той же машине
  • Все сценарии работы поддерживаются с помощью консольных инструментов

Перейдем к ASP.NET Core. Это новый фреймворк от Microsoft для разработки Веб приложений, который появился вследствие редизайна ранее существующего фреймворка ASP.NET MVC. Нужно понимать, что ASP.NET Core не обязательно должен базироваться на .NET Core. Можно создать ASP.NET Core приложение на основе старого доброго .NET. Такая опция есть в стандартном диалоге создания нового проекта:

В чем же тогда особенности и отличия ASP.NET Core от предыдущего ASP.NET? Некоторые из них это:

  • Возможность намного лучше контролировать нужные модули, сборки. Например, нет жесткой привязки к IIS, System.Web.dll
  • Встроенный функционал для внедрения зависимостей
  • Открытый исходный код

Кроме того, Core приложение теперь унифицировано с другими типами приложений. Теперь, оно таким же образом включает метод Main, который вызывается при запуске приложения, а тот в свою очередь просто запускает Веб часть. Минимальное приложение выглядит примерно таким образом:

Класс Statup можно, в какой-то степени, охарактеризовать как новый вариант Global.asax (Это класс для глобальной настройки всего приложения в предыдущей версии ASP.NET). Грубо говоря, можно сказать, что метод ConfigureServices нужен для конфигурации контейнера для внедрения зависимостей и его сервисов, а метод Configure для конфигурации конвейера обработки запросов.

Приступим к практической реализации

Для того, чтобы лучше понять все новшества, создадим ASP.NET Core приложение на основе .NET Core.

Чтобы облегчить себе жизнь, выберем Web Application и поменяем аутентификацию на Individual User Accounts. Таким образом Visual Studio уже сгенерирует весь нужный код для базового приложения.

Рассмотрим детальней что же нового появилось в ASP.NET Core. С точки зрения разработки вся концепция осталась прежней. Структура проекта базируется на паттерне MVC. Для работы с данными по умолчанию используем Entity Framework, логика описана в классах-контроллерах, на уровне представлений используем синтаксис cshtml + новая фишка tag helpers.

Проверим классы Program.cs и Startup.cs, они действительно выглядят такими же, как было описано выше. Конечно класс Startup не совсем пуст, а уже вмещает функционал для считывания конфигурации, настройки базового логирования, маршрутизации и привязку на нашу модель базы данных.

Дополним модель базы данных сущностями для создания и прохождения тестов. Будем использовать следующие сущности: Набор тестовых вопросов — TestPackage, Сам вопрос (тест) — TestItem, Результат теста — TestResult. Пример можно посмотреть тут. Радует, что EntityFramework Core уже поддерживает большинство функционала и можно полноценно пользоваться Code First миграциями.

Добавляем логику

Теперь, когда у нас есть модель базы данных, мы можем приступить к созданию логики для нашего приложения. Самый простой способ создания админки — это механизм scaffolding. Для этого, кликаем правой кнопкой мыши по папке контроллеров и выбираем Add → New Scaffold Item:

Выбираем «MVC Controller с представлениями, с использованием Entity Framework». Этот шаблон позволяет нам быстро создать контроллер и вьюхи для управления одной конкретной моделью. Проделаем такой трюк для TestPackage и TestItem. В результате у нас есть готовый прототип админки для нашей системы. Можно запустить проект и зайти на страницы этих контроллеров, просто добавить его имя без слова Controller в конец адреса, например, /testpackages. Конечно в ней еще не все идеально, поэтому нужно допилить некоторые моменты и сделать их более удобными.

После создания модели и простого функционала для работы с ней, можно перейти к самому процессу прохождения тестов. В общем, все выглядит просто. Сервер присылает вопрос, варианты, мы отсылаем назад ответ. Сервер сохраняет его. В конце теста показываем результат. Добавим код для этого поведения.

В общем, все что нужно для теста у нас есть.

Основы Dependency Injection в ASP.NET Core

Важным новшеством новой версии ASP.NET так же является встроенный механизм внедрения зависимостей. В 2020 году уже никого не удивишь тем, что механизм внедрения зависимостей можно перенести внутрь фреймворка. Мало какое серьёзное приложение пишут без использование этого подхода. DI в ASP.NET Core реализован достаточно базово, но в то же время позволяет решить большинство задач управления зависимостями.

Конфигурация контейнера осуществляется в методе ConfigureServices класса Startup. Пример:

Можно заметить, что для контекста базы данных и Identity фреймворка есть дополнительные, не типичные методы их регистрации. Это позволяет более гибко их сконфигурировать. В этот подход регистрации сервисов очень красиво вписываются extension-методы.

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

Деплой

Одним из самых простых способов деплоймента остается Microsoft Azure. Нам достаточно самых базовых настроек для полноценной работы. Развертывание сайта на сервере все так же просто — с помощью нескольких кликов, начиная с контекстного меню на файле проекта.


Выводы

Пока не известно будущее «классического» .NET фреймворка, так как он, все же, является более стабильным и проверенным, поэтому может существовать еще довольно долго (привет, Python 2), хотя возможна и ситуация быстрой миграции большинства девелоперов на Core версии (не такой уже .NET и старый — 14 лет всего лишь).

Аутентификация 2FA с помощью SMS¶

В этой статье я расскажу вам, как настроить двухфакторную аутентификацию (2FA) с помощью SMS. Здесь используется Twilio, но вы можете использовать любой другой SMS провайдер.

Создание новогоASP.NET Core проекта¶

Создайте новыйASP.NET Core проект с отдельными пользовательскими аккаунтами.

После создания проекта следуйте инструкциям в Подтверждение аккаунта и восстановление пароля , чтобы настроить SSL.

Настройка SMS для двухфакторной аутентификации с помощью Twilio¶

  • Создайте аккаунт Twilio.
  • Во вкладке Dashboard аккаунта Twilio обратите внимание на Account S > Install-Package Twilio
    • Добавьте код в файл Services/MessageServices.cs, чтобы включить SMS.

    Twilio пока еще не поддерживает .NET Core. Чтобы использовать Twilio, вам нужно работать с полной версией .NET Framework или вызвать Twilio REST API, чтобы отправлять SMS сообщения.

    Вы можете удалить комментарий // со строки System.Diagnostics.Debug.WriteLine(message); в этой строке тестируется приложение, если вы не можете получать SMS сообщения. Лучше всего использовать встроенное логирование .

    Настройка имени/значения SMS провайдера¶

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

    • Создайте класс, соответствующий ключевому SMS ключу. Для данного примера у нас будет класс AuthMessageSMSSenderOptions в файле Services/AuthMessageSMSSenderOptions.cs.

    Установите SID , AuthToken и SendNumber с помощью secret-manager tool . Например:

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

    Добавьте AuthMessageSMSSenderOptions в контейнер сервисов в конце метода ConfigureServices класса Startup.cs:

    Включение двухфакторной аутентификации¶

    Откройте Razor файл Views/Manage/Index.cshtml.

    Снимите комментарий с номера телефона, который начинается с:

    Снимите комментарий с Model.TwoFactor , который начинается с:

    Закомментируйте или удалите

    There are no two-factor authentication providers configured. .

    Весь код представлен ниже:

    Логин с помощью двухфакторной аутентификации¶

    • Запустите приложение и создайте нового пользователя
    • Наберите имя пользователя, и это активирует метод действия Index в контроллере Manage. Затем выберите ссылку Add для номера телефона.
    • Добавьте номер телефона, на который будет приходить верификационный код, и нажмите Send verification code.
    • Вы получите текстовое сообщение с кодом верификации. Введите его и нажмите Submit

    Если вы не получили сообщение, см. Отладка Twilio.

    • В представлении Manage видно, что номер телефона был успешно добавлен.
    • Нажмите Enable.

    Тестирование двухфакторной аутентификации¶


    • Выйдите.
    • Залогиньтесь.
    • Включается двухфакторная аутентификация, так что вам нужно предоставить второй фактор аутентификации. В данном примере мы использовали телефонную верификацию. В качестве второго фактора по умолчанию также может быть указан имейл. Вы можете выбрать и другие вторые факторы, например, QR коды. Нажмите Submit.
    • Введите код, который вы получили в SMS.
    • Если вы поставите галочку на Remember this browser, то вам не нужно будет использовать 2FA, чтобы залогиниться с этого устройства и данного браузера. При включении 2FA и нажатии на Remember this browser вы будете хорошо защишены от злонамерных атак на ваш аккаунт. Это стоит делать на том устройстве, которое только вы регулярно используете.

    Локаут аккаунта для защиты против зловредных атак¶

    Мы рекомендуем вам использовать локаут аккаунта. Если пользователь пытается залогиниться, сохраняется каждая неудачная попытка, и при достижении максимума этих попыток (по умолчанию 5) пользователь не может залогиниться в течение 5ти минут (время блокировки может быть настроена с помощью DefaultAccountLockoutTimeSpan ). В данном примере блокировка составляет 10 при 10 неудачных попытках.

    Отладка Twilio¶

    Если вы используете Twilio API, но не получаете SMS, попробуйте сделать следующее:

    1. Залогиньтесь на сайт Twilio и перейдите на страницу Logs >SMS & MMS Logs. Вы можете проверить, можно ли получать и отправлять сообщения.
    2. Для тестирования Twilio используйте данный код:

    ASP.NET — что это такое?

    По всей видимости, рядовые пользователи, использующие компьютеры исключительно для повседневных нужд или в сфере развлечений, с таким понятием, как ASP.NET, сталкиваются вряд ли. Зато веб-разработчики всех уровней подготовки знают эту платформу достаточно хорошо, хотя некоторые из них и считают, что она, если можно так сказать, морально несколько устарела. Тем не менее стоит сделать небольшой экскурс в историю создания и развития технологии ASP.NET. Что это такое, многим рядовым пользователям станет понятно после прочтения ниже предлагаемого материала. При этом попытаемся отталкиваться от самых простых терминов, не особо вдаваясь в механизмы функционирования этого инструмента, чтобы каждый желающий мог сообразить, о чем, собственно, идет речь.

    ASP.NET: что это такое?

    И для начала остановимся на самом инструментарии. Вообще, считается, что ASP.NET является достаточно мощным инструментом для быстрого создания веб-приложений, который входит практически во все известные на сегодня версии платформы Microsoft .NET Framework.

    Сам же инструментарий содержит специализированные средства в виде веб-сервисов, программной инфраструктуры и модели программирования.

    Многие считают, что описываемая технология является некой наследницей ASP. В чем-то сходство, безусловно, есть, и именно поэтому, как считается, многие программисты могут с легкостью перейти с устаревшей платформы на использование более новой. Однако на самом деле различия между этими двумя средами более существенны, что особо сильно проявляется в организации внутренней структуры среды разработки и обеспечения безопасности. Несмотря на вроде бы кажущиеся современные подходы к созданию веб-страниц и приложений, которые заложены именно в этой платформе, многие программисты относятся к ней с явным недоверием, предпочитая средства PHP или что-то подобное. Некоторые отзывы свидетельствуют о том, что не спасает ситуацию даже улучшенная среда разработки ASP.NET Core. Так ли это, далее и попробуем выяснить.

    Для чего используется ASP.NET на практике?

    Но это все были общие фразы. Рядовому пользователю нужно знать, какой практический смысл в использовании такого инструментария. В самом простом случае ASP.NET для профессионалов является весьма неплохим средством для быстрого создания динамических веб-страниц, которые существенно отличаются от статических (ASP). Иногда и включаемые в содержание HTML-страниц веб-сервисы тоже можно достаточно просто создать на основе инструментария ASP.NET.

    При всем этом нужно четко понимать, что все это очень сильно взаимосвязано именно с платформой Microsoft. NET Framework и работает исключительно в исполняемой среде (CLR Environment) на основе компилируемых языков. Чтобы было понятнее, попробуем посмотреть, что собой представляют статические и динамические страницы, а также особое внимание уделим вопросам безопасности.

    Основные отличия динамических веб-страниц от статических

    Итак, говоря о том, что это, ASP.NET можно охарактеризовать как расширенный набор инструментов, модулей и форм, позволяющий очень быстро создавать такие серверные веб-приложения, которые могли бы осуществлять динамическое взаимодействие между самим сервером, на котором расположена страница или сервис, и браузером, с которого пользователь входит в интернет. Но в чем отличие динамических и статических страниц? Статическая страница, написанная на HTML, изначально содержит только те элементы, которые были указаны непосредственно в ее коде, то есть во времени не изменяется. Но что делать, если вам потребовалось разработать страницу или приложение, в котором, например, будет заложено отображение каждодневного курса валют?

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

    История создания

    Первые упоминания об ASP.NET относятся к 1997 году, когда корпорацией Microsoft была реализована первая версия сервера IIS, что касалось исследований возможности своеобразного отделения содержания от оформления с целью написания, так сказать, «чистого» кода. Изначально проект носил название XSP, но что значила литера «Х» в сокращении, для многих до сих пор остается загадкой. Но тут нужно понимать, что сама технология базировалась в то время на запатентованной компанией Sun Microsystems общей среде программирования Java, поэтому нет ничего удивительного в том, что и сама платформа была написана именно на этом языке. зато с выходом исполняемой среды CLR (Common Language Runtime) и фреймворка .NET исходные принципы стали совершенствоваться, что и привело в конечном итоге к появлению инструментария ASP.NET, которым, невзирая на лица, пользуются многие современные программисты, кто бы там что ни говорил об устаревании платформы.

    Принципы использования и безопасности

    Что касается основных составляющих данной платформы, она позволяет писать «чистые» коды на любом языке программирования, входящем в состав фреймворка .NET (например, C#, J#, Script .NET, VB .NET и др.). При этом частично реализация исполняемого кода в процессе формирования страницы возложена на так называемую абстрактную программную модель Web Forms. Кроме того, при использовании IIS-авторизации в ASP.NET существенно повышается и безопасность взаимодействия сервера и клиента на основе протокола HTTP.

    Применение архитектуры Membership API позволяет управлять даже данными пользователей из других источников вроде SQL Server или Active Directory. Сама же аутентификация производится либо за счет специальных форм, либо прямо через Windows IIS.

    Преимущества перед ASP

    В смысле превосходства над своей предшественницей эта платформа действительно имеет ряд неоспоримых преимуществ. Так, например, ускорено выполнение компилированного кода, а все ошибки исправляются еще на стадии первичной разработки, улучшена обработка ошибок в готовой программе, быстрая разработка веб-приложений стала возможной за счет использования множества выделяемых пользовательских шаблонов, библиотек классов и элементов управления, появилась возможность написания исходного кода на любом языке, поддерживающем .NET и т. д. Кроме того, отдельно можно отметить, что теперь стало возможным кэшировать страницу целиком или частично для увеличения производительности и скорости ее загрузки в браузерах, использовать master-страницы и расширяемые модели событий, элементы управления и обработки запросов, а также применять встроенную поддержку AJAX.

    ASP.NET Core

    Эта ветвь в разработке основной платформы, по сути своей, сохранила те же принципы, которые был заложены в ASP.NET. Что это, с точки зрения улучшений?

    Только то, что Core является практически полным аналогом ASP.NET, но с открытым исходным кодом и базируется на паттерне MVC. Кроме того, сама платформа стала более унифицирована по отношению к другим приложениям, отпала необходимость жесткой привязки к System.Web.DLL и IIS, и в ней появился собственный встроенный инструментарий для обеспечения внедрения зависимостей. А вот унификация позволила оптимизировать использование метода Main и запуск веб-части приложений.

    Связь между ASP.NET и Framework

    Как уже было сказано выше, ASP.NET имеет достаточно строгую привязку к основному фреймворку, что впервые было замечено при выходе платформы версии 1.0. Сам фреймворк выступает в качестве своеобразного средства стандартизации обращения к вызовам. В свою очередь, исполняемая среда CLR дает возможность использовать единый набор сервисов, вне зависимости от применяемого языка программирования.

    Некоторые нюансы установки

    Что касается установки платформы и ускорения разработки веб-приложений на основе .NET, большинство специалистов рекомендует для начального ознакомления устанавливать ASP.NET версии 2.0. Эта модификация может использоваться практически во всех десктопных и серверных версиях Windows с сопутствующими сервис-паками, начиная с Windows 2000. Но сами готовые страницы желательно размещать исключительно на Windows Server.

    Можно ли обойтись без ASP.NET?

    Как считается, установка ASP.NET не является необходимой при использовании Visual Studio .NET 2005 года выпуска и выше.

    В этом наборе имеется специальный компонент Visual Web Developer Express Edition, для которого достаточно наличия только основного фреймворка .NET. Системные требования выглядят весьма скромными (ЦП 600 МГц 128 Мб ОЗУ), не говоря уже о том, что на установку всех компонентов, включая документацию, потребуется порядка 1,3 Гб свободного места на диске, но в процессе инсталляции VWD самостоятельно догрузит из интернета еще около 120 Мб.

    Исключение типа «System.Data.Entity.Core.EntityCommandExecutionException»

    Выпадает исключение на втором цикле foreach
    «Исключение типа «System.Data.Entity.Core.EntityCommandExecutionException» возникло в EntityFramework.SqlServer.dll, но не было обработано в коде пользователя

    Дополнительные сведения: An error occurred while executing the command definition. See the inner exception for details.»

    20.07.2020, 10:47

    Ошибка при установке Mysql.Data.EntityFramework core
    При установке Mysql.Data.EntityFramework core через nuget выдает ошибку Failed to add reference to.

    Получить base64-строку из изображения в .NET Core, используя System.Drawing.Common-пакет
    Добрый вечер! Подключаю этот пакет в asp.net core 2 .net core. Как можно исправить код.

    Исключение типа «System.Web.HttpUnhandledException»
    Добрый вечер.Подскажите что означает следующая ошибка: Выдано исключение типа.

    ADO.NET Entity Fraemwork и ошибка «Каждое имя типа в схеме должно быть уникальным»
    Здравствуйте. я создал проект в visual studio 2012, подключил к нему базу данных, через.

    Как вызвать что-то типа MsgBox-а с кнопками «Да» и «Нет» ?
    И чтоб при нажатии на ‘Да’ переходила на указанную ссылку, а при нажатии на ‘Нет’ ничего не.

    Что такое код asp accessnoremoteexecute

    ASP – веб-технология, которую в декабре 1996 года представила компания Microsoft для возможности создания интерактивных веб-приложений. ASP – это аббревиатура от Active Server Pages, что переводится, в соответствии с логикой технологии, как «активные серверные страницы». Важно понимать, что ASP не является языком программирования, она только позволяет встраивать в обычный HTML-код сценарии на каком-либо скриптовом языке(Visual Basic Script или Java Script). Таким образом, за счет использования ASP на веб-страницы могут встраиваться элементы с заранее настроенным программным управлением.

    Изначально в любом текстовом редакторе создается исходный код программы. По умолчанию используется Visual Basic – если ничего дополнительно не указывать, система будет считать, что программа написана именно на этом языке. Затем файл, которому задается расширение .asp, выкладывается в каталог, имеющий права на выполнение, чтобы сервер мог исполнить этот файл, когда браузер пользователя запросит его. Для пользователя этот файл не виден, поскольку сначала загруженный файл с программой интерпретирует сервер таким образом, что программный код будет отображаться непосредственно в HTML-коде страницы, в скобках вида скобки .

    ASP просуществовала в чистом виде до 2002 года. 1 января этого года увидел свет релиз ASP.NET, технологии, в которой были учтены ошибки и недочеты ASP. Устранить их получилось благодаря тому, что новая технология была основана на более функциональной платформе Microsoft .NET.

    Синонимы: нет
    Все термины на букву «A»
    Все термины в глоссарии

    Что такое код asp accessnoremoteexecute

    Для усердия и искусства мало невыполнимого.

    ( Сэмюэл Джонсон )

    Создание сайта :
    — сегодня уже не роскошь, а необходимый инструмент для эффективной рекламы и продвижения своего товара, продукции, компании.
    Созданный сайт, прежде всего, должен обладать профессиональным, стильным web дизайном и клиент всегда должен иметь возможность легко найти необходимую для него услугу или товар.
    Мы занимаемся: (разработка сайта, создание сайтов, редизайн сайтов, предоставление хостинга, продвижение сайтов, оптимизация под поисковые системы, создание индивидуального стиля компании, графика, Flash, шаблоны сайтов)
    Читать далее

    Полезные вещички
    HTML (учебник)
    Web (веб) статьи
    Раскрутка
    Web-мастеру
    Программы
    Рассылка
    Главная Студия Услуги НАШИ РАБОТЫ Цены Заказ Контакты Полезное
    | Доменное имя | Разное php | Тонкости web | Выбираем хостинг | Библиотека |
    Что такое ASP?

    Что такое ASP?
    Относительно недавно на смену статическим веб-страницам стали приходить динамические — то есть страницы, содержимое которых формируется в зависимости от действия пользователя. Соответственно, потребовался и новый класс приложений, способных формировать такие страницы. Эти приложения получили название серверов веб-приложений.
    В начале 1997 года компания Microsoft выпустила 3-ю версию своего веб-сервера (Internet Information Server или IIS), в котором был реализован принципиально новый метод написания серверных приложений. Он получил название ASP (Active Server Pages — активные серверные страницы). Метод является функциональным расширением веб-сервера Microsoft и основан на использовании программных интерфейсов сервера.

    По сути ASP — это обычные текстовые файлы (обычно с расширением имени asp), содержащие конструкции языка HTML и сценарии, написанные на языках JScript и/или VBScript, выполняющиеся на сервере наряду с обычным HTML-кодом.

    Чем же хороша технология ASP? Прежде всего, возможностью исполнять сценарии на сервере. С помощью сценариев для сервера можно получить доступ к файлам, базам данных и другим ресурсам, хранимым на сервере, а также к централизованным ресурсам сервера, таким как электронная почта или факс-служба.

    Функционирование в непротиворечивой и управляемой среде — еще одно преимущество выполнения сценариев на сервере. Ваш код выполняется только на одной версии единственного сервера, а не на множестве версий множества браузеров. Тем самым достигается так называемая кросс-платформенная совместимость.

    Сценарии, расположенные в страницах ASP, могут быть не только серверными, но и клиентскими. Серверные сценарии выделяются специальным образом и исполняются на сервере, в то время как клиентские сценарии загружаются вместе с HTML-страницей на компьютер пользователя и работают под управлением браузера, не имея возможности выполнять какие-либо деструктивные функции на стороне клиента.

    Новый год детям
    Создание сайта. Участие в благотворительном фонде помощь детям.

    Илон Маск рекомендует:  Что такое код mail
    Понравилась статья? Поделиться с друзьями:
    Кодинг, CSS и SQL