Newsfeeds können sehr praktisch sein. Schon mal an eine Interaktion von Feed <-> System Management Server oder Feed <-> Domain gedacht?
Ein praktisches Beispiel:
In einem Unternehmen werden regelmäßig Systemhotfixe, Systemupdates, Application Updates etc. verteilt. Dabei sollen die User aber vorher informiert werden damit sie wissen, das ein Update zur Installation ansteht oder das die Performance kurzfristig beeinträchtigt werden kann.
In der Regel gehen dann ellenlange Mails mit (für den User) unverständlichen Informationen durch das Unternehmen.
Man könnte aber auch einen (oder mehrere) zentrale(n) Newsfeed(s) anbieten. Einen für Hotfixe, noch einen für Office-Patches oder auch einen für Updates einer spezifischen Software (Visual Studio meinetwegen).
Großes Gerede, aber was brauchen wir?
Wie benötigen ein wenig ASP.Net 2 Webspace. Wenn vorhanden noch eine SQL-Datenbank, es reicht aber auch wenn man eine Access-Datenbank nutzt.
Dort legt man 2 Tabellen an:
CREATE TABLE Channels ( [id] [int] IDENTITY(1,1) NOT NULL, [title] [nvarchar](255) NULL, [description] [ntext] NULL, [managingeditor] [nvarchar](50) NULL, [webmaster] [nvarchar](50) NULL); CREATE TABLE Items( [id] [int] IDENTITY(1,1) NOT NULL, [title] [nvarchar](255) NULL, [description] [ntext] NULL, [pubdate] [datetime] NULL, [author] [nvarchar](50) NULL, [channel] [int] NULL, [published] [bit] NULL DEFAULT ((0)), [targetou] [ntext] NULL, [smscollection] [nvarchar](50) NULL, [clientlist] [ntext] NULL);
Die Tabellennamen sind selbsterklärend: Channels für die verfügbaren Feeds und Items für alle Nachrichten. Bei der Tabelle Items habe ich 3 Spalten um die Nachrichten genauer zu Verteilen:
In “targetou” kann ein spezifischer LDAP-String eingetragen werden, sodass später nur Clients die Nachricht bekommen die auch Mitglied der OU sind. Gleiches gilt für “smscollection”. Eine eingetragene Collection aus SMS stellt sicher, das nur Clients die in der Collection sind die Nachricht erhalten. Und die Spalte “clientlist” ist für spezifische Rechnerlisten. Dort sollen Semikolonseparierte FQDN-Namen von Rechnern eingetragen werden die die Nachricht erhalten sollen (z.B. zur Definition von Testfeldern).
Weiterhin benötigen wir eine Webseite Default.aspx die uns alle verfügbaren Feeds auflistet:
<%#eval("title") %><%#Eval("description")%> |
Ich habe eine Accessdatenbank in den App_Data Ordner gepackt, man kann aber auch andere Datenbanksysteme einsetzen. Wie man sieht, habe ich 2 Formate implementiert: RSS und ATOM.
Der Grund ist simpel: Im RSS ist nach Definition kein HTML-Code erlaubt. Im ATOM-Format ist dies erlaubt.
Fehlt uns noch die Datei “service.aspx” die letztendlich für die Auslieferung der Feeds zuständig ist.
Im Page_Load Ereignis müssen wir nur prüfen ob eine FeedID übergeben wurde.
If Request.QueryString("feed") Is Nothing Or _
Request.QueryString("feed").Trim = "" Then Exit Sub
Response.Clear()
Response.ContentType = "text/xml"
If Request.QueryString("Format") IsNot Nothing Then
Select Case Request.QueryString("Format").ToUpper
Case "ATOM" : Response.Write(GenerateAtomFeed)
Case Else : Response.Write(GenerateRSSFeed)
End Select
Else
Response.Write(GenerateRSSFeed)
End If
Response.End()
Weiterhin wird unterschieden ob ein spezielles Format gewünscht ist, per Defautl verwenden wir RSS.
Die 3 wichtigsten Funktionen zum Generieren der Feeds:
Private Function GetAllItems(ByVal channelid As String) As List(Of message)
Dim SqlAllItems As New AccessDataSource
SqlAllItems.DataFile = AppSettings("Database")
SqlAllItems.SelectCommand = AppSettings("AllItems_SelectCommand")
Dim retval As New List(Of message)
SqlAllItems.SelectParameters.Clear()
SqlAllItems.SelectParameters.Add("channel", channelid)
'alle nachrichten des channels
Dim itemlist As Data.DataView = SqlAllItems.Select(DataSourceSelectArguments.Empty)
For j As Integer = 0 To itemlist.Count - 1
Dim msg As New message
With msg
.title = itemlist(j)("title").ToString
.description = itemlist(j)("description").ToString
.clientlist = itemlist(j)("clientlist").ToString
.id = itemlist(j)("id").ToString
.pubdate = itemlist(j)("pubdate").ToString
.smscollection = itemlist(j)("smscollection").ToString
.targetou = itemlist(j)("targetou").ToString
.author = itemlist(j)("author").ToString
End With
retval.Add(msg)
Next
Return retval
End Function
Private Function GenerateAtomFeed() As String
Dim responsetext As New StringBuilder
Dim reqclient As String = Net.Dns.GetHostEntry(Request.UserHostName).HostName
responsetext.Append(" ")
'alle channels durchgehen
Dim chinfo As channel = GetChannelInfo(Request.QueryString("feed"))
responsetext.AppendFormat("", chinfo.title)
responsetext.AppendFormat("{0}", chinfo.description)
responsetext.AppendFormat("urn:uuid:{0}", chinfo.id)
responsetext.AppendFormat("{0}", chinfo.webmaster)
responsetext.AppendFormat("{0}", chinfo.managingeditor)
For Each tmp As message In GetAllItems(chinfo.id)
Dim additem As Boolean = False
If tmp.clientlist.Trim.Length > 1 Then
If tmp.clientlist.ToUpper.Contains(reqclient.ToUpper) Then
additem = True
End If
ElseIf tmp.smscollection.Trim.Length > 1 Then
If IsClientInCollection(reqclient, tmp.smscollection) Then additem = True
ElseIf tmp.targetou.Trim.Length > 1 Then
If IsClientInOU(reqclient, tmp.targetou) Then additem = True
Else
additem = True
End If
If additem Then
With responsetext
.Append("")
.AppendFormat("", tmp.title)
.Append("")
.AppendFormat("
{0}
", tmp.description)
.Append("")
.AppendFormat("{0}", tmp.pubdate)
.AppendFormat("{0}", tmp.author)
.AppendFormat("urn:uuid:{0}", tmp.id)
.Append("")
End With
End If
Next
responsetext.Append("")
Return responsetext.ToString
End Function
Private Function GenerateRSSFeed() As String
Dim responsetext As New StringBuilder
Dim reqclient As String = Net.Dns.GetHostEntry(Request.UserHostName).HostName
responsetext.Append("")
'alle channels durchgehen
Dim chinfo As channel = GetChannelInfo(Request.QueryString("feed"))
responsetext.Append("")
responsetext.AppendFormat("", chinfo.title)
responsetext.AppendFormat("{0}", chinfo.description)
responsetext.AppendFormat("{0}", chinfo.webmaster)
responsetext.AppendFormat("{0}", chinfo.managingeditor)
For Each tmp As message In GetAllItems(chinfo.id)
Dim additem As Boolean = False
If tmp.clientlist.Trim.Length > 1 Then
If tmp.clientlist.ToUpper.Contains(reqclient.ToUpper) Then
additem = True
End If
ElseIf tmp.smscollection.Trim.Length > 1 Then
If IsClientInCollection(reqclient, tmp.smscollection) Then additem = True
ElseIf tmp.targetou.Trim.Length > 1 Then
If IsClientInOU(reqclient, tmp.targetou) Then additem = True
Else
additem = True
End If
If additem Then
With responsetext
.Append("")
.AppendFormat("", tmp.title)
.AppendFormat("", tmp.description)
.AppendFormat("
{0}", tmp.pubdate)
.AppendFormat("{0}", tmp.author)
.Append("")
End With
End If
Next
responsetext.Append("")
responsetext.Append("")
Return responsetext.ToString
End Function
Ich hatte geschrieben, das wir prüfen wollen ob ein Rechner in einer bestimmten OU oder Collection enthalten ist:
Private Function IsClientInCollection(ByVal client As String, ByVal collection As String) As Boolean
Dim SqlSMSCollection As New AccessDataSource
SqlSMSCollection.DataFile = AppSettings("Database")
SqlSMSCollection.SelectCommand = AppSettings("SMSCollection_SelectCommand")
SqlSMSCollection.SelectParameters.Clear()
SqlSMSCollection.SelectParameters.Add("smscoll", collection)
SqlSMSCollection.SelectParameters.Add("client", client.Split(".")(0))
Dim dv As Data.DataView = SqlSMSCollection.Select(DataSourceSelectArguments.Empty)
If dv IsNot Nothing Then
If dv.Count > 0 Then
Dim clientsmscoll As String = dv(0)("Collection")
If clientsmscoll.ToUpper = collection.ToUpper Then Return True
End If
End If
Return False
End Function
Private Function IsClientInOU(ByVal client As String, ByVal ou As String) As Boolean
Dim SqlComputerOU As New AccessDataSource
SqlComputerOU.DataFile = AppSettings("Database")
SqlComputerOU.SelectCommand = AppSettings("ComputerOU_SelectCommand")
SqlComputerOU.SelectParameters.Clear()
SqlComputerOU.SelectParameters.Add("client", client.Split(".")(0))
Dim dv As Data.DataView = SqlComputerOU.Select(DataSourceSelectArguments.Empty)
If dv IsNot Nothing Then
If dv.Count > 0 Then
Dim clientou As String = dv(0)("distinguishedname")
clientou = clientou.Substring(clientou.IndexOf(","))
If String.Compare(clientou, ou, True) Then Return True
End If
End If
Return False
End Function
Jedem, der jetzt noch da ist dürfte aufgefallen sein, das die Application Settings aus der web.config fehlen:
Den Key “ComputerOU_SelectCommand” muss man gegebenfalls anpassen wenn man ein Mirror des Active Direcotys in einer Datenbank zur Verfügung hat. Wenn nicht, muss die Funktion “IsClientInOU” angepasst werden sodass direkt per LDAP geprüft wird.
Damit ist die ganze Show getan. Man sollte jetzt noch ein Admin-Interface zusammenschrauben.






0 Responses to “ASP.NET 2 in 30 minutes: Feeds made simple”