Использование browscap.ini с VB.Net

С 2013 года (более 3 лет) я использую http://www.useragentstring.com/ в своем основном проекте VB.Net для получения имени / версии браузера и имени / версии ОС из строки пользовательского агента для добавления статистики в мое локальное веб-приложение.

Но в последнее время, в последние месяцы, этот сайт был ненадежным с большим количеством простоев. Поэтому, чтобы не пропустить данные в моей статистике, я искал локальное решение, а не онлайн. Я обнаружил, что http://browscap.org/ - это старый веб-сайт (с 1998 года), который до сих пор загружает обновленную информацию о пользовательских агентах по сей день (browscap.ini). Он разработан для PHP, но я нашел там реализацию C#: https://www.gocher.me/C-Sharp-Browscap.

Но, как разработчик VB.Net, я не нашел никакой реализации VB для него. Я много гуглил, но безуспешно. Кто-нибудь получает один для VB.NET?

1 ответ

Решение

Я наконец-то смог преобразовать решение C# в VB.NET, немного почесав голову.

Public Class CompareByLength
Implements IComparer(Of String)
    Private Function Compare(ByVal x As String, ByVal y As String) as Integer _
        Implements IComparer(Of String).Compare
            If x Is Nothing Then
                If y Is Nothing Then
                    Return 0
                Else
                    Return 1
                End If
            Else
                If y Is Nothing Then
                    Return -1
                Else
                    Dim retval As Integer = x.Length.CompareTo(y.Length)
                    If retval <> 0 Then
                        Return -retval
                    Else
                        return -x.CompareTo(y)
                    End If

                End If
            End If
        End Function
End Class

Public Class BrowsCap
    Private Declare Function GetPrivateProfileSectionNames Lib "kernel32.dll" Alias "GetPrivateProfileSectionNamesA" (ByVal lpReturnedString As Byte(), ByVal nSize As Integer, ByVal lpFileName As String) As Integer
    Private Declare Function GetPrivateProfileSection Lib "kernel32.dll" Alias "GetPrivateProfileSectionA" (ByVal lpAppName As String, ByVal lpReturnedBuffer As Byte(), ByVal nSize As Integer, ByVal lpFileName As String) As Integer
    Private Declare Function GetPrivateProfileString Lib "kernel32.dll" Alias "GetPrivateProfileStringA" (ByVal lpApplicationName As String, ByVal lpKeyName As String, ByVal lpDefault As String, ByVal lpReturnedBuffer As String, ByVal nSize As Integer, ByVal lpFileName As String) As Integer

    Private path As String
    Private sections As String()

    Private Function GetSectionNames() As String()
        Dim maxsize As Integer = 500
        Do
            Dim bytes(maxsize) As Byte
            Dim size As Integer = GetPrivateProfileSectionNames(bytes, maxsize, path)
            If size < maxsize - 2 Then
                Dim Selected As String = Encoding.ASCII.GetString(bytes, 0, size - (IIf(size > 0, 1, 0)))
                Return Selected.Split(New Char() {ControlChars.NullChar})
            End If
            maxsize = maxsize * 2
        Loop
    End Function

    Public Sub IniFileName(ByVal INIPath As String)
        path = INIPath
        sections = GetSectionNames()
        Array.Sort(sections, New CompareByLength())
    End Sub

    public Function IniReadValue(ByVal Section As String, ByVal Key As String) As String
      Dim temp As New StringBuilder(255)
      Dim i As Integer = GetPrivateProfileString(Section, Key, "", temp.ToString(), 255, path)
      Return temp.ToString()
    End Function

    Private Function findMatch(ByVal Agent As String) As String
      If sections IsNot Nothing Then
        For Each SecHead As String In sections
          If (SecHead.IndexOf("*", 0) = -1) And (SecHead.IndexOf("?", 0) = -1) And (SecHead = Agent) Then
            If IniReadValue(SecHead, "parent") <> "DefaultProperties" Then
              Return SecHead
            End If
          End If
        Next
        For Each SecHead As String In sections
          Try
            If (SecHead.IndexOf("*", 0) > -1) Or (SecHead.IndexOf("?", 0) > -1) Then
              if Regex.IsMatch(Agent, "^" + Regex.Escape(SecHead).Replace("\*", ".*").Replace("\?", ".") + "$") Then
                Return SecHead
              End If
            End If
          Catch ex As Exception
            'Console.WriteLine(ex)
          End Try
        Next
        Return "*"
      End If
      Return ""
    End Function

    Public Function getValues(ByVal Agent As String) As NameValueCollection 
      Dim match As String = findMatch(Agent)
      Dim col As NameValueCollection = New NameValueCollection()
      Do
        Dim entries() As string
        Dim goon As Boolean = true
        Dim maxsize As Integer = 500
        While goon
          Dim bytes(maxsize) As Byte
          Dim size As Integer = GetPrivateProfileSection(match, bytes, maxsize, path)
          If size < maxsize - 2
            Dim section As String = Encoding.ASCII.GetString(bytes, 0, size - IIf(size > 0, 1, 0))
            entries = section.Split(New Char() {ControlChars.NullChar})
            goon = False
          End If
          maxsize = maxsize * 2
        End While
        match = ""
        If entries.Length > 0 Then
          For Each entry As String In entries
            Dim ent As String() = entry.Split(New Char() {"="C})
            If ent(0) = "Parent" Then
              match = ent(1)
            else if col(ent(0)) is nothing Then
              col.Add(ent(0), ent(1))
            End If
          Next
        End If
      Loop While match <> ""
      Return col
    End Function
End Class

А вот как это использовать:

Dim dict As Dictionary(Of String, Object) = New Dictionary(Of String, Object)
Dim bc As New BrowsCap
bc.IniFileName(Server.MapPath("/App_Data/lite_asp_browscap.ini"))
Dim Entry As NameValueCollection = bc.getValues(Request.UserAgent)
For Each s As String In Entry.AllKeys
    dict.Add(s, Entry(s))
Next
' dict("Browser") will contains browser name like "IE" or "Chrome".
' dict("Version") will contains browser version like "11.0" or "56.0".
' dict("Platform") will contains OS name and version like "Win7".

Осталось только обновить мой browscap.ini (или lite_asp_browscap.ini) иногда (например, раз в неделю).

Другие вопросы по тегам