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


Содержание

Как установить Persistent-Auth: true в IIS и в чем его использовать?

Я нахожусь в стадии обучения WEB API, и я просто хочу знать, как установить Persistent-Auth как истинный для моего ответа службы, и в чем польза от этого?

Для IIS 7.x это значение: authPersistSingleRequest. Установка этого знака в значение True указывает, что проверка подлинности сохраняется только для одного запроса в соединении. IIS сбрасывает аутентификацию в конце каждого запроса и принудительно повторяет аутентификацию при следующем запросе сеанса. Значение по умолчанию неверно.

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

ASP.NET — Основы ASP.NET — Элементы управления проверки достоверности

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

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

Написание кода проверки достоверности — сложная задача, в особенности из-за различия моделей клиентского программирования (обычно JavaScript) и серверного программирования (в данном случае ASP.NET). Разработчики Microsoft в курсе этого, поэтому в дополнение к набору элементов управления HTML и веб-элементов управления они также разработали набор элементов управления проверкой достоверности.

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

Элементы управления

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

RequiredFieldValidator

Контролирует, не пуст ли проверяемый элемент управления при отправке формы.

RangeValidator

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

CompareValidator

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

RegularExpressionValidator

Контролирует, соответствует ли значение данного элемента управления определенному регулярному выражению

CustomValidator

Позволяет определить любую клиентскую или серверную операцию проверки достоверности JavaScript для выполнения собственной логики проверки достоверности

ValidationSummary

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

Следует отметить, что для одного элемента управления можно использовать сразу несколько элементов управления проверкой достоверности. Например, один элемент управления проверкой достоверности можно настроить на то, чтобы связанный элемент управления ввода был не пуст, а второй — на то, что он содержит данные определенного типа. Фактически при использовании RangeValidator, CompareValidator или RegularExpressionValidator проверка достоверности автоматически пройдет успешно, если элемент управления вводом будет пуст, поскольку значение для проверки отсутствует.

Если требуется другое поведение, к элементу управления следует добавить RequiredFieldValidator. Это обеспечивает выполнение двух типов проверки достоверности, что эффективно отсекает пустые значения.

Несмотря на невозможность проверки достоверности элементов управления RadioButton или CheckBox, можно проверить достоверность TextBox (наиболее распространенный выбор) и других элементов управления, таких как ListBox, DropDownList, RadioButtonList, HtmlInputText, HtmlTextArea и HtmlSelect. При проверке достоверности спискового элемента управления проверяемым свойством является Value выбранного объекта ListItem. Вспомните, что свойство Value является скрытым атрибутом, содержащим информацию на HTML-странице для каждого элемента списка, и в браузере не отображается. Если не использовать атрибут Value, невозможно проверить достоверность элемента управления (проверка достоверности текста выбора не поддерживается).

Формально каждый класс элементов управления содержит опцию назначения одного свойства, которое будет проверяться с использованием атрибута ValidationProperty. Например, если вы создали собственный класс элементов управления FancyTextBox, обозначить свойство Text как свойство, поддерживающее проверку достоверности, можно следующим образом:

Процесс проверки на предмет достоверности

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

Когда используется автоматический процесс проверки, пользователь получает обычную страницу и приступает к заполнению отображаемых на ней элементов управления вводом. По завершении он щелкает на какой-нибудь кнопке, чтобы отправить страницу. У каждой кнопки имеется свойство CausesValidation, которое может быть установлено либо в true, либо в false. То, что произойдет после выполнения пользователем щелчка на кнопке, зависит от значения этого свойства.

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

Если значение свойства CausesValidation равно true (по умолчанию), ASP.NET автоматически проверит страницу после щелчка пользователем на кнопке, выполнив проверку для каждого элемента управления на странице. В случае если какой-то из элементов управления не пройдет проверку, ASP.NET вернет страницу с сообщением об ошибке (в зависимости от выбранных настроек). Код обработки событий Click может будет, а может и не будет выполнен, т.е. то, является ли страница действительной, необходимо выяснять специально в обработчике событий.

Свойство CausesValidation предоставляют и многие другие элементы управления кнопочного типа, которые могут применяться для отправки страницы. Например, к их числу относятся такие элементы управления, как LinkButton, ImageButton и BulletedList.

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

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

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

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

Класс BaseValidator

