Поделиться через


Общие сведения о службах проверки подлинности и приложений профилей ASP.NET AJAX

Скотт Кейт

Служба проверки подлинности позволяет пользователям предоставлять учетные данные для получения файла cookie проверки подлинности и является службой шлюза, разрешая настраиваемые профили пользователей, предоставляемые ASP.NET. Использование службы проверки подлинности ASP.NET AJAX совместимо со стандартной проверкой подлинности ASP.NET с помощью форм, поэтому приложения, использующие проверку подлинности с помощью форм (например, с элементом управления "Вход"), не будут нарушены при обновлении до службы проверки подлинности AJAX.

Введение

В рамках платформа .NET Framework 3.5 корпорация Майкрософт выполняет обновление среды с заметным объемом. Кроме того, доступна не только новая среда разработки, но и новые функции запросов Language-Integrated (LINQ) и другие улучшения языка. Кроме того, некоторые знакомые функции других наборов инструментов, в частности расширения ASP.NET AJAX, включены в качестве первоклассных членов библиотеки базовых классов платформа .NET Framework. Эти расширения обеспечивают множество новых функциональных возможностей клиента, включая частичную отрисовку страниц без полного обновления страницы, возможность доступа к веб-службам через клиентский скрипт (включая API профилирования ASP.NET) и обширный КЛИЕНТСКИй API, предназначенный для зеркало многих схем управления, которые можно увидеть в ASP.NET наборе элементов управления на стороне сервера.

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

Этот технический документ основан на бета-версии 2 Visual Studio 2008 и платформа .NET Framework 3.5. В этом техническом документе также предполагается, что вы будете работать с Visual Studio 2008 Beta 2, а не с Visual Web Developer Express, и будете предоставлять пошаговые руководства в соответствии с пользовательским интерфейсом Visual Studio. В некоторых примерах кода могут использоваться шаблоны проектов, недоступные в Visual Web Developer Express.

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

Службы профилей и проверки подлинности Microsoft ASP.NET предоставляются системой проверки подлинности на основе форм ASP.NET и являются стандартными компонентами ASP.NET. Расширения ASP.NET AJAX предоставляют доступ к этим службам через прокси-серверы скриптов с помощью довольно простой модели в пространстве имен Sys.Services клиентской библиотеки AJAX.

Служба проверки подлинности позволяет пользователям предоставлять учетные данные для получения файла cookie проверки подлинности и является службой шлюза, разрешая настраиваемые профили пользователей, предоставляемые ASP.NET. Использование службы проверки подлинности ASP.NET AJAX совместимо со стандартной проверкой подлинности ASP.NET с помощью форм, поэтому приложения, использующие проверку подлинности с помощью форм (например, с элементом управления "Вход"), не будут нарушены при обновлении до службы проверки подлинности AJAX.

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

Включение ASP.NET служб проверки подлинности и профилирования в приложение выходит за рамки область этого технического документе. Дополнительные сведения по этой теме см. в библиотека MSDN справочной статье Управление пользователями с помощью членства по адресу https://msdn.microsoft.com/library/tw292whz.aspx. ASP.NET также включает служебную программу для автоматической настройки членства с помощью SQL Server, которая является поставщиком услуг проверки подлинности по умолчанию для ASP.NET Membership. Дополнительные сведения см. в статье средство регистрации ASP.NET SQL Server (Aspnet_regsql.exe) по адресу https://msdn.microsoft.com/library/ms229862(vs.80).aspx.

Использование службы проверки подлинности ASP.NET AJAX

Служба проверки подлинности ASP.NET AJAX должна быть включена в web.config файле:

<system.web.extensions> 
 <scripting>
 <webServices>
 <authenticationService enabled="true" /> 
 </webServices>
 </scripting> 
</system.web.extensions>

Служба проверки подлинности требует, чтобы ASP.NET проверка подлинности с помощью форм была включена, а файлы cookie должны быть включены в клиентском браузере (скрипт не может включить сеанс без файлов cookie, так как для сеансов без файлов cookie требуются параметры URL-адреса).

После включения и настройки службы проверки подлинности AJAX клиентский скрипт может немедленно воспользоваться преимуществами объекта Sys.Services.AuthenticationService. В первую очередь клиентский скрипт хочет воспользоваться преимуществами login метода и isLoggedIn свойства . Существует несколько свойств для предоставления значений по умолчанию для метода входа, который может принимать большое количество параметров.

Элементы Sys.Services.AuthenticationService

Метод login:

Метод login() начинает запрос на проверку подлинности учетных данных пользователя. Этот метод является асинхронным и не блокирует выполнение.

Параметры:

Имя параметра Значение
userName Обязательный. Имя пользователя для проверки подлинности.
password Необязательный параметр (по умолчанию имеет значение NULL). Пароль пользователя.
isPersistent Необязательный параметр (по умолчанию — false). Должен ли файл cookie проверки подлинности пользователя сохраняться в сеансах. Если значение равно false, пользователь выйдет из системы после закрытия браузера или истечения срока действия сеанса.
redirectUrl Необязательный параметр (по умолчанию имеет значение NULL). URL-адрес, на который перенаправляется браузер после успешной проверки подлинности. Если этот параметр имеет значение NULL или пустую строку, перенаправление не происходит.
customInfo Необязательный параметр (по умолчанию имеет значение NULL). Этот параметр в настоящее время не используется и зарезервирован для использования в будущем.
loginCompletedCallback Необязательный параметр (по умолчанию имеет значение NULL). Функция, вызываемая при успешном завершении входа. Если он указан, этот параметр переопределяет свойство defaultLoginCompleted.
failedCallback Необязательный параметр (по умолчанию имеет значение NULL). Функция, вызываемая при сбое входа. Если он указан, этот параметр переопределяет свойство defaultFailedCallback.
userContext Необязательный параметр (по умолчанию имеет значение NULL). Пользовательские данные контекста, которые должны передаваться в функции обратного вызова.

Возвращаемое значение:

Эта функция не включает возвращаемое значение. Однако после завершения вызова этой функции включается ряд поведений:

  • Текущая страница будет либо обновлена, либо изменена, если redirectUrl параметр не имеет значения NULL и не является пустой строкой.
  • Однако если параметр имеет значение NULL или пустую строку, loginCompletedCallback вызывается параметр или defaultLoginCompletedCallback свойство .
  • Если вызов веб-службы завершается сбоем failedCallback , вызывается параметр defaultFailedCallback свойства .

Метод выхода:

Метод logout() удаляет файл cookie учетных данных и выводит текущего пользователя из веб-приложения.

Параметры:

Имя параметра Значение
redirectUrl Необязательный параметр (по умолчанию имеет значение NULL). URL-адрес, на который перенаправляется браузер после успешной проверки подлинности. Если этот параметр имеет значение NULL или пустую строку, перенаправление не происходит.
logoutCompletedCallback Необязательный параметр (по умолчанию имеет значение NULL). Функция, вызываемая после успешного завершения выхода. Если он указан, этот параметр переопределяет свойство defaultLogoutCompleted.
failedCallback Необязательный параметр (по умолчанию имеет значение NULL). Функция, вызываемая при сбое входа. Если он указан, этот параметр переопределяет свойство defaultFailedCallback.
userContext Необязательный параметр (по умолчанию имеет значение NULL). Пользовательские данные контекста, которые должны передаваться в функции обратного вызова.

Возвращаемое значение:

Эта функция не включает возвращаемое значение. Однако после завершения вызова этой функции включается ряд поведений:

  • Текущая страница будет либо обновлена, либо изменена, если redirectUrl параметр не имеет значения NULL и не является пустой строкой.
  • Однако если параметр имеет значение NULL или пустую строку, logoutCompletedCallback вызывается параметр или defaultLogoutCompletedCallback свойство .
  • Если вызов веб-службы завершается сбоем failedCallback , вызывается параметр defaultFailedCallback свойства .

свойство defaultFailedCallback (get, set):

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

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

function AuthenticationFailureCallback(error, userContext, methodName);

Параметры:

Имя параметра Значение
error Указывает сведения об ошибке.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции входа или выхода из системы.
methodName Имя вызывающего метода.

свойство defaultLoginCompletedCallback (get, set):

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

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

function AuthenticationLoginCompletedCallback(validCredentials, userContext, methodName);

Параметры:

Имя параметра Значение
validCredentials Указывает, предоставил ли пользователь допустимые учетные данные. true значение , если пользователь успешно вошел в систему; в противном случае false.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции входа.
methodName Имя вызывающего метода.

свойство defaultLogoutCompletedCallback (get, set):

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

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

function AuthenticationLogoutCompletedCallback(result, userContext, methodName);

Параметры:

Имя параметра Значение
набор по Этот параметр всегда будет иметь значение null; он зарезервирован для использования в будущем.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции входа.
methodName Имя вызывающего метода.

Свойство isLoggedIn (get):

Это свойство получает текущее состояние проверки подлинности пользователя; Он задается объектом ScriptManager во время запроса страницы.

Это свойство возвращает значение true , если пользователь в данный момент вошел в систему; в противном случае возвращает значение false.

Свойство path (get, set):

