#ASP.NET: Ausgabe manipulieren
Angenommen, Sie würden eine Webseite betreiben, die etwa BB-Code oder anderen Pseudocode für Formatierungen von Ausgaben verwendet. Sie hätten dann die unangenehme Aufgabe, ein entsprechendes Umformatieren aller BB-Code-Tags in die entsprechenden HTML-Tags bei jeder Ausgabe vorzunehmen. Da wäre es doch angenehmer, dies zentral erledigen zu lassen.
Für genau diesen Zweck ist die Eigenschaft Filter der HttpResponse-Klasse geschaffen worden. Diese erlaubt es, eine eigene Stream-Implementierung zu definieren, die eine Ausgabe … naja, filtert. Dabei ist das Schwierigste, diese Implementierung zu entwickeln, jedenfalls dann, wenn man nicht weiß, wie man es anstellen soll.
Die Lösung: Einfach die vorhandene Stream-Implementierung im Konstruktor des eigenen Streams übergeben lassen, in einer Instanzvariablen speichern und dann überall verwenden. Der eigene Filter erbt dabei zwingend von der Basisklasse System.IO.Stream und implementiert die abstrakten Methoden dieser Klasse.
Das sieht dann insgesamt etwa so aus:
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
/// <summary>
/// Eigene Stream-Implementierung zur Manipulation der Ausgabe
/// </summary>
public class CustomResponseFilter : Stream
{
private Stream stream;
/// <summary>
/// Konstruktor der Klasse
/// </summary>
public CustomResponseFilter(Stream stream)
{
this.stream = stream;
}
#region Standard-Implementierung verwenden
public override bool CanRead
{
get { return stream.CanRead; }
}
public override bool CanSeek
{
get { return stream.CanSeek; }
}
public override bool CanWrite
{
get { return stream.CanWrite; }
}
public override void Flush()
{
stream.Flush();
}
public override long Length
{
get { return stream.Length; }
}
public override long Position
{
get
{
return stream.Position;
}
set
{
stream.Position = value;
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return stream.Read(buffer, offset, count);
}
public override long Seek(long offset, SeekOrigin origin)
{
return stream.Seek(offset, origin);
}
public override void SetLength(long value)
{
stream.SetLength(value);
}
#endregion
Nun fehlt noch eine Methode, die für das Schreiben der Ausgabe notwendig und von der abstrakten Stream-Klasse auch erfordert wird: Write(). Und genau die beinhaltet nun den Code, der die Ausgabe manipulieren wird. Dabei wird folgende Vorgehensweise verwendet:
- Der übergebene Inhalt (ein Byte-Array) wird in eine Zeichenkette umgewandelt, um manipuliert werden zu können
- Die Manipulation findet auf der Zeichenkette statt
- Die Zeichenkette wird wieder in ein Byte-Array umgewandelt und per innerem Stream ausgegeben.
Im Code sieht das dann für ein [URL …]-Tag so aus:
/// <summary>
/// Schreibt den Output
/// </summary>
public override void Write(byte[] buffer, int offset, int count)
{
// Byte-Array in String umwandeln
string output = Encoding.UTF8.GetString(buffer);
// Zeichenkette suchen
string pattern = "\\[URL ([^\\]]+?)\\]";
string replacement = "<a href=\"$1\" target=\"_blank\">";
output = Regex.Replace(output, pattern, replacement,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
// Schließendes Element suchen
pattern = "\\[/URL\\]";
replacement = "</a>";
output = Regex.Replace(output, pattern, replacement,
RegexOptions.IgnoreCase | RegexOptions.Compiled);
// Wieder in Byte-Array umwandeln
byte[] result = Encoding.UTF8.GetBytes(output);
// ...ausgeben lassen
stream.Write(result, offset, count);
}
}
Somit ist der eigene Filter für die Ausgabe definiert. Wichtig ist, das wir einen Konstruktor haben, der den standardmäßig definierten Outputstream als Parameter entgegen nimmt und diesen für alle Ausgabeoperationen intern verfügbar macht.
Damit dieser Filter dann auch funktioniert, muss er noch aktiviert werden. Dies geschieht durch Zuweisung an die Eigenschaft Filter der Response-Eigenschaft einer Webseite oder gleich in der global.asax beim BeginRequest-Ereignis. Hier ist es auf Ebene einer einzelnen Seite implementiert:
<%@ Page Language="C#" AutoEventWireup="true" %>
<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
Response.Filter = new CustomResponseFilter(Response.Filter);
}
</script>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>BB-Code als Link</h2>
[URL http://www.aspextra.de]ASP.extra[/URL]
</div>
</form>
</body>
</html>
Wenn Sie den Filter nicht aktiviert hätten, würden Sie folgende Ausgabe im Browser sehen:
Ist der Filter aktivert, erscheint nicht etwa der BB-Code, sondern ein Link, der die entsprechende Webseite in einem neuen Fenster öffnet:
Den Code zu diesem Artikel können Sie hier herunterladen: OutputStream.zip
Kategorie: .NET, ASP.NET, Tipp Kommentieren »