Классы элементов управления проверкой достоверности находятся в пространстве имен System.Web.UI.WebControls и наследуются от класса BaseValidator. Этот класс определяет базовые функции элемента управления проверкой достоверности:

Свойства и методы класса BaseValidator

Свойство или метод Описание
ControlToValidate Указывает на элемент управления вводом, подлежащий проверке
Display Определяет способ отображения сообщения об ошибке. Если установлено в Static, заранее подсчитывается пространство, необходимое для отображения сообщения, и добавляется к компоновке. Если установлено в Dynamic, компоновка страницы будет динамически изменяться для отображения строки ошибок. Следует отметить, что несмотря на кажущуюся пользу способа Dynamic, если компоновка основана на табличных структурах, при динамическом добавлении множества строк будет внесено довольно много изменений, которые могут запутать пользователя
EnabledClientScript Булевское свойство, определяющее, будет ли выполняться проверка достоверности на стороне клиента. По умолчанию установлено в true
Enabled Булевское свойство, позволяющее пользователю включать или отключать элемент управления проверкой достоверности. В отключенном состоянии элемент управления проверкой достоверности, естественно, никакой проверки не выполняет. Это свойство может устанавливаться программно при необходимости создать страницу, динамическим образом принимающую решение о том, что должно проверяться, а что — нет
ErrorMessage Строка ошибки, которая будет отображаться в итоговой информации об ошибках элементом управления ValidationSummary, если таковой присутствует
Text Текст ошибки, который отображается в элементе управления проверкой достоверности, если связанный элемент управления вводом дает сбой при проверке
IsValid Это свойство также обычно читается или устанавливается только из кода сценария (или класса отделенного кода) для определения достоверности значения в заданном элементе управления вводом.
Это свойство можно проверить на сервере после обратной отправки, но если проверка достоверности на стороне клиента активна и поддерживается клиентским браузером, выполнение не перейдет на сервер в случае недостоверного значения. (Иначе говоря, это свойство проверяется только в том случае, если проверка достоверности на стороне клиента не запускалась.)
Обратите внимание, что можно также прочитать свойство Page.IsValid, чтобы узнать результат проверки достоверности всех элементов управления вводом за одно действие. Page.IsValid возвращает true, только если все содержащиеся на странице элементы управления успешно прошли проверку
SetFocusOnError Если равно true, то когда пользователь пытается отправить страницу с недостоверным элементом управления вводом, браузер передает фокус на этот элемент для быстрого исправления значения. (В случае false фокус сохраняет кнопка или элемент управления, на котором был выполнен щелчок для отправки страницы.)
Это свойство работает для проверки достоверности как на стороне клиента, так и на стороне сервера. При наличии нескольких элементов управления проверкой достоверности с SetFocusOnError, установленным в true, и все элементы управления вводом недостоверны, фокус получит первый элемент управления в последовательности
ValidationGroup Позволяет объединять несколько элементов управления проверкой достоверности в одну логическую группу для того, чтобы они могли осуществлять свою проверку отдельно, без вмешательства элементов управления из других групп. Это свойство удобно использовать, когда на веб-странице присутствует несколько отдельных панелей, в каждой из которых имеется собственная кнопка отправки
Validate() Этот метод выполняет повторную проверку элемента управления и соответствующим образом обновляет свойство IsValid. Веб-страница вызывает этот метод автоматически тогда, когда страница отправляется обратно элементом управления CausesValidation. Однако он также может вызываться и в коде (например, если содержимое элемента управления вводом устанавливается программно и требуется проверка его достоверности).

Вдобавок класс BaseValidator содержит другие свойства, такие как BackColor, Font, ForeColor и другие унаследованные (и в некоторых случаях переопределенные) свойства базового класса Label (и классов, от которых он наследуется — WebControl и Control). Каждый производный элемент управления проверкой достоверности добавляет собственные специфические свойства, которые рассматриваются в последующих разделах.

Элемент управления RequiredFieldValidator

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

В качестве альтернативы вместо проверки пустых значений можно указать значение по умолчанию с использованием свойства InitialValue. В этом случае проверка проходит неудачно, если содержимое элемента управление совпадает с InitialValue (указывая на то, что пользователь не внес никаких изменений).

Ниже приведен пример типичного элемента RequiredFieldValidator:

Объявленный здесь элемент управления проверкой достоверности отобразит символ звездочки (*), если текстовое окно Name (Имя) окажется пустым. Этот текст ошибки появляется, когда пользователь пытается отправить форму, щелкая на кнопке с CausesValidation, установленным в true. Он также появляется на стороне клиента в Internet Explorer 5.0 и последующих версиях при переходе на новый элемент управления благодаря клиентскому JavaScript-коду.

Если вы собираетесь поместить определенное сообщение возле проверенного элемента управления, то следует заменить * сообщением об ошибке. (Использовать свойство ErrorMessage не обязательно, оно необходимо лишь в том случае, когда вы собираетесь вывести итоговую информацию по всем ошибкам на странице с применением элемента управления ValidationSummary).

В качестве альтернативы для лучших результатов можно использовать HTML-дескриптор для вывода изображения (например, восклицательного знака в желтом треугольнике) с окном подсказки для сообщения об ошибке.

Элемент управления RangeValidator

Элемент управления RangeValidator проверяет, чтобы введенное значение не выходило за рамки определенного диапазона. Он имеет три специальных свойства: MinimumValue, MaximumValue и Type.

Свойства MinimumValue и MaximumValue определяют диапазон допустимых значений, а свойство Type — тип данных, которые будут вводиться в элементе управления вводом и проверяться на достоверность. Поддерживаемыми значениями являются Currency, Date, Double, Integer и String.

В следующем примере проверяется, чтобы введенная дата находилась в диапазоне между 1 января и 31 декабря 2012 года (здесь даты кодируются в независимом от локали формате «dd/MM/yyyy»; если на веб-сервере используются другие региональные параметры, измените формат даты):

Элемент управления CompareValidator

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

Подобно элементу управления RangeValidator, элемент управления CompareValidator предоставляет свойство Type, в котором указывается тип сравниваемых данных. Помимо этого, он еще также предоставляет свойства ValueToCompare и ControlToCompare, которые позволяют сравнивать значение элемента управления вводом с константным значением или значением другого элемента управления вводом. Использовать можно только одно из этих двух свойств.

Свойство Operator позволяет задать тип операции сравнения, которая должна выполняться. Доступными значениями являются Equal, NotEqual, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual и DataTypeCheck. Значение DataTypeCheck заставляет элемент управления CompareValidator проверять, что введенные данные соответствуют требуемому типу (указанному с помощью свойства Type), и больше не выполнять никаких дополнительных операций сравнения.

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


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

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

Элемент управления RegularExpressionValidator

Элемент управления RegularExpressionValidator является одним из самых мощных средств в наборе инструментов разработчика приложений ASP.NET. Он позволяет проверять текст путем сопоставления с образцом, определенным в регулярном выражении. От разработчика требуется всего лишь установить это регулярное выражение в свойстве ValidationExpression.

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

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

Илон Маск рекомендует:  vw в CSS

Выражение .*@.<2,>\.. <2,>указывает, что проверяемая им строка должна начинаться с определенного количества символов (.*) и содержать символ @, а также еще минимум два символа (для имени домена), точку (защищенную как \.) и, наконец, по крайней мере, еще два символа для расширения домена.

Более подробно регулярные выражения описаны в статье «Регулярные выражения в C#», а ниже показаны наиболее часто используемые регулярные выражения:

Часто используемые регулярные выражения

Содержимое Регулярное выражение Описание
Адрес электронной почты \[email protected]\S+\.\S+ Определяет электронный адрес, в котором обязательно должен присутствовать символ @ и точка (.), и допускает наличие только непробельных символов
Пароль \w+ Определяет пароль, допускающий любую последовательность словесных символов (букв, пробелов или символов подчеркивания)
Пароль специфической длины \w Определяет пароль, который должен состоят не менее чем из 4, но и не более чем из 10 символов
Расширенный пароль [a-zA-Z]\w Определяет пароль, в котором, как в пароле специфической длины, может всего присутствовать от 4 до 10 символов. Хитрость состоит в том, что первый символ должен находиться в диапазоне a-z или A-Z (т.е. должен начинаться с обычной буквы)
Еще один расширенный пароль [a-zA-Z]\w*\d+\w* Определяет пароль, начинающийся с буквенного символа, за которым следует ноль или более словесных символов, потом одна или более цифр и затем снова ноль или более словесных символов. Проще говоря, требует, чтобы где-то внутри пароля содержалось число. С помощью аналогичной схемы можно также требовать, чтобы в пароле содержалось как минимум два числа или другой специальный символ
Поле ограниченной длины символов \S Определяет строку длиной от 4 до 10 символов (подобно примеру пароля), но позволяет использовать специальные символы (звездочки, амперсанды и т.д.)

