(ASP.NET) ASP.NET (2006 год)

Управление профилями пользователей

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

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

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



На самом деле, наиболее распространенным методом сериализации является XML (особенно для System.Collections.Specialized.StringCollection), однако для System.Collections.Specialized.StringDictionary поддерживается только Binary-сериализация. Как вы могли увидеть выше - в таблице dbo.aspnet_Profile есть поля для текстовой PropertyValuesString и двоичной PropertyValuesBinary сериализации. Указанное выше определения профиля сохраняется в поле PropertyNames.

Для начала рассмотрим вот такую интересную страничку, на которой профили пользователя выводятся. При работе пользоваетель форума может добавить закладки на некоторые темы форума, а на этой страничке их простмотреть. Эта страничка интересна тем, что НЕ СОДЕРЖИТ КОДА программирования. Только разметку.





Эта удивительная страничка не содержит кода программирования, но отображает из профиля пользователя все сохраненные в нем ссылки. В этом как бы весь смысл всей чехарды со встроенным АПИ профилей. Все автоматически поднялось из поля PropertyValuesBinary таблицы aspnet_Profile, и вывелось в таблицу на страничке в виде гиперссылок. Теперь я расскажу как я добился этого.





Сама по себе указанная страничка состоит из одного DataList с шаблоном в виде гиперссылки и одного ObjectDataSource. На вопросах привязки шаблона к данным я останавливаться не буду - это разжевано на моем сайте до безобразия. Вопросы изготовления собственных бизнес-обьектов - разжеваны тоже, однако тут - случай особый. Фактически бизнес-обьект здесь полностью вырожденный, и это заслуживает внимания.



Как видите, самое главное здесь - понимать, что StringDictionary - это хеш-таблица строк, индексируемая строками и если бы мы все-таки добавили в эту страничку код, то увидели бы как ObjectDataSource перебирает элементы DictionaryEnrty хеш-таблицы StringDictionary. Ну а второе, что можно увидеть из кода выше - как из базы поднялась и десериализовалась из бинарного потока таблицы aspnet_Profile методом Web.Profile.ProfileBase коллекция ProfileBase и заполнилась в контексте текущего пользователя.

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



Теперь рассмотрим страничку, на которой я покажу, как я вывожу графику из профиля пользователя.



Здесь применена техника, когда один из столбцов GridView определен статически в HTML-коде, а остальные столбцы создаются на лету, параметром AutoGenerateColumns=True. В принципе, шаблон можно было бы тоже создать на лету, ссылки как это сделать - тут



Как вы видите, страничка содержит GridView с единственным статическим элементом в шаблоне - рисунком. Все остальное я добавил в таблицу динамически. Для этого я определил свою DataTable и привязал сетку на эту ДатаТабле динамически. Сетку, а не DataList?, я выбрал потому, что она поддерживает автоматический пейджинг, который мне в данном случае понадобилось сюда докрутить.





Прежде всего, обратите внимание на технику пейждинга, в случае динамической привязки таблы по G1.DataSource = DT. Далее обратите внимание, как я в строке 29 создал новую строку DataRow своей DataTable и добавил ее в строке 62 в свою таблицу. Но перед тем как создать строку со строгим типом данных каждого поля методом NewRow, я создал в таблице столбцы. Обратите внимание на типы столбцов - не все они являются элементарными. Некоторые из них являются ссылочными и не могуь быть использованы в определении типа данных столбца. Как вы видите - рисунок - это набор байтов - строка 26. И вписать его (а не ссылку на него) в ДатаСет можно так, как я это сделал в строках 51-55.

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



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

