BigBastis Blog

Entstehung einer ASP.NET Webanwendung anhand eines Beispiels

Introduction

user

Michael Bernhard


LATEST POSTS

Ausgeben einer Meldung nach dem Anmelden des Benutzers an einer ASP.NET Webseite 12th August, 2011

.NET

Entstehung einer ASP.NET Webanwendung anhand eines Beispiels

Posted on .

Mit diesem Artikel will ich skizzieren wie eine Webanwendung mittels ASP.NET entworfen und umgesetzt wird. Ich will einen Einblick in die Vorüberlegungen, sowie in die Umsetzung des Projektes geben. Nicht mehr, aber auch nicht weniger.

Vorüberlegungen

Wie fast alle Hobbyprogrammierer erstelle auch ich eine Unzahl unnötiger und zum Teil auch unsinniger Anwendungen. Dies ist der Luxus den man sich leisten kann, wenn man damit nicht sein Geld verdienen muss.

Da ich ab und zu auf Dienstreise gehe, ist die aktuelle Uhrzeit am gegenwärtigen Standort immer ein Thema. Oft kommt auch die Frage auf, wie spät es denn bei den Lieben zu Hause wohl sein mag.

Hierfür  kommt natürlich nur, mein neuestes Steckenpferd, eine Webanwendung in Frage.

Die ersten Überlegungen:

  1. Welcher Aufbau einer Webanwendung ist der beste
  2. Wie ermittle ich meinen aktuellen Standort
  3. Welche zusätzlichen Informationen kann ich noch anzeigen

1. Welcher Aufbau einer Webanwendung ist der beste?

Ich hab mich hier, sehr schnell, für eine Webanwendung entschieden, die ihre Informationen aus einem RSS-Feed bezieht. Vorteil hierbei, es handelt sich um ein XML-Format, welches leicht zu lesen ist und auch anderweitig verwendet werden kann.
Eine Windows-, Linux-, MacOS- oder Android Anwendung könnte den RSS-Feed ebenfalls nutzen.

2. Wie ermittle ich meinen aktuellen Standort

Im Prinzip wäre GPS das ideale Werkzeug um den aktuellen Standort auf der Welt bestimmen zu können. Da ich jedoch nur ein Notebook auf meinen Dienstreisen zur Verfügung habe, fällt das mit dem GPS aus, denn die wenigsten Notebooks verfügen über GPS – meines schon gar nicht.

Eine weitere Möglichkeit meinen Standort zu bestimmen wäre über die IP Adresse, mit der sich mein Computer über den jeweiligen Provider mit dem Internet verbindet. Nicht sehr genau, aber wenn es um die Zeitzone geht – genau genug.

Eine andere Alternative, die mir erst vor kurzem bekannt wurde, ist die Ermittlung des Standortes via HTML 5 – Voraussetzung hierfür sind ein Browser der diese neue Technologie unterstützt und aktiviertes JavaScript.

Die Umsetzung via HTML 5 ist zudem genauer als der Weg über die IP-Adresse. Ideal wäre also die Verknüpfung beider Techniken.

Da meine Seite aktuell mit der IP-Adresse arbeitet, möchte ich das als Basis der folgenden Abhandlungen nehmen.

3. Welche zusätzlichen Informationen kann ich noch anzeigen

Weitere Informationen bietet ASP.NET von allein. IP-Adresse, Sprache, Browser, Auflösung usw.

 

Die Umsetzung:

Wie schon erwähnt ist ein RSS-Feed nichts anderes als eine XML Datei. Diese wird als Antwort (Response) auf eine Anfrage (Request) vom Webservice zurückgegeben.

Im Prinzip also recht einfach

  1. Daten ermitteln
  2. XML erstellen
  3. Daten zurückgeben

Überlegung:

Welche Daten benötigen wir und welche Daten soll der RSS-Feed zusätzlich enthalten?

Im Prinzip benötigen wir nur drei Werte um die aktuelle Uhrzeit und Zeitzone übermitteln zu können.

  1. Die Zeitzone als ID – damit kann dann ganz einfach die passende Zeitzone auf dem Windows-PC gefunden werden.
    (Wie das auf einem MAC OS oder einem Linux Rechner umgesetzt werden kann wäre eine weitere Überlegung wert)
  2. Die Zeitverschiebung in Stunden (Als Basis gilt hier immer die koordinierte Weltzeit)
  3. Die Zeitverschiebung in Minuten (Als Basis gilt hier immer die koordinierte Weltzeit)

 

Alle weiteren Daten sind Beiwerk und blähen unseren RSS-Feed nur auf. Aber wer kommt denn schon ohne Beiwerk aus?