Элемент управления CustomValidator

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

Элемент управления CustomValidator позволяет выполнять специальные процедуры проверки как на стороне клиента, так и на стороне сервера. Эти процедуры могут привязываться к нему, чтобы проверка достоверности выполнялась автоматически. Если выполнение проверки не проходит, для свойства Page.IsValid устанавливается значение false, как и случае любого другого элемента управления проверкой достоверности.

Процедуры проверки достоверности, которые CustomValidator должен выполнять на стороне клиента и на стороне сервера, объявляются похожим образом. Те и другие принимают два параметра: ссылку на элемент управления проверкой достоверности, к которому они должны относиться, и специальный целевой объект. Этот объект предоставляет свойство Value, в котором содержится текущее значение связанного элемента управления вводом (значение, подлежащее проверке), и свойство IsValid, которое позволяет определять, является ли введенное значение допустимым.

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

Связать этот код с элементом управления так, чтобы процедура проверки на стороне клиента выполнялась автоматически, можно, указав для ClientValidationFunction в качестве значения имя функции (в данном случае — EmpIDClientValidate).

Далее при отправке страницы ASP.NET необходимо инициировать событие CustomValidator.ServerValidate. Это событие нужно обработать с помощью кода на C# так, чтобы оно решало ту же задачу. И хотя JavaScript-логика является необязательной, процедура проверки достоверности на стороне сервера должна быть обязательно добавлена, чтобы проверка выполнялась даже в случае использования клиентом устаревшего браузера (или изменения HTML-кода веб-страницы).

Ниже показан обработчик событий для события ServerValidate. Он выполняет C#-эквивалент приведенной ранее JavaScript-процедуры проверки:

И, наконец, вот пример использующего эти процедуры дескриптора CustomValidator:

Элемент управления CustomValidator предоставляет еще одно дополнительное свойство, которое называется ValidateEmtpyText и по умолчанию имеет значение false. Однако бывают случаи, когда требуется создать клиентскую функцию, пытающуюся оценивать пустые значения. В таких сценариях для свойства ValidateEmtpyText должно устанавливаться значение true для предоставления аналогичного поведения и обработчику событий на стороне сервера.

Элемент управления ValidationSummary

Элемент управления ValidationSummary никакой проверки не выполняет. Вместо этого он позволяет показывать сводную информацию обо всех возникших на странице ошибках. В этой сводной информации отображается значение ErrorMessage каждого элемента управления проверкой достоверности, которому не удалось успешно пройти проверку. Сводная информация может отображаться как в клиентском окне сообщений JavaScript (в случае установки свойства ShowMessageBox в true), так и на самой странице (при установке свойства ShowSummary в true). Значение true может устанавливаться одновременно для обоих этих свойств, чтобы отобразить итоговую информацию двумя способами, поскольку эти свойства не являются взаимно исключающими.

В случае отображения итоговой информации на странице, с помощью свойства DisplayMode можно выбрать для нее определенный стиль (например, SingleParagraph, List или BulletList). И, наконец, свойство HeaderText позволяет указывать для итоговой информации конкретный заголовок.

Объявление элемента управления ValidationSummary выглядит довольно просто:

На рисунке показан пример, в котором сводная информация отображается в виде маркированного списка как на самой странице, так и в окне сообщения:

Использование проверочных элементов в коде

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

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

Похожий прием можно использовать и для реализации специального процесса проверки достоверности. Базовая идея состоит в добавлении кнопки со свойством CausesValidation, установленным в false. Когда на этой кнопке совершается щелчок, необходимо выполнить вручную проверку всей страницы или только определенных элементов управления проверкой достоверности вызовом метода Validate(). Затем следует просмотреть свойство IsValid и на основе его значения принять решение о том, что делать дальше.

Обработка ошибок в ASP

21.12.2010, 12:33

ASP и обработка ошибок MS SQL
Здравствуйте, господа! как определить на АСП код ошибки MS SQL? Т.е., в базе есть поле.

ASP+MSSQL обработка ошибок
Суть проблемы такова — есть процедура, которая возвращает 0 и -1, вернее должна возвратить, но при.

