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

Сборка для работы с данными стандартных ASP.NET-профилей на уровне SQL

Микрасофтавцав иногда пробивает на светлые идеи но, как правило - это остается недоделанными полуфабрикатами. Не исключение - и их идея ASP NET профилей. С одной стороны это достаточно удобно - прописав в конфиг подобное определение получить автоматически создаваемый класс-обертку ProfileCommon и вот такую IntelliSense-подсказку.

Но вся эта идея - класический пример очередного сырья со стороны MS. Все как всегда брошено на полпути. Ведь в базе-то эта информация хранится в весьма крученном виде. А ведь данные профилей ВСЕГДА нужны именно в процедурах.

Но как же выковырнуть на уровне SQL эти данные профиля? Вот например типичная проца - где я на уровне SQL хотел бы увидеть - активирован ли логин. Я вообще не желаю создавать НИКАКИЕ обьекты в базе - пока не увижу, что логин активирован. Хотя бы в силу защиты от DOS-атак. Следовательно - самое естественное место для хранения этого свойства - профиль. А как я при отборе могу увидеть, что профиль активировался?

А никак, пока к недоделанной микрософтовской идее не будет докручен основной компонент - вычитывание данных профилей на уровне SQL. Именно такую важную сборку мы и рассмотрим на этой страничке.


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

00001: Imports System
00002: Imports System.Data
00003: Imports System.Data.SqlClient
00004: Imports System.Data.SqlTypes
00005: Imports Microsoft.SqlServer.Server
00006: Imports System.Globalization
00007: 
00008: Partial Public Class UserDefinedFunctions
00009: 
00010:     <Microsoft.SqlServer.Server.SqlFunction(DataAccess:=DataAccessKind.Read)> _
00011:     Public Shared Function GetAspBinaryProfileProperty(ByVal UserID As String, ByVal ProfilePropertyName As String) As SqlBytes
00012:         Dim Names As String() = Nothing
00013:         Dim Buffer As Byte() = Nothing
00014:         Using CN As New SqlConnection("context connection=true")
00015:             CN.Open()
00016:             Dim CMD As New SqlCommand("SELECT PropertyNames, PropertyValuesBinary FROM dbo.aspnet_Profile Where UserID='" & UserID & "'", CN)
00017:             Dim RDR As SqlDataReader = CMD.ExecuteReader
00018:             If RDR.Read Then
00019:                 Names = RDR.GetString(0).Split(CChar(":"))
00020:                 Dim Buflen As Integer = CInt(RDR.GetBytes(1, 0, Nothing, 0, 0))
00021:                 Buffer = New Byte(Buflen - 1) {}
00022:                 RDR.GetBytes(1, 0, Buffer, 0, Buflen)
00023:                 Dim i As Integer
00024:                 For i = 0 To CInt((Names.Length / 4) - 1)
00025:                     Dim OnePropertyName As String = Names((i * 4))
00026:                     Dim PropertyStartIndex As Integer = Integer.Parse(Names(((i * 4) + 2)), CultureInfo.InvariantCulture)
00027:                     Dim PropertyLength As Integer = Integer.Parse(Names(((i * 4) + 3)), CultureInfo.InvariantCulture)
00028:                     If (OnePropertyName = ProfilePropertyName) Then
00029:                         If (((Names(((i * 4) + 1)) = "B") AndAlso (PropertyStartIndex >= 0)) AndAlso ((PropertyLength > 0) AndAlso (Buffer.Length >= (PropertyStartIndex + PropertyLength)))) Then
00030:                             Dim dst() As Byte = New Byte(PropertyLength - 1) {}
00031:                             System.Buffer.BlockCopy(Buffer, PropertyStartIndex, dst, 0, PropertyLength)
00032:                             Return New SqlBytes(dst)
00033:                         End If
00034:                     End If
00035:                 Next
00036:             End If
00037:         End Using
00038:     End Function
00039: End Class

00001: Imports System
00002: Imports System.Data
00003: Imports System.Data.SqlClient
00004: Imports System.Data.SqlTypes
00005: Imports Microsoft.SqlServer.Server
00006: Imports System.Globalization
00007: 
00008: Partial Public Class UserDefinedFunctions
00009: 
00010:     <Microsoft.SqlServer.Server.SqlFunction(DataAccess:=DataAccessKind.Read)> _
00011:     Public Shared Function GetAspStringProfileProperty(ByVal UserID As String, ByVal ProfilePropertyName As String) As SqlString
00012:         Dim Names As String() = Nothing
00013:         Dim Values As String = Nothing
00014:         Using CN As New SqlConnection("context connection=true")
00015:             CN.Open()
00016:             Dim CMD As New SqlCommand("SELECT PropertyNames, PropertyValuesString FROM dbo.aspnet_Profile Where UserID='" & UserID & "'", CN)
00017:             Dim RDR As SqlDataReader = CMD.ExecuteReader
00018:             If RDR.Read Then
00019:                 Names = RDR.GetString(0).Split(CChar(":"))
00020:                 Values = RDR.GetString(1)
00021:                 Dim i As Integer
00022:                 For i = 0 To CInt((Names.Length / 4) - 1)
00023:                     Dim OnePropertyName As String = Names((i * 4))
00024:                     Dim PropertyStartIndex As Integer = Integer.Parse(Names(((i * 4) + 2)), CultureInfo.InvariantCulture)
00025:                     Dim PropertyLength As Integer = Integer.Parse(Names(((i * 4) + 3)), CultureInfo.InvariantCulture)
00026:                     If (OnePropertyName = ProfilePropertyName) Then
00027:                         If (((Names(((i * 4) + 1)) = "S") AndAlso (PropertyStartIndex >= 0)) AndAlso ((PropertyLength > 0) AndAlso (Values.Length >= (PropertyStartIndex + PropertyLength)))) Then
00028:                             Return Values.Substring(PropertyStartIndex, PropertyLength)
00029:                         End If
00030:                     End If
00031:                 Next
00032:             End If
00033:         End Using
00034:     End Function
00035: 
00036: End Class

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





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


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



Комментарии к этой страничке ( )
ссылка на эту страничку: http://www.vb-net.ru/asp2/38/index.htm
<На главную>  <В раздел ASP>  <В раздел NET>  <В раздел SQL>  <В раздел Разное>  <Написать автору>  < Поблагодарить>