Interessant sind natürlich auch

  1. Die momentane IP-Adresse
  2. Die eingestellte Sprache
  3. Der aktuelle Ort (Stadt) bzw. das Land
  4. Die Region (hier kommen wir später darauf zurück)
  5. Die Geokoordinaten (geographische Länge und Breite)

Umsetzung:

Die erste Schwierigkeit besteht darin aus der IP-Adresse den aktuellen Standort zu ermitteln.

Hierfür gibt es eine Menge Webservices, die aber alle nicht sehr aktuell sind und ihre Daten nicht so einfach zur Verfügung stellen wollen.

Als die beste aller Möglichkeiten hat sich die MaxMind GeoLight City Datenbank in Verbindung mit dem Google Maps UserControl von SubGurim.net gezeigt.
Nachteil hier – die Datenbank ist 30MB schwer und muss jeden Monat aktualisiert werden, da sich die IP-Adressen ständig ändern. Was soviel heißt wie, je länger der Monat dauert je ungenauer die Angaben.

Abhilfe würde hier die kostenpflichtige Datenbank schaffen – diese ist zwar noch Größer wird aber in einem kürzeren Zyklus aktualisiert. Da ich das Ganze aber nur als Hobby-Projekt umsetzen will, sind mir die Kosten dafür zu hoch.

Die kostenpflichtige Datenbank gibt es ebenfalls hier (GeoCity) und kann natürlich auch mit dem gleichen UserControl betrieben werden.

Ich hab mich für das Binary Format der Datenbank entschieden, da diese Version in Verbindung mit dem SubGurim UserControl sehr schnell ist. Die Zugriffszeiten auf meinen RSS-Feed liegen bei etwa 0.5 Sekunden.

Das SubGurim Control wurde für ASP.NET 2.0 entwickelt, arbeitet aber auch im Framework 4 ohne Probleme.

Bindet man nun alles ein – ein Lesen der Dokumentation hilft wie immer weiter – reduziert sich der Code zur Ermittlung der Geokoordinaten auf

Dim location As Location = GetLocationFromIP(userIP)

Im Prinzip schon fast alles. Nur war es nicht unser Ziel die Geokoordinaten zu ermitteln, wir wollten die Uhrzeit und Zeitzone am aktuellen Standort ermitteln.

Anmerkung:

Die Klasse Location ist hier ein Teil des SubGurim.Net UserControls und enthält neben den GeoKoordinaten auch die ermittelte Stadt, das Land (beides als Klartext) und die Region als Kürzel (z.B. 02 = Bayern, 05 = Hessen).

Da ich für die nächsten Schritte keine weiteren Controls, Dll’s oder anderes frei verfügbares Werkzeug gefunden habe, musste ich die Verknüpfung der Standortdaten zur Zeitzone und das Decodieren des Regionkürzels selbst erledigen.

Überlegung:

Ein jeder Punkt dieser Welt gehört einer bestimmten Zeitzone an. Hier gilt es 3 Fälle zu beachten.

  1. Länder die als Ganzes einer Zeitzone angehören (z.B. Deutschland, Österreich, Schweiz)
  2. Länder die mehreren Zeitzonen angehören (z.B. USA, Russland, Indonesien)
  3. Gebiete die nicht erfasst werden können (Oceane und Wüsten)

1. Länder die als Ganzes einer Zeitzone angehören

Die einfachste Form, die Inhalte der Klasse Location können direkt zur Ermittlung der Zeitzone herangezogen werden.

Vereinfacht: Land = Zeitzone = Zeitverschiebung

2. Länder die mehreren Zeitzonen angehören

Nicht mehr ganz so einfach. Die Zeitzone wird hier anhand des Landes und der Region bestimmt.

Vereinfacht: Land (z.B. USA) – Region (z.B. CA – Kalifornien) = Zeitzone = Zeitverschiebung

Sonderfall: Eine Region enthält mehrere Zeitzonen (z.B. USA/Indiana – Eastern- und Central Time)

Hierfür habe ich noch keine Lösung – mir fehlen die genauen Daten – aber vermutlich wird es dann eine weitere Unterteilung anhand der ermittelten Stadt geben.

Land (z.B. USA) – Region (z.B. IN – Indiana) – Stadt (?) = Zeitzone = Zeitverschiebung

3. Gebiete die nicht erfasst werden können

Da es auf dem Meer oder in der Wüste keinen Provider bzw. keine Empfang gibt, kann dieser Fall ausgeschlossen werden.

Lösung hierfür wäre eine Ermittlung des Standortes via Geokoordinaten (GPS), was im Moment noch nicht umgesetzt wurde.

Die beschriebene Funktionalität hab ich in eine DLL gepackt, das alles beschreiben zu wollen würde hier aber zu weit führen.