Обработка ошибок в ASP — ADO — посоветуйте .
Может кто-нибудь посоветует , как лучше организовать вывод сообщений об ошибке, если она.

Обработка ошибок входа в БД SQL в asp
Приветствую! Проблема в сл.: Со страницы 1 (из формы) посылается запрос на авторизацию в.

обработка ошибок SQL в ASP и проверка столбцов.
Здраствуй уважаемый all! А теперь по существу. делаем в ASP поиск из SQL 2000 с помощью CONTAINS.

Что такое Web API?

Web API – новая исполяющая среда веб-приложения, построенная на уроках и паттернах, одобренных в ASP.NET MVC. Используя простую парадигму контроллеров, Web API позволяет разработчику создавать простые Web API веб-службы с небольшим по объему кодом и конфигурацией.

Вы можете задать очень разумный вопрос: почему нам нужен новый фреймворк веб-служб? Не входит ли уже в стек разработки компании Microsoft популярная и широко совместимая технология Simple Object Access Protocol (SOAP) (простой протокол доступа к объектам)? И не существовали ли ASMX веб-службы с тех самых пор, как был выпущен ASP.NET? И не поддерживает ли уже Windows Communication Foundation (WCF) самую гибкую и расширяемую архитектуру веб-служб? Веб-службы являются повсеместными, и разработчики понимают их. Почему Web API?

Почему Web API?

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

  • Я верю в то, что существует лучший способ создания веб-служб.
  • Я верю, что веб-службы могут быть простыми и что WCF слишком сложен.
  • Я верю, что в будущем мне нужно будет поддерживать больше HTTP клиентов.
  • Я верю, что основных веб-технологий таких, как GET , POST , PUT и DELETE , достаточно.

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

Чем Web API отличается от WCF?

ASMX веб-службы на протяжении многих лет поддерживали SOAP веб-службы поверх HTTP, но они не без труда поддерживали более простые веб-службы, которым не нужно было наличие способности взаимодействовать и, таким образом, для них не нужен был SOAP. WCF занял место ASMX как самый последний и лучший способ создания веб-служб на стеке .NET. WCF службы для конечных точек HTTP похожи на следующий код.

Листинг 24-1: Для WCF служб требуется интерфейс, класс и множество атрибутов

Строка 2: Интерфейс определяет службу

Строка 4: Атрибуты определяют операции

Строка 11: Отдельный класс реализует логику службы

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

Запуская эту службу в Visual Studio, вы можете использовать тестовый клиент WCF для того, чтобы увидеть запрос и отклик операции GetData , как это продемонстрировано на рисунке 24-1.

Рисунок 24-1: Тестовый клиент WCF может помочь вам протестировать SOAP веб-службу с помощью WCF.

В рамках отрасли многие разработчики прилагают усилия для упрощения WCF HTTP веб-служб. Многие говорят о RESTful-стиле (Representational State Transfer – репрезентативная передача состояния), который был введен для того, чтобы обозначать использование простейших HTTP веб-служб без всяких украшательств.

ASP.NET Web API использует понятие обычного MVC контроллера и базируется на нем для того, чтобы создать для разработчика простое и продуктивное событие. Web API оставляет SOAP в истории как средство, которое используют приложения для взаимодействия. На сегодняшний момент, из-за повсеместного использования HTTP, большинство рабочих сред и систем программирования поддерживают основные принципы HTTP веб-коммуникации. В связи с тем, что вопрос совместимости решается другими способами, SOAP может быть отодвинут в сторону возрастающими технологиями наследования, а разработчики могут быстро создавать простые HTTP веб-службы (web APIs) с помощью ASP.NET Web API фреймворка.

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

Листинг 24-2: Web API обладает очень простым стилем программирования с ApiController

Строка 4: Базовый класс разрешает основную функциональность


Строка 7: Простые методы определяют операции

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

Возврат значения в рамках Web API схож с использованием WCF, но результат совершенно другой. Вы можете увидеть результат, запуская проект в Visual Studio и тестируя его с помощью веб-браузера. Помните, что одним из основополагающих убеждений, касающихся Web API, является тот факт, что веб-службы могут быть простыми. Перейдите с помощью Internet Explorer по адресу http://localhost:/api/values/43 , содержащий средства разработки (нажмите F12 ). На рисунке 24-2 продемонстрировано, что получится в результате.