Это свойство программно определяет расположение веб-службы проверки подлинности. Его можно использовать для переопределения поставщика проверки подлинности по умолчанию, а также декларативного набора в свойстве Path дочернего узла AuthenticationService элемента управления ScriptManager (дополнительные сведения см. в разделе Использование поставщика пользовательской службы проверки подлинности ниже).

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

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

Это свойство представляет собой String объект , представляющий путь к веб-службе проверки подлинности.

Свойство timeout (get, set):

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

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

Пример кода. Вход в службу проверки подлинности

Следующая разметка является примером ASP.NET страницы с простым вызовом скрипта методов входа и выхода класса AuthenticationService.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head runat="server">
 <title>Login Example</title>
 <script type="text/javascript">
 function Login()
 {
 var userTextbox = $get("txtUser");
 var passTextbox = $get("txtPassword");
 Sys.Services.AuthenticationService.login(userTextbox.value, 
 passTextbox.value, false, null, null, LoginServiceCompleted, 
 LoginServiceFailed, "Context Info");
 }
 function Logout()
 {
 Sys.Services.AuthenticationService.logout(null, LogoutServiceCompleted, 
 LoginServiceFailed, "Context Info");
 }
 function LoginServiceFailed(error, userContext, methodName)
 {
 alert('There was an error with the authentication service:\n\n' + error);
 }
 function LoginServiceCompleted(validCredentials, userContext, methodName)
 {
 if (validCredentials)
 {
 alert('Great! You successfully logged in.');
 }
 else
 {
 alert('Oops! You gave us bad credentials!');
 }
 }
 function LogoutServiceCompleted(result, userContext, methodName)
 {
 alert('You have been logged out from the web site.');
 }
 </script>
 </head>
 <body>
 <form id="form1" runat="server">
 <asp:ScriptManager ID="ScriptManager1" runat="server" 
 EnableScriptLocalization="true">
 </asp:ScriptManager>
 <div>
 <asp:TextBox ID="txtUser" runat="Server"></asp:TextBox>
 <br />
 <asp:TextBox ID="txtPassword" runat="Server" TextMode="Password"/>
 <br />
 <asp:Button Text="Log in" ID="btnLogin" runat="server" 
 OnClientClick="Login(); return false;" />
 </div>
 </form>
 </body>
</html>

Доступ к данным профилирования ASP.NET через AJAX

Служба профилирования ASP.NET также предоставляется через расширения ASP.NET AJAX. Так как служба профилирования ASP.NET предоставляет широкий, детализированный API для хранения и извлечения пользовательских данных, это может быть отличным инструментом для повышения производительности.

Служба профилей должна быть включена в web.config; По умолчанию это не так. Для этого убедитесь, что дочерний profileService элемент имеет значение enabled= true, указанное в web.config, и что вы указали, какие свойства можно считать или записать следующим образом:

<system.web.extensions>
 <scripting>
 <webServices>
 <profileService enabled="true"
 readAccessProperties= Name,Address,BackgroundColor 
 writeAccessProperties= BackgroundColor />
 </webServices>
 </scripting>
</system.web.extensions>

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

<profile enabled="true">
 <properties>
 <add name="Name" type="System.String"/>
 <group name="Address">
 <add name="Line1" type="System.String"/>
 <add name="Line2" type="System.String"/>
 <add name="City" type="System.String"/>
 <add name="State" type="System.String"/>
 <add name="Zip" type="System.String"/>
 </group>
 <add name="BackgroundColor" type="System.Drawing.Color"/>
 </properties>
</profile>

Клиентский скрипт сможет получить доступ к Name, Address.Line1, Address.Line2, Address.City, Address.State, Address.Zip и BackgroundColor в качестве свойств поля свойств класса ProfileService.

После настройки службы профилирования AJAX она будет немедленно доступна на страницах; однако его придется загрузить один раз перед использованием.

Элементы Sys.Services.ProfileService

поле properties:

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

Sys.Services.ProfileService.properties.Address.State

Метод load:

Загружает выбранный список или все свойства с сервера.

Параметры:

Имя параметра Значение
propertyNames Необязательный (по умолчанию имеет значение NULL). Свойства, загружаемые с сервера.
loadCompletedCallback Необязательный (по умолчанию имеет значение NULL). Функция, вызываемая после завершения загрузки.
failedCallback Необязательный (по умолчанию имеет значение NULL). Функция, вызываемая при возникновении ошибки.
userContext Необязательный (по умолчанию имеет значение NULL). Сведения о контексте, передаваемые функции обратного вызова.