Die Punkte 1. und 2. werden komplett durch eine List(of Structure) abgebildet, die alle Länder dieser Welt, inkl. den unter 2. beschriebenen Fällen, enthält.

    Public Structure myTimeZone
        Public Country As String
        Public Region As String
        Public TimeZoneInfo As TimeZoneInfo

        Public Sub New(ByVal c As String, ByVal r As String, ByVal tzi As TimeZoneInfo)
            Country = c
            Region = r
            TimeZoneInfo = tzi
        End Sub
    End Structure

Private mytimezones As New List(Of myTimeZone)

Die Klasse „TimeZoneInfo“ ist schon Bestandteil des Frameworks und bildet die auf dem jeweiligen System installierten Zeitzonen ab.

Die durch das SubGurim.Net UserControl bereitgestellten Informationen (Klasse Location) dienen somit als Filter für die Suche innerhalb der Liste. Die dadurch ermittelten Daten können nun den RSS-Feed füllen.

Erstellen eines RSS-Feeds:

Wie schon erwähnt ist ein RSS-Feed nichts anderes als eine XML-Datei welche durch eine Webseite zurückgegeben wird.

Dies kann auf vielfältige Art und Weiße geschehen.

Anfangs erstellte ich meinen Feed innerhalb einer WebForm (*.aspx). Später jedoch bin ich auf eine Methode gestoßen, die mir eleganter erschien, nämlich das Erstellen eines RSS-Feeds mittels eines „Generic Handlers“ (*.ashx)

Im Prinzip wird nichts anderes gemacht, als den kompletten Feed mittels LINQ zusammenzubauen und am Schluss als Response zurückzugeben.

Dim doc As New XDocument()

Dim rss As New XElement("rss")
rss.Add(New XAttribute("version", "2.0"))

Dim channel As New XElement("channel")
rss.Add(channel)

channel.Add(New XElement("title", "The TimeZoneNotifier RSS-Feed"))
channel.Add(New XElement("link", "http://TimeZoneNotifier.free-file-download.de"))
channel.Add(New XElement("description", "This site detects the timezone you're currently staying in !"))
channel.Add(New XElement("ttl", "60"))

Dim item As New XElement("item")

Channel.Add(item)

item.Add(New XElement("userIP", userIP))
item.Add(New XElement("userBrowser", userBrowser))
item.Add(New XElement("userLanguage", userLanguage))
item.Add(New XElement("userCity", userCity))
item.Add(New XElement("userRegion", userRegion))
item.Add(New XElement("userLongitude", userLongitude))
item.Add(New XElement("userLatitude", userLatitude))
item.Add(New XElement("userTimeOffsetHours", userTimeOffsetHours))
item.Add(New XElement("userTimeOffsetMinutes", userTimeOffsetMinutes))
item.Add(New XElement("CurrentUTCTime", CurrentUTCTime.ToString))
item.Add(New XElement("userTimeZone", userTimeZone))

doc.Add(rss)

(Den RSS-Feed wie er dann ausgegeben wird, sehen Sie am Ende dieses Artikels)

Sind wir erst einmal hier angekommen, wurde die meiste Arbeit schon erledigt. Der Rest besteht nur noch im Anzeigen der ermittelten Daten.

Anzeigen der Daten mittels einer WebForm:

Hier zum Verständnis, noch der Code für die Anzeige der Daten.

Da wir den Feed mittels einer Webanwendung abfragen, sind manche Informationen für den RSS-Feed nicht sichtbar. Bei diesen Daten verwerfen wir die Informationen die der RSS-Feed enthält einfach und füllen die Ausgabe mit den Werten der WebForm.

Protected Sub Page_Load(ByVal sender As Object, _
                    ByVal e As System.EventArgs) Handles Me.Load