Рисунок 24-2: Используются HTTP заголовки вместо SOAP конверта.

Вместо того чтобы возвращать SOAP XML , как это делается в WCF, используется более простой формат, JavaScript Object Notation (JSON). Этот формат силен в передаче единичных значений, а также структур сложных объектов. Поскольку язык JavaScript понимает этот формат, jQuery может принимать этот тип данных для использования в AJAX вызовах.

Теперь, когда вы увидели отличие WCF от Web API, давайте начнем добавлять некоторую интересную функциональность поверх приложения «Guestbook» из главы 2.

C# WebClient NTLM authentication starting for each request

Consider a simple C# NET Framework 4.0 application, that:

  • uses WebClient
  • authenticates using NTLM (tested on IIS 6.0 and IIS 7.5 server)
  • retrieves a string from an URL multiple times using DownloadString()

Here’s a sample that works fine:

The problem:

When enabling tracing I see that the NTLM authentication does not persist.

Each time Webclient.DownloadString is called, NTLM authentication starts (server returns «WWW-Authenticate: NTLM» header and the whole authenticate/authorize process repeats; there is no «Connection: close» header).

Wasn’t NTLM supposed to authenticate a connection, not a request?

Is there a way to make WebClient reuse an existing connection to avoid having to re-authenticate each request?

2 Answers 2

After 10 days of trying everything I could think of and learning a lot in the process, I finally figured a fix for this issue.

The trick is to enable UnsafeAuthenticatedConnectionSharing by overriding GetWebRequest and setting the property to true in the HttpWebRequest you get back.

You may want to combine that with the ConnectionGroupName property to avoid the potential use of the connection by unauthenticated applications.

Here is the sample from the question modified to work as expected. It opens a single NTLM authenticated connection and reuses it:

At this point I would also like to thank @Falco Alexander for all the help; while his suggestions didn’t quite work for me, he did point me in the right direction to look for and finally find the answer.

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).

Идентификация в ASP.NET

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

Базовые понятия систем безопасности

Существуют два понятия, без которых невозможно обсуждение безопасности:

  • Аутентификация (authentication) – процесс определения личности пользователя, требующий верные логин и пароль, чтобы доказать, что он на самом деле тот, за кого себя выдает.
  • Авторизация (authorization) – это процесс выставления прав пользователю, прошедшего аутентификацию.

Способы аутентификации ASP.NET

Среда ASP.NET предоставляет три способа аутентификации:

  • Windows – аутентификация на основе системы диспетчера локальной сети Windows
    NT.
  • Forms – аутентификация на основе cookies.
  • Passport – аутентификация с помощью службы Passport от
    Microsoft.

Для того, чтобы выбрать тот или иной способ аутентификации потребуется внести изменения в файл конфигурации web.config следующим образом (я выбрал метод Forms — как наиболее актуальную при разработке web-приложений):

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

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

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

Небольшие пояснения: параметр loginUrl в теге authentication указывает на страницу регистрации (по умолчанию – default.aspx), а параметр passwordFormat в теге credentials означает, что логин и пароль не зашифрованы (альтернативы – использовать алгоритмы шифрования SHA1 и MD5. О них мы поговорим позже ).

Для проверки верности логина и пароля будем использовать метод
FormsAuthentication. Authenticate(string login,string pass). А для регистрации пользователя в приложение ASP.NET путем создания cookie, и перенаправления на страницу, которая была изначально запрошена пользователем, будем использовать метод
FormsAuthentication. RedirectFromLoginPage(string login, bool CreatePersistentCookie) (второй параметр указывает на то,
каким будет посланный cookie – постоянный (срок годности
— 50 лет, значение true) или нет (false)).

Вот, собственно, и сам код страницы регистрации:

Авторизация

Как сделать авторизацию всплывающим окошком браузера с привязкой к БД? Мне надо на asp, но надеюсь, что принцип общий.

Response.Addheader «WWW-Authenticate», «BASIC»
Response.Status = «401 Unauthorized»

Вот так оно (окно авторизации), конечно, выводится, но при этом жестко привязывается к ACL (системе). введную серфером пару «user name/password» получить не удается.

ps Вот, SpyLog, к примеру, выдает такое окно. неужели они всех пользователей заводят в ACL?

[Сообщение изменено пользователем 19.06.2003 16:50]

