Рассылка закрыта
При закрытии подписчики были переданы в рассылку "BloggLand и Я | Блоггландия" на которую и рекомендуем вам подписаться.
Вы можете найти рассылки сходной тематики в Каталоге рассылок.
В седьмом выпуске рассылки '.Net Собеседник' вы можете познакомиться с
Информационный Канал Subscribe.Ru |
.Net Собеседник #7
Содержание- От автора
- Обзор новостей
- Мощь базовых страниц
- Время кода - Хэшируйте пароли для дополнительной безопасности
- Форумы .Net на www.sql.ru
От автора
Здравствуйте, коллеги!
На вторые грабли я не наступил. Дело в том, что по умолчанию в
WinXP Professional не устанавливается IIS (в Home Edition он вообще не
ставится). А если вы поставите сначала среду разработки, а потом IIS, то вам
ещё необходимо будет пройти достаточно простую процедуру регистрации c помощью
команды aspnet_regiis –i, о существовании которой многие просто не подозревают.
Неблагополучные симптомы проявляются только при создании веб-приложения – на
откомпилированной странице не отображаются кнопки, размещённые в режиме дизайна
и т.д. и т.п. …
Но об этой особенности я помнил – в форумах часто встречаются вопросы на эту
тему (даже слишком часто, я бы сказал), а вот про двойные кавычки я не
вспоминал уже изрядно.
Короче говоря, желаю вам быть внимательными – на
нашем нелёгком пути немало подводных камней.
А теперь желаю приятного чтения.
{К содержанию}
Обзор новостей
-
Вышел долгожданный AllDb v.1.0
- Компания ApexCalibur Software выпустила золотую версию своего флагманского продукта AllDb. Эта библиотека классов позволит вам получить единый доступ ко всем СУБД, поддерживаемым платформой .NET Framework, что позволяет разработчикам и интеграторам сосредоточиться на написании единого источника данных главного приложения, не заботясь о том, поддерживает ли клиент конкретную СУБД.
-
Вышел .NET Memory
Profiler 2.0
- Компания SciTech Software рада сообщить о выходе .NET Memory Profiler 2.0. .NET Memory Profiler – мощный инструмент для поиска утечек памяти и оптимизации использования памяти программами, написанными для платформы .NET.
-
Mainsoft объявила о новом интегрированном
продукте .NET/J2EE
- Компания Mainsoft, широко известная своими пакетами для миграции приложений из Unix в Windows (MainWIN), выпустила новый продукт, Visual MainWin, позволяющий коду .NET исполняться в среде J2EE.
-
Включите в ваши приложения .NET поддержку скриптов
- Roy Osherove написал интересную статью в своём блоге о сценариях в .NET приложениях: "Добавление поддержки сценариев в ваши приложения – одна из наиболее ценных особенностей, которую вы можете предоставить клиентам, позволяющая добавить им стоимость к вашему продукту и содержать его в соответствии с текущими требованиями без участия разработчика..."
-
Увидела свет спецификация WS-Discovery
- Microsoft, Intel, BEA и Canon объявили о выходе спецификации WS-Discovery, предназначенной для простого и удобного динамического поиска веб-сервисов; в частности, спецификация нацелена на переферию и устройства.
-
Первые впечатления от Resharper’а,
инструмента рефакторинга кода на C#
- Компания JetBrains, авторы популярного Java IDE IntelliJ, выпустили первый релиз своего наиболее ожидаемого продукта по имени "ReSharper" (плагин к VS.NET). Первые впечатления от использования этого инструмента вы найдёте по ссылке.
-
MSDN .NET Architecture Center
- Был переработан .NET Architecture Center на сайте MSDN. В добавок к новому облику, теперь там появилось больше рубрик, добавлен новый выпуск Microsoft Architecture Update, каталог паттернов Microsoft и ссылки на блоги архитекторов, сайты и т.п.
-
Большинству разработчиков нравятся .NET WebServices
- Компания Westbridge Technology, поставщик решения масштаба корпорации Web Services Management и XML Firewall опубликовала сегодня результаты опроса использования Web Service’ов. .NET является наиболее популярным инструментом для создания веб-сервисов (43%) . Java занимает второе место с 35%.
-
Innovasys выпустила Document! X 4
- Document!X ускоряет процесс создания и поддержуи документации и контекстно-зависимой помощи для .Net сборок, исходного кода на Visual Basic/VBA/Visual Basic.NET, компонент COM.
Мощь базовых страниц
Мощь базовых страниц
ЯЗЫК: C#
Адрес оригинальной статьи:
The Power of Base Pages
Автор: Russ Nemhauser
Дата публикации оригинала: 19.01.2004 г.
ПЕРЕВОД: Чужа В.Ф. ака hDrummer
Три абзаца воды о рождественских печеньях и заказе домов, имеющих
единый план строительства, в который каждый заказчик может вносить изменения.
Опустим для ясности.
Представим себе, что мы работаем над онлайновым коммерческим сайтом. Назовём его http://www.superextramegaverygoodshop.ru/ . Короткое и запоминающееся название :). К такому сайту обычно предъявляется несколько основных требований, с реализацией которых мы будем иметь дело в этой статье:
- Отслеживать товары, которые уже просматривались посетителем. Например, на сайте Amazon.com есть область, в которой вы можете просмотреть то, на что недавно обращали внимание.
- Сохранять корзину покупателя между визитами. Я могу несколько раз заходить на сайт и добавлять товары в корзину, но я не всегда готов немедленно их оплатить и мне совсем не понравится добавлять их повторно на следующий день или через неделю – в общем, в мой следующий визит
- Помнить пользователей, которые уже посещали сайт, без необходимости повторного ввода логина/пароля
- Предоставлять единый и понятный вид для каждой страницы
Если не считать создание базы данных, то у нас останется одна-единственная задача – идентификация посетителя. Если мы знаем, кто просматривает данную конкретную страницу, то мы можем индивидуально настроить страницу для каждого пользователя. Если захотим, конечно. Некоторые сайты идентифицируют пользователя с помощью сессионного идентификатора. Однако, этот способ работает только в случае одного визита, нас же интересует идентификация в случае многократного посещения. Кроме того, желательно иметь возможность ‘узнать’ пользователя на любой странице сайта, избежав каких-либо издержек в тех случаях, когда нам это совершенно ни к чему.
Пишем класс BasePage
Первым делом займёмся классом Base Page. Для этого создадим новое веб-приложение и добавим к нему новый класс. Назовём его BasePage.cs. Нам нужно будет наследовать System.Web.UI.Page, поэтому наш класс должен содержать такой код:
using System;
using System.Web.UI; namespace BasePagesCS { public class BasePage : Page { public BasePage() { }}} |
Сохраним наш класс, откомпилируем наше веб-приложение и откроем файл с кодом для формы WebForm1. Изменим наследование от System.Web.UI.Page на BasePage, для того, чтобы мы могли пользоваться функциональностью, которую мы добавим к нашему классу.
Поскольку именно идентификация является движущей силой в реализации
каждого из трёх вышеприведенных требований, надо бы написать метод в нашем
классе, возвращающий ID посетителя. Для начала наш метод будет просматривать
cookie с именем "shopperid". Если этот cookie будет иметь значение, то мы его
вернём. Если нет, то нам надо будет сгенерировать новый ID, сохранить его в
cookie и вернуть этот новый ID. Добавим следующий метод к нашему классу
BasePage:
protected string ShopperID()
{ string id = Request.Cookies["shopperid"].Value; if (id == "") { // ID посетителя ещё не сгенерирован. Создаём его и пишем в cookie. id = Guid.NewGuid().ToString(); HttpCookie ck = new HttpCookie("shopperid", id); ck.Expires = DateTime.MaxValue; Response.Cookies.Add(ck); return id; } else { // Возвращаем ID, который мы уже создавали и вытащили из cookie. return id; } } |
Добавив единственный метод, мы с лёгкостью выполнили все три
требования. Наша страница, отображающая товары, может сохранять в БД ID
посетителя и ID товара, для того, чтобы сохранить историю просмотра для каждого
посетителя. Если же сохранить ID посетителя, ID товара и его количество в
таблице ShoppingCart (КорзинаПокупателя), мы сможем хранить состояние корзины
покупателя между визитами (если их cookie куда-нибудь не запропастятся). Точно
также мы сможем идентифицировать пользователя с любой страницы с помощью
простого сохранения cookie на его машине.
Создаём свойства класса BasePage
Теперь разберёмся с новыми свойствами нашего класса BasePage. Поскольку мы решили отталкиваться от компоновки "перевёрнутая L", необходимо предоставить разработчику возможность работы со всеми тремя областями, предлагаемыми этим видом компоновки. Итак, создадим три свойства в классе BasePage, возвращающие объекты TableCell. TableCells имеют коллекцию Controls, которая позволяет разработчику легко манипулировать любым элементом управления в заголовке, навигационной части или в области отображения. А вот и код:
private TableCell baseTitleArea; protected
TableCell TitleBar { get { return baseTitleArea; } } private TableCell baseNavArea; protected TableCell NavigationBar { get {return baseNavArea; } } private TableCell baseContentArea; protected TableCell ContentArea { get { return baseContentArea; } } |
Теперь нам необходимо показать HtmlForm, что является общим
подходом для всех веб-форм. Разработчик может захотеть изменить некоторые
свойства формы (например, свойство Enctype для разрешения закачки файлов на
удаленный компьютер). И последнее, что мы должны сделать – ограничить
возможности разработчика. Добавим следующий код в наш класс:
private HtmlForm baseForm;
protected HtmlForm Form { get { return baseForm; } } |
Ещё одно свойство, которое мы добавим в наш класс BasePage, для
облегчения нашей нелёгкой программерской жизни будет называться Title. Каждый
пытавшийся изменить программно заголовок страницы знает, что это сделать не
легко, разве что вы будете устанавливать для каждой страницы свой тэг
<title>. Мы же позаботимся о тех, кто будет наследовать свою страницу от
класса BasePage создав HtmlGenericControl для представления тэга <title>
и позволим пользователю класса оперировать им как свойством, также, как
свойствами ID и IsPostBack. В нашем случае применение этого свойства может быть
оправдано в случае необходимости отображения названия товара, просматриваемого
пользователем нашего онлайн-магазина. Поскольку нет смысла создавать одну
страницу для каждого вида товара, мы используем ID товара для того, чтобы
получить сведения о нём из базы данных. Теперь разработчик программно может
установить как содержимое страницы, так и её заголовок. Добавим следующий код к
нашему классу BasePage (заметьте, что наше свойство устанавливает или считывает
свойство InnerText класса HtmlGenericControl):
private HtmlGenericControl baseTitle;
protected string Title { get { return baseTitle.InnerText; } set { baseTitle.InnerText = value; } } |
Поскольку наш класс BasePage будет ответственен за формирование
всего HTML-кода на странице, нам нужно создать метод, который позаботится и об
этом. Этот метод создаст теги <html>, <head>, и другие тэги,
необходимые нам для создания нашей страницы, скомпонованной в виде перевёрнутой
L. Назовём его BuildFrame:
private void BuildFrame() {
// создаём открывающие тэги LiteralControl baseHtml = newLiteralControl("<html>"); baseHtml.ID = "baseHtml"; this.Controls.Add(baseHtml); LiteralControl baseHead = newLiteralControl("<head>"); baseHead.ID = "baseHead"; this.Controls.Add(baseHead); // Заголовок страницы baseTitle = new HtmlGenericControl("title"); baseTitle.ID = "baseTitle"; this.Controls.Add(baseTitle); LiteralControl baseHead2 = new LiteralControl("</head>"); baseHead2.ID = "baseHead2"; this.Controls.Add(baseHead2); LiteralControl baseBody = newLiteralControl("<body>br> baseBody.ID = "baseBody"; this.Controls.Add(baseBody); // Добавим форму baseForm = new HtmlForm(); baseForm.ID = "baseForm"; this.Controls.Add(baseForm); // Добавим таблицу Table tbl = new Table(); tbl.Width = Unit.Percentage(100); // Строка-заголовок TableRow rw = new TableRow(); baseTitleArea = new TableCell(); baseTitleArea.ColumnSpan = 2; rw.Height = Unit.Pixel(40); rw.Cells.Add(baseTitleArea); tbl.Rows.Add(rw); // Навигационное меню и содержимое rw = new TableRow(); baseNavArea = new TableCell(); baseNavArea.Width = Unit.Pixel(120); rw.Cells.Add(baseNavArea); baseContentArea = new TableCell(); rw.Cells.Add(baseContentArea); tbl.Rows.Add(rw); baseForm.Controls.Add(tbl); //Закрываем наши тэги LiteralControl baseBody2 = newLiteralControl("</body>"); baseBody2.ID = "baseBody2"; this.Controls.Add(baseBody2); LiteralControl baseHtml2 = newLiteralControl("</html>"); baseHtml2.ID = "baseHtml2"; this.Controls.Add(baseHtml2); } |
Перемещение элементов управления
Как вы видите, код выглядит достаточно прозрачно. Всё, что мы делаем – создаём элементы управления и добавляем их туда, где они должны быть. Теперь же мы должны подумать о разработчиках, добавляющих элементы управления в режиме дизайна приложения. Любой, кто попробует сделать это на данном этапе, получит ошибку, говорящую о том, что элементы управления ASP.NET должны быть размещены в форме, исполняемой на стороне сервера. Сейчас же получается так, что элементы управления, добавленные в режиме дизайна приложения, размещают свой HTML-код вне нашей HtmlForm’ы и мы должны сами их туда переместить.
- У элемента нет ID
- Элемент обладает ID длиной меньше чем четыре символа
- У элемента есть не меньше чем 4-х символьный ID, но первые 4 символа не являются словом "base"
Если кто-то из вас сильно озабочен эффективностью работы приложения, построенного с помощью такого подхода, есть такой выход – поместить все элементы в элемент Panel, который и переместить с помощью метода MoveControls:
private void MoveControls() { int ph = 0; while (this.Controls.Count > ph) { if (this.Controls[ph].ID == null || this.Controls[ph].ID.Length < 4 || (this.Controls[ph].ID.Length > 3 && this.Controls[ph].ID.Substring(0, 4).ToLower() ! = "base")) < BR> { baseContentArea.Controls.Add(this.Controls[ph]); } else {ph += 1;} }} |
Как уже обсуждалось ранее, мы перегрузим метод OnInit класса
System.Web.UI.Page. Сначала вызовем метод BuildControls, затем MoveControls. И
только потом вызовем метод OnInit родительского класса, для уверенности в том,
что он выполнит предназначенную ему работу:
protected override void OnInit(EventArgs e)
{ BuildFrame(); MoveControls(); base.OnInit (e); } |
Тестируем класс BasePage
Теперь наш класс BasePage готов – пришло время тестирования. Переключимся на WebForm1 нашего проекта, перейдём в просмотр HTML и удалим оттуда весь код, исключая директивы. Повторю ещё раз – не должно остаться ни одной HTML-строчки. Затем нажмём F7 и изменим предка WebForm1 на наш класс BasePage.
private void Page_Load(object sender,
System.EventArgs e) { // Заголовк страницы Title = "Hello World"; // Область контента Label lbl = new Label(); lbl.Text = "Hello World"; ContentArea.Controls.Add(lbl); // Область навигации Button btn = new Button(); btn.Text = "Push Here"; NavigationBar.Controls.Add(btn); // Область заголовка сайта lbl = new Label(); lbl.Text = "www.sql.ru"; lbl.Font.Bold = true; lbl.Font.Name = "Verdana"; lbl.Font.Size = FontUnit.Large; TitleBar.Controls.Add(lbl); } |
Ни один сайт с навигационным меню и логотипом комапнии не может считаться законченным без мест, в которые можно попасть с помощью этого меню и наличия самой картинки логотипа. В основном такие элементы существуют в виде пользовательских элементов (файлов ascx), которые можно добавить на вашу страницу. Использование нашего класса BasePage ничем в этом плане не отличается. Использовав Page.LoadControl в методе BuildFrame(), мы можем вставить любой пользовательский элемент в любую нашу страницу для того, чтобы удовлетворить требованиям, предъявляемым к общему виду приложения.
В итоге
После этого замечательного путешествия мы остались один на один с классом, который позволяет с лёгкостью придать единый вид всем веб-формам проекта. Мы добавили функциональность, которая не присуща классу System.Web.UI.Page – наш класс позволяет нам идентифицировать посетителя и установить заголовок страницы. Следуя этой же логике можно добавить функциональность, позволяющую программно добавлять тэги <meta> . Это может пригодиться для отображения страницы на страницах поисковых сайтов. Есть несколько другой подход в реализации подобного рода функциональности, нечто, зовущееся Master Pages, - они появятся в версии Whidbey. Но помните – этот подход не единственный и почти всегда можно найти путь, ведущий к лучшим решениям.
Время кода
Хэшируйте пароли для дополнительной безопасности
ЯЗЫК: C#
ВЕРСИИ ASP.NET: 1.0 | 1.1
АВТОР: Jeff Prosise http://www.aspnetpro.com/
ПЕРЕВОД: Чужа В.Ф ака hDrummer
Все мы видели примеры аутентификации с помощью ASP.NET форм,
которые проверяют данные, введенные в форму входа с данными, находящимися в
базе данных (обычно это пара логин/пароль). Такие примеры часто используют код,
подобный приведенному ниже. В нём используется хранимая процедура
"proc_IsUserValid" для определения содержит ли БД запись с данными,
соответствующими введённым:
// Предположим, что username содержит
набранное имя пользователя // Предположим, что password содержит набранный пароль // Предположим, что connection – открытое соединение типа SqlConnection SqlCommand command = new SqlCommand("proc_IsUserValid", connection); command.CommandType = CommandType.StoredProcedure; command.Parameters.Add ("@UserName", username); command.Parameters.Add ("@Password", password); SqlParameter result = command.Parameters.Add("@Result", SqlDbType.Bit); result.Direction = ParameterDirection.ReturnValue; bool valid = (bool) command.ExecuteScalar (); |
Для дополнительной безопасности, не рекомендую вам хранить пароли в
БД в виде открытого текста. Лучше применять хэширование вместо хранения данных
в виде открытого текста. В этом случае, если хакер прорвётся через защитный
периметр вашего веб-сервера и получит доступ к БД, он или она всё ещё не
получит доступ к именам и паролям пользователей. (По определению, математически
не возможно – и по меньшей мере практически не целесообразно – пробовать
получить обратное значение однонаправленного хэша). Метод
FormsAuthentication.HashPasswordForStoringInConfigFile позволяет легко
генерировать хэши паролей. Вот модифицированный пример, использующий алгоритм
хэширования SHA-1, для хэширования введенного пользователем пароля, перед тем,
как позволить ему посылать запросы к БД:
SqlCommand command = new
SqlCommand("proc_IsUserValid", connection);
command.CommandType = CommandType.StoredProcedure; command.Parameters.Add ("@UserName", username); command.Parameters.Add ("@Password", FormsAuthentication.HashPasswordForStoringInConfigFile((password, "SHA1")); SqlParameter result = command.Parameters.Add("@Result", SqlDbType.Bit); result.Direction = ParameterDirection.ReturnValue; bool valid = (bool) command.ExecuteScalar (); |
Не бывает чего-то слишком много, особенно если это «что-то» - безопасность. Метод хранения хэшей паролей, а не самих паролей предлагает нам более высокий уровень безопасности и это может когда-нибудь сыграть свою решающую роль.
Форумы .Net - вопросы оставшиеся без ответа
Access
OleDb: "Could not lock file"
Работа с миллисекундами
Как программно вызвать QueryBuilder?
Ошибка (?) сортировки DataViewManager'ом
Вставка объекта в asp:Table
Помогите! не работает строчка :rsAdd.Open "Sport1", Conn, 1, 2, 2
Как на ASP на сервере узнать какие е сть диски и папки на диске
Help!!! Access и ASP
Crystal Report как создать "*.rpt" файл (шаблон)
.Net Remoting
Не нашел BackgroundColor у toolBar'a...
WinForms: Как сделать docking form
Как отследить появление скролла у richTextBox'a ?
Как узнать позицию вертикального скролла в listBox'e ?
как создать в DataGrid поле в виде CheckBox
На этом седьмой выпуск .Net Собеседника закончен.
До следующего номера.
Чужа Виталий Ф. aka hDrummer,
hdrummer@sql.ru - жду ваши предложения, вопросы и замечания.
http://subscribe.ru/
E-mail: ask@subscribe.ru |
Отписаться
Убрать рекламу |
В избранное | ||