Функция load не имеет возвращаемого значения. Если вызов выполнен успешно, вызывается loadCompletedCallback параметр или defaultLoadCompletedCallback свойство . Если вызов завершился сбоем или истекло время ожидания, failedCallback будет вызван параметр или defaultFailedCallback свойство .

propertyNames Если параметр не указан, с сервера извлекаются все свойства, настроенные для чтения.

Метод сохранения:

Метод save() сохраняет указанный список свойств (или все свойства) в профиле ASP.NET пользователя.

Параметры:

Имя параметра Значение
propertyNames Необязательный (по умолчанию имеет значение NULL). Свойства, сохраняемые на сервере.
saveCompletedCallback Необязательный (по умолчанию имеет значение NULL). Функция, вызываемая после завершения сохранения.
failedCallback Необязательный (по умолчанию имеет значение NULL). Функция, вызываемая при возникновении ошибки.
userContext Необязательный (по умолчанию имеет значение NULL). Сведения о контексте, передаваемые функции обратного вызова.

Функция сохранения не имеет возвращаемого значения. Если вызов завершится успешно, вызовет параметр saveCompletedCallback или defaultSaveCompletedCallback свойство . Если вызов завершился сбоем или истекло время ожидания, failedCallback вызывается свойство или defaultFailedCallback .

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

свойство defaultFailedCallback (get, set):

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

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

function AuthenticationFailureCallback(error, userContext, methodName);

Параметры:

Имя параметра Значение
Ошибка Указывает сведения об ошибке.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции загрузки или сохранения.
methodName Имя вызывающего метода.

свойство defaultSaveCompleted (get, set):

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

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

function ProfileSaveComplete(numPropsSaved, userContext, methodName);

Параметры:

Имя параметра Значение
numPropsSaved Указывает количество сохраненных свойств.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции загрузки или сохранения.
methodName Имя вызывающего метода.

Свойство defaultLoadCompleted (get, set):

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

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

function ProfileLoadComplete(numPropsLoaded, userContext, methodName);

Параметры:

Имя параметра Значение
numPropsLoaded Указывает количество загруженных свойств.
userContext Указывает сведения о контексте пользователя, предоставленные при вызове функции загрузки или сохранения.
methodName Имя вызывающего метода.

Свойство path (get, set):

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

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

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

Это свойство представляет собой String объект , представляющий путь к веб-службе профиля.

Свойство timeout (get, set):

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

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

Пример кода: загрузка данных профиля при загрузке страницы

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

function Page_Load()
{
 if (Sys.Services.AuthenticationService.get_isLoggedIn())
 {
 Sys.Services.ProfileService.load();
 }
}
function ProfileLoaded(numPropsLoaded, userContext, methodName)
{
 document.documentElement.style.backgroundColor = Sys.Services.ProfileService.properties.BackgroundColor;
}

Использование пользовательского поставщика службы проверки подлинности

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

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

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

Чтобы задать путь декларативно, добавьте дочерний элемент AuthenticationService объекта ScriptManager на страницу ASP.NET:

<asp:ScriptManager ID="ScriptManager1" runat="server">
 <AuthenticationService Path="~/AuthService.asmx" />
</asp:ScriptManager>

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

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

protected void Page_Load(object sender, EventArgs e)
{
    this.ScriptManager1.AuthenticationService.Path = "~/AuthService.asmx";
}

Чтобы задать путь в скрипте, выполните следующие действия.

Чтобы задать путь программным способом в скрипте, используйте path свойство класса AuthenticationService:

function Login()
{
 var userTextbox = $get("txtUser");
 var passTextbox = $get("txtPassword");
 Sys.Services.AuthenticationService.set_path("./AuthService.asmx");
 Sys.Services.AuthenticationService.login(userTextbox.value, passTextbox.value, false, null, null, LoginServiceCompleted, LoginServiceFailed, "Context Info");
}

Пример веб-службы для пользовательской проверки подлинности

<%@ WebService Language="C#" Class="AuthService" %>
using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;
using System.Web.Script.Services;
[ScriptService]
[WebService]
public class AuthService : WebService
{
 [WebMethod]
 public bool Login(string userName, string password, bool createCookie)
 {
 Session["LoggedInUser"] = userName;
 return true;
 }
 [WebMethod]
 public void Logout()
 {
 Session.Abandon();
 }
}

Итоги

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

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

Биография

Скотт Кейт работает с веб-технологиями Майкрософт с 1997 года и является президентом myKB.com (www.myKB.com), где он специализируется на написании ASP.NET приложений, ориентированных на программное обеспечение базы знаний. С Скоттом можно связаться по электронной почте по адресу scott.cate@myKB.com или в его блоге на ScottCate.com