заведенеи пользователей и раздача прав на асп не такая уж и сложная задача!

а интегрейт аутентификация дает неимоверные приемущества перед басик

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

Большущее всем спасибо. Похоже не понимаете, что мне надо.

Про Digest/Integrated/Basic я в курсе, и про соответствующие кыржики в IIS тоже. но все это работает с системными списками пользователей, а у меня они (пользователи) сугубо в БД лежат.


Да, так же, я понимаю, что можно нарисовать HTML форму и не парится. но надо именно всплывающим окошком. вот и спрашиваю: «Не ужели, что бы авторизовывать народ через это окно надо сначала завести всех пользователей в ACL OS?».

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

2 zynaps: сделай грязь следующего рода поставь в ИИС разрешения для анонимуса в каталог и разреши басик авторизацию потом смотришь если зашел не авторизовавшийся пользователь то выписывай ему

Response.Addheader «WWW-Authenticate», «BASIC»
Response.Status = «401 Unauthorized»
получаешь переменные логина и пароля , смотришь по своей базе проверяешь если надо даешь ему доступ не забудь прописать в сессии что он авторизовался и все что тебе там надо
тогда если он авторизовался то заголовки об авторизации не выдавай больше

у меня все работало в свое вермя

то что ты говоришь что переменых не видишь это ваще странно
хотя у меня пока одно подозрение что ты крыжики с встроеной утентификации не убрал вот она его в АД и пытаеться найти в таком случае если там не нашла то переменые должны быть пустыми!

Да это будет не сервер, а сплошная дыра в безопасности. НИКОГДА нельзя заводить внешних юзеров в системные ACL.

В ACL-то, как раз, и не хочу добавлять.

Ок. видно не судьба.

TIRAN, можно поподробнее, где ты это прочитал?
В документации по IIS 5.0 сказано прямо обратное:

«Basic Authentication
.
When your Web server verifies that the user name and password correspond to a val >

По ходу нашел как это делаеться, но могу ошибаться (не я настраивал ИИС):