00001: 'У этого контрола хитрая схема сохранения состояния. 
00002: 'Он грузится:
00003: '1.Просто вхолостую (при сборке странички Page4) - (нет Постбека) - состояние любое
00004: '2.Загрузка контрола в его начальном состоянии после редиректа с Page4_NewUser (состояние ForumState.State.NewUser)
00005: '3.Постбек с кнопки вложенного контрола.
00006: 'Далее если код введен правильно, ВОЗМОЖНО возникновения события SEND (если код введен правильно)
00007: 'После выполнения SEND всегда делается REDIRECT на Page4
00008: '4.После этого контрол грузится еще раз (нет Постбека) - ForumState.State.NewUser
00009: '5.При повторах в случае неудачного создания юзера (есть Постбек) - то же что и пункт 2
00010: 'При удачном создании юзера меняет состояние на ForumState.State.EndRegister
00011: '
00012: 'Если записать просто ошибку в L0.Text и сделать Постбек, то после Редиректа
00013: 'при новой сборке страницы она потеряется ДАЖЕ во ViewState.
00014: '
00015: 'Err1 - не принята EULA форума
00016: 'Err2 - отключен Javascript и не прошли проверки корректности на клиент2
00017: 'Err3 - ошибка создания нового юзера Membership-провайдером
00018: 'Err4 - общая ошибка странички
00019: 'Err5 - ошибка скачки файла
00020: 
00021: Partial Class Control_ForumNewUser
00022:     Inherits System.Web.UI.UserControl
00023: 
00024:     Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
00025:         If Me.Page.IsPostBack Then
00026:             If Not Err3.Checked Then
00027:                 Session("ForumRegErr3") = "Условие не принято. Регистрация невозможна."
00028:             Else
00029:                 Session("ForumRegErr3") = ""
00030:             End If
00031:         Else
00032:             If Session("ForumState") = ForumState.State.NewUser Then
00033:                 Err1.Text = Session("ForumRegErr1")
00034:                 Err2.Text = Session("ForumRegErr2")
00035:                 Err3.Text = Session("ForumRegErr3")
00036:                 Err4.Text = Session("ForumRegErr4")
00037:                 Err5.Text = Session("ForumRegErr5")
00038:             End If
00039:         End If
00040:     End Sub
00041: 
00042:     Protected Sub S1_Send() Handles S1.Send
00043:         If Not Err3.Checked Then
00044:             Response.Redirect(Session("OnNavigateReturnURL"))
00045:         Else
00046:             Me.Page.Validate()
00047:             If Me.Page.IsValid Then
00048:                 Session("ForumRegErr2") = ""
00049:                 Try
00050:                     Dim Result As MembershipCreateStatus
00051:                     'создаем нового юзера
00052:                     Dim X As System.Web.Security.MembershipUser = System.Web.Security.Membership.CreateUser(T1.Text, T2.Text, T4.Text, T5.Text, T6.Text, True, Result)
00053:                     If Result = MembershipCreateStatus.Success And (Not (X Is Nothing)) Then
00054:                         Session("ForumRegErr1") = ""
00055:                         'создали профиль нового юзера
00056:                         Dim P As System.Web.Profile.ProfileBase = ProfileBase.Create(X.UserName.ToString, True)
00057:                         'и заполняем его
00058:                         Dim Y As New System.Collections.Specialized.StringDictionary
00059:                         P.SetPropertyValue("HideMail", C1.Checked)
00060:                         P.SetPropertyValue("HideLink", C2.Checked)
00061:                         P.SetPropertyValue("Devis", T7.Text)
00062:                         P.SetPropertyValue("Links", Y)
00063:                         'скачка указанного файла и определение его корректности как рисунка
00064:                         Dim Z As System.Drawing.Bitmap, M As System.IO.MemoryStream
00065:                         If U1.PostedFile.FileName = "" Then
00066:                             Z = New Drawing.Bitmap(1, 1, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
00067:                             Dim G As Drawing.Graphics = Drawing.Graphics.FromImage(Z)
00068:                             G.Clear(Drawing.Color.White)
00069:                             P.SetPropertyValue("Image", Z)
00070:                         Else
00071:                             Try
00072:                                 'СИНХРОННАЯ скачка указанного файла
00073:                                 If U1.PostedFile.InputStream.Length > 1000000 Then
00074:                                     Session("ForumRegErr5") = "Превышена длина файла"
00075:                                     Throw New System.Data.SyntaxErrorException
00076:                                 Else
00077:                                     Dim Buf(U1.PostedFile.InputStream.Length) As Byte
00078:                                     U1.PostedFile.InputStream.Read(Buf, 0, U1.PostedFile.InputStream.Length)
00079:                                     M = New System.IO.MemoryStream(Buf)
00080:                                     Session("ForumRegErr5") = ""
00081:                                 End If
00082:                             Catch ex As Exception
00083:                                 Session("ForumRegErr5") = ex.Message
00084:                             End Try
00085:                             Try
00086:                                 'загрузить скачанное в BITMAP
00087:                                 Dim Z1 As New Drawing.Bitmap(M, False)
00088:                                 Dim Rate As Double = IIf(Z1.Width / 150 > Z1.Height / 150, Z1.Width / 150, Z1.Height / 150)
00089:                                 'перемасштабировали рисунок к максимальному размеру 150 рiх
00090:                                 Z = New System.Drawing.Bitmap(Z1, CInt(IIf(Z1.Width / 150 > Z1.Height / 150, 150, Z1.Width / Rate)), CInt(IIf(Z1.Width / 150 > Z1.Height / 150, Z1.Height / Rate, 150)))
00091:                             Catch ex As Exception
00092:                                 Z = New Drawing.Bitmap(50, 10, System.Drawing.Imaging.PixelFormat.Format24bppRgb)
00093:                                 Dim G As Drawing.Graphics = Drawing.Graphics.FromImage(Z)
00094:                                 G.Clear(Drawing.Color.White)
00095:                                 G.DrawString("Error", New Drawing.Font("", 10, Drawing.FontStyle.Regular, Drawing.GraphicsUnit.Pixel), Drawing.Brushes.Red, 0, -2)
00096:                             End Try
00097:                         End If
00098:                         'в любом случае - то что получили вписываем в профиль
00099:                         P.SetPropertyValue("Image", Z)
00100:                         P.Save()
00101:                         Session("ForumState") = ForumState.State.EndRegister
00102:                     Else
00103:                         Select Case Result
00104:                             Case MembershipCreateStatus.DuplicateEmail
00105:                                 Session("ForumRegErr1") = "Ошибка. Дублирование почты."
00106:                             Case MembershipCreateStatus.DuplicateProviderUserKey
00107:                                 Session("ForumRegErr1") = "Ошибка. Дублирование DuplicateProviderUserKey."
00108:                             Case MembershipCreateStatus.DuplicateUserName
00109:                                 Session("ForumRegErr1") = "Ошибка. Дублирование имени пользователя."
00110:                             Case MembershipCreateStatus.InvalidAnswer
00111:                                 Session("ForumRegErr1") = "Ошибка. Дублирование имени пользователя."
00112:                             Case MembershipCreateStatus.InvalidEmail
00113:                                 Session("ForumRegErr1") = "Ошибка. Недопустимая почта."
00114:                             Case MembershipCreateStatus.InvalidPassword
00115:                                 Session("ForumRegErr1") = "Ошибка. Слишком простой пароль."
00116:                             Case MembershipCreateStatus.InvalidProviderUserKey
00117:                                 Session("ForumRegErr1") = "Ошибка. Недопустимый код пользователя."
00118:                             Case MembershipCreateStatus.InvalidQuestion
00119:                                 Session("ForumRegErr1") = "Ошибка. Недопустимый ответ."
00120:                             Case MembershipCreateStatus.InvalidUserName
00121:                                 Session("ForumRegErr1") = "Ошибка. Недопустимое имя пользователя."
00122:                             Case MembershipCreateStatus.ProviderError
00123:                                 Session("ForumRegErr1") = "Ошибка провайдера авторизации."
00124:                             Case MembershipCreateStatus.UserRejected
00125:                                 Session("ForumRegErr1") = "Ошибка. Пользователь сброшен."
00126:                         End Select
00127:                         SH.Common.ErrorMessage(Me.Page, "Ошибка создания пользователя.", Session("ForumRegErr1"))
00128:                         Session("ForumRegErr4") = ""
00129:                     End If
00130:                 Catch ex As Exception
00131:                     Session("ForumRegErr4") = ex.Message
00132:                     SH.Common.ErrorMessage(Me.Page, "Упала регистрация", ex.Message)
00133:                 Finally
00134:                     Response.Redirect(Session("OnNavigateReturnURL"))
00135:                 End Try
00136:             Else
00137:                 Session("ForumRegErr2") = "Отключен JavaScript. Регистрация невозможна."
00138:                 Response.Redirect(Session("OnNavigateReturnURL"))
00139:             End If
00140:         End If
00141:     End Sub
00142: End Class

Но перед тем, как вписывать предпочтения пользователя, его надо было сначала создать по System.Web.Security.Membership.CreateUser. Конечно, АПИ из ASP2 не только создает сами профиля юзеров, но и само вызывает необходимые процедуры чтобы создать и самих пользователей. Но об этом подробнее я писал здесь.



Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/asp2/13/index.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>