if Postback Then
'RSS-Feed holen
    Dim retRss As New Xml.XmlDocument
    retRss.Load("http://timezonenotifier.free-file-download.de/rss.ashx?ip=" & _
                Request.UserHostAddress)
    'IP-Adresse das Feeds stimmt
    Me.LabelIP.Text = retRss.SelectSingleNode("/rss/channel/item/userIP").InnerText
    'Wurde eine nicht gültige IP-Adresse erkannt -> Anzeigen der Daten abbrechen
    If Me.LabelIP.Text = "No valid IP-Adress !!" Then
        Exit Sub
    End If
    'Kein Browser im RSS-Feed vorhanden, da vom Server aus angefragt wird
    Me.LabelBrowser.Text = Request.Browser.Browser
    'Keine Sprache im RSS-Feed vorhanden, da vom Server aus angefragt wird
    Try
        Dim ci As New CultureInfo(Request.UserLanguages(0))
        Me.LabelLanguage.Text = ci.DisplayName
    Catch ex As Exception
        Me.LabelLanguage.Text = "Unknown"
    End Try
    'erkannte Stadt
    Me.LabelCity.Text = 
        retRss.SelectSingleNode("/rss/channel/item/userCity").InnerText
    'erkannte Region
    Me.LabelRegion.Text = 
        retRss.SelectSingleNode("/rss/channel/item/userRegion").InnerText
    'erkannte Geogr. Länge
    Me.LabelLong.Text = 
        retRss.SelectSingleNode("/rss/channel/item/userLongitude").InnerText
    'erkannte Geogr. Breite
    Me.LabelLat.Text = 
        retRss.SelectSingleNode("/rss/channel/item/userLatitude").InnerText
    'erkannte Zeitverschiebung
    Dim _offsethours As Integer = 
        CInt(retRss.SelectSingleNode("/rss/channel/item/userTimeOffsetHours").InnerText)
    Dim _offsetminutes As Integer = 
        CInt(retRss.SelectSingleNode("/rss/channel/item/userTimeOffsetMinutes").InnerText)
    'aktuelle Zeit am Standort berechnen
    Dim tempRSS As String = 
        retRss.SelectSingleNode("/rss/channel/item/CurrentUTCTime").InnerText
    Me.LabelCurrentTime.Text = 
        CDate(tempRSS).AddHours(_offsethours).AddMinutes(_offsetminutes).ToLongDateString & " - " & CDate(tempRSS).AddHours(_offsethours).AddMinutes(_offsetminutes).ToLongTimeString
    
    Me.LabelCurrentTimeDiff.Text = _offsethours.ToString & _ 
        " h " & _offsetminutes.ToString & " min"
    'erkannte Zeitzone
    Me.LabelCurrentTimezone.Text = 
        retRss.SelectSingleNode("/rss/channel/item/userTimeZone").InnerText
Else
    'kein Postback
End If
End Sub

Die Ergebnisse meiner Arbeit:

Das oben beschriebene hab ich unter http://timezonenotifier.free-file-download.de als ASP.NET Webseite veröffentlicht.
Den RSS-Feed gibt es unter http://timezonenotifier.free-file-download.de/rss.ashx
RSS-Feed (mein Standort)
<pre>

<rss version="2.0">
    <channel>
        <title>The TimeZoneNotifier RSS-Feed</title>
        <link>http://TimeZoneNotifier.free-file-download.de</link>
        <description>
            This site detects the timezone you're currently staying in !
        </description>
        <ttl>60</ttl>
        <item>
            <userIP>79.249.177.227</userIP>
            <userBrowser>Chrome</userBrowser>
            <userLanguage>Deutsch (Deutschland)</userLanguage>
            <userCity>Mering / Germany</userCity>
            <userRegion>Bayern</userRegion>
            <userLongitude>10,9833</userLongitude>
            <userLatitude>48,2667</userLatitude>
            <userTimeOffsetHours>2</userTimeOffsetHours>
            <userTimeOffsetMinutes>0</userTimeOffsetMinutes>
            <CurrentUTCTime>07.06.2011 09:40:14</CurrentUTCTime>
            <userTimeZone>
                (UTC+01:00) Amsterdam, Berlin, Bern, Rom, Stockholm, Wien
            </userTimeZone>
       </item>
    </channel>
</rss>

Quellen:

http://www.maxmind.com/app/geolitecity
http://de.googlemaps.subgurim.net/
http://lukencode.com/2010/05/19/ip-to-geo-location-in-asp-net-mvc/
http://www.aspcode.net/Creating-an-RSS-feed-for-your-ASPNET-site.aspx

Copyright:

Die Rechte der verwendeten Datenbanken und des UserControls liegt bei den Autoren.

Der angebotene RSS-Feed darf frei verwendet werden – eine Nennung der Quelle des Feeds bzw. der Adresse dieses Artikels wird vorausgesetzt.

Ein Dank geht an Sebastian Gross der mir einige Anregungen gegeben hat.

Dieser Service bleibt kostenlos, die Bedingungen zur Nutzung des RSS-Feed können sich jedoch jederzeit ändern.

Über den Autor

Michael Bernhard
Hobby-Programmierer von VB.NET, C# und ASP.NET Anwendungen. Hauptberuflich als Inbetriebnehmer bei der Böwe Systec GmbH beschäftigt. Vorzeigbare Projekte – TimeZone Notifier und TSV Neusäß Junioren.

kick it on dotnet-kicks.de

profile

Michael Bernhard

There are no comments.

Kommentar verfassen

View Comments (0) ...
Navigation