Basic authentication
Basic authentication is a simple authentication protocol defined as part of the HTTP 1.0 protocol defined in RFC 2617 (available at http://www.ietf.org/rfc/rfc2617.txt). Although virtually all Web servers and Web browsers support this protocol, it is extremely insecure because the password is in cleartext (also called plaintext), meaning it’s passed over the network «in the clear.» (Actually, it’s not in the clear; it’s base64-encoded, which is so trivial to decode that it might as well be cleartext!). Basic authentication works well through proxy servers and firewalls.

Basic authentication, as implemented in IIS 5, requires Windows 2000 accounts, either in the SAM or in Active Directory. This allows the Web site to use ACLs to determine access to resources. When a user connects to a Web site using Basic authentication, IIS gets the username and password from the HTTP Authorization header, calls the LogonUser API, and then impersonates the user.

By default, users accessing your Basic authentication Web server need the right to log on locally, although this can be changed in the IIS metabase by using ADSI. Refer to Chapter 13 for this method.

So, why change the logon type? The LogonUser API allows you to determine how the account is logged on. For example, the account can be logged on using log on locally, network, or batch privileges. Interactive logon is the default because it’s the most flexible setting for most environments; it’s not necessarily the most secure. Giving users this privilege allows them to log on to the Web server if they have physical access to the server.

The flexibility of a local logon is a legacy of Windows NT 4 and IIS 4. If an account is authenticated using NTLM or is logged on with network privileges, the account cannot access secured resources on another remote computer. While the issue of client delegation is resolved in Windows 2000 by using Kerberos, the only way to work around this in Windows NT with IIS 4 and Windows 2000 with IIS 5 in a non-Active Directory environment is to log the account on using log on locally privileges.

With log on locally privileges, information about the client, such as group membership and privileges, is stored so that the account can perform an offline logon if the server performing the logon cannot access a domain controller. The downside to storing this information is its effect on speed—it takes a certain amount of time to load and store the data.

Nevertheless, you can get the best of both worlds—speed and the ability to «hop» onto a remote server securely—by using the batch logon privilege. However, few user accounts have this privilege, so you must grant the privilege to the users in question.

The Network Logon With Cleartext password setting

Just to make things a little more interesting, there’s another option! Once you give a user the network privilege—again, the Access This Computer From The Network privilege—you can allow the user to hop off the IIS server and onto a remote server by using a flag in the call to LogonUser that is new to Windows 2000: the Network Logon With Cleartext password setting. This is a new implementation in Windows 2000 of the network logon, a way of using the network privilege when calling LogonUser. This capability can be set only by using ADSI, as we’ll describe in Chapter 13.

Table 5-1 outlines the advantages and drawbacks of each logon privilege when applied to Basic authentication.

Table 5-1. Basic authentication and the effects of different privileges.

Privilege Pros Cons
Local User can perform a hop to a remote, secured server running Windows NT or Windows 2000. Insecure—giving users this privilege allows them to log on to the Web server if they have physical access to it.
Slower than other logon types because client information is cached.
Network Secure—the user cannot log on to the server even with physical access to the server.
Fast because no client data is cached. User is unable to make a hop to a remote server.
Batch User can make a hop to a remote server.
Secure—the user cannot log on to the server even with physical access to the server.
Fast because no client data is cached.
(Note: future versions of Windows might support caching client data for batch logon.) Very few accounts have this privilege by default.
Network with cleartext logon Secure—the user cannot log on to the server even with physical access to the server.
Fast because no client data is cached.
User can make a hop to a remote server.

Using Basic authentication with Active Directory

Basic authentication, when used on a system with Active Directory, offers two other features:

The ability to delegate identity

The use of user principal names (UPNs)

Let’s look at both in turn.

By default, the account logging on to the Web server using Basic authentication must have the Log On Locally privilege, by which IIS can make requests for secured resources on a remote computer on behalf of the user. In other words, if Cheryl attempts to use a resource on a remote computer, the remote computer will see that Cheryl is performing the task. However, if the remote computer attempts to access a resource on another computer, the next computer won’t see that Cheryl is making the request. In fact, the chances are good that the request will fail. This is the delegation problem, which Figure 5-5 shows more clearly. As you can see, there’s a limit to how many times the user’s credentials can be used to set up secure connections between computers running Windows NT or Windows 2000.

However, when Active Directory is used the delegation issue is solved because Windows 2000 uses Kerberos (which, as we know, is enabled when Active Directory is installed) to perform delegation. The net effect of this configuration is shown in Figure 5-6. In short, the delegation problem is solved when using Basic authentication and Active Directory.

Использование Angular для Single Page Applications (SPAs)¶

В этой статье мы покажем вам, как создавать SPA ASP.NET приложения с помощью AngularJS.

Что такое AngularJS?¶

AngularJS — это современный JavaScript фреймворк от Google, который обычно используется для работы с Single Page Applications (SPA). AngularJS имеет открытый исходный код с лицензией MIT, а процесс по разработке AngularJS можно отследить на GitHub. Библиотека называется Angular, потому что HTML использует angular скобки.

AngularJS не управляет DOM, как jQuery, но он использует jQLite. AngularJS в основном используется на декларативных атрибутах HTML, которые можно добавлять к HTML тэгам. Вы можете увидеть AngularJS в браузере с помощью вебсайта Code School.

Начинаем¶

Чтобы начать использовать AngularJS, вы должны установить его как часть проекта или сослаться на него через CDN.

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

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

StatusCodeResult

StatusCodeResult позволяет отправить любой статусный код клиенту:

Для создания этого результата используется метод StatusCode() , в который передается отправляемый код статуса.

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

HttpNotFoundResult и HttpNotFoundObjectResult

NotFoundResult и NotFoundObjectResult посылает код 404, уведомляя браузер о том, что ресурс не найден. Второй класс в дополнении к статусному коду позволяет отправить доплнительную информацию, которая потом отобразится в браузере.

Объекты обоих классов создаются методом NotFound . Для первого класса — это метод без параметров, для второго класса — метод, который в качестве параметра принимает отправляемую информацию. Например, используем NotFoundObjectResult:

UnauthorizedResult

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

Для создания ответа используется метод Unauthorized() .

BadResult и BadObjectResult

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

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

Объекты обоих классов создаются методом BadRequest . Для первого класса — это метод без параметров, для второго класса — метод, который в качестве параметра принимает отправляемую информацию:

OkResult и OkObjectResult

OkResult и OkObjectResult посылают код 200, уведомляя об успешном выполнении запроса. Второй класс в дополнении к статусному коду позволяет отправить доплнительную информацию, которая потом отобразится в браузере.

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

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