Archiv für den Monat Mai 2013

Serialisieren bzw. Deserialisieren von Objekten mit dem XmlSerializer


Wenn man ein Objekt mit C# und  XmlSerializer serialisiert, dann erhält man das serialisierte Objekt in einer XML Struktur als String zurück. Außerdem ist es möglich dieses XML Dokument über den XmlSerializer auch wieder zu deserialisieren und wieder das passende Objekt zu erhalten.

Ein einfacher Weg dies umzusetzen, stellen die folgenden drei Funktionen dar. Hier kann ein beliebiges “einfaches” Objekt von einem beliebigen Typ übergeben werden und serialisiert bzw. deserialisiert werden. Dabei handelt es sich nur um eine beispielhafte Umsetzung, um zu verdeutlichen wie einfach es sein kann ein Objekt in XML umzuwandeln.

/// <summary>
/// serialisieren der Übergebenen Daten
/// </summary>
/// <typeparam name="T">Der Typ der Serialisiert werden soll</typeparam>
/// <param name="obj">Das Objekt welches Serialisiert werden soll</param>
/// <returns>Serialisiertes Objekt als XML-String</returns>
public static string Serialize<T>(T obj)
{
    using (var writer = new StringWriter())
    {
        new XmlSerializer(obj.GetType()).Serialize(writer, obj);
        string xml = writer.GetStringBuilder().ToString();
        return xml;
    }
}

/// <summary>
/// Deserialisieren unseres Übergebenen XML Strings und als ref des Übergebenen Objektes zurückgeben
/// </summary>
/// <param name="xml">Der XML String aus dem das passende Objekt erstellt werden soll</param>
public static void Deserialize<T>(ref T obj, string xml)
{
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    StringReader reader = new StringReader(xml);
    object deserialized = serializer.Deserialize(reader);
    obj = (T)deserialized;
}

/// <summary>
/// Deserialisieren unseres Übergebenen XML Strings und zurückgeben des passenden Objektes
/// </summary>
/// <param name="xml">Der XML String aus dem das passende Objekt erstellt werden soll</param>
public static T Deserialize<T>(string xml)
{
    T obj = (T)Activator.CreateInstance(typeof(T));
    XmlSerializer serializer = new XmlSerializer(obj.GetType());
    StringReader reader = new StringReader(xml);
    object deserialized = serializer.Deserialize(reader);
    return (T)deserialized;
}
Advertisements

MVC Trace, Debugging, Routes und Requests im Browser auswerten mit glimpse


Beim Erstellen einer neuen MVC4 Webseite hatte ich, das Problem das der Aufbau der Seite “extrem” langsam war und ich hatte bereits ermittelt, das es an der DB nicht liegt. Daher habe ich nach einer Möglichkeit gesucht, den Seitenaufbau wie früher im Classic ASP.NET mit Trace anzeigen zu können. Dabei bin ich schnell auf das Tool glimpse gestoßen.

Bei glimpse handelt es sich um ein Plugin welches dem MVC Projekt z.B. per Nuget hinzugefügt werden kann. Die Installation per NuGet ist unkompliziert und geht schnell. In der web.config wird ein Eintrag hinzugefügt, mit dem sich glimplse schnell ein und ausschalten lässt. Hier einfach von defaultRuntimePolicy=“On“ auf defaultRuntimePolicy=“Off“ stellen um glimplse komplett zu deaktivieren.

<glimpse defaultRuntimePolicy="On" endpointBaseUri="~/Glimpse.axd">
 ....
</glimpse>

Ein sehr gutes und cooles Video mit den Entwicklern von glimpse findet Ihr hier, im Video wird gezeigt was man mit glimpse alles machen kann.

Wenn man glimpse eingerichtet und aktiviert hat in der web.config und man sein Projekt startet, kann man ganz einfach über die eigene Projekt URL “http://localhost:58901/Glimpse.axd” noch ein “Glimpse.axd” anhängen und die folgende Seite wird angezeigt.

image

Die beiden Links für “Turn Glimpse on” und “Turn Glimpse off” kann man sich am besten in seine Favoriten ziehen. Wenn man jetzt auf “Turn Glimpse on” klickt und auf seine Projektseite geht, siehst man rechts unten im Bildschirm ein kleines “Logo”

image

Klickt man auf das Logo erscheint die glimpse Übersicht und man kann auf alle wichtigen Debuginformationen zugreifen.

Man sieht z.B. welche Route verwendet wurde um die Seite zu laden, dabei sind die gelben Einträge immer die die verwendet/gefunden wurde.

image

Oder man Sieht wie lange es gedauert hat die Seite zu rendern und wo genau die Zeit “vergangen” ist.

image

Viele der Funktionen werden im oben verlinkten Video erläutert und gezeigt. Ich bin bzw. war sehr begeistert von glimpse, es kann einem wirklich gut helfen Fehler zu finden und Daten auszuwerten, von Ajax Aufrufen bis hin zu Remotenutzungen ist alles möglich (siehe Video).

MVC Custom/Benutzerdefinierte Messages “verwalten” und zwischen Views und Controllern übergeben und anzeigen – v2.0


Es ist schon eine Weile her, da habe ich in “Grundzügen” in einem Blogpost gezeigt wie man Messages (Meldungen) in MVC so erweitert, das man auch eigene Meldungen anzeigen kann und nicht nur Fehlermeldungen anzeigt. Das ganze habe ich jetzt ein wenig aufgebohrt und mit Twitter Bootstrap Alert Styles umgesetzt. Mit der neuen Methode, ist es möglich gleichzeitig beliebig viele Fehlermeldungen und Messages anzuzeigen, die zum einen z.B. aus dem Modelstate Fehlern zusammengesetzt werden und aus den eigenen Meldungen bestehen. Die eigenen Meldungen müssen hier keine Fehler sein, es kann sich z.B. um Positive Bestätigungen oder Warnmeldungen handeln.

image

Das ganze setzt sich aus einem HTML Helper zusammen der einfach im View aufgerufen wird und die Meldungen dann nur noch darstellt. Die eigenen Meldungen, die wir ausgeben wollen, werden dabei im TempData abgelegt. Diese Variable wir automatisch gelöscht, nach dem Sie einmal abgerufen wurde und wir müssen uns um “nichts” kümmern. Wobei die Messages durch die Modelvalidation, werden immer als Fehler dargestellt und aus dem Modelstate abgerufen.

/// <summary>
/// Prüft ob im TempData Messages hinterlegt wurden und wenn ja dann werden diese angezeigt.
/// nach einem Request ist Tempdata auch direkt wieder leer, ist nur für einen Request aktiv!
/// Außerdem wird überprüft ob die Modeldaten ebenfalls einen Fehler enthalten und dieser wird hier ebenfalls ausgegeben
/// 
/// http://stackoverflow.com/questions/4642845/asp-net-mvc-how-to-preserve-modelstate-errors-across-redirecttoaction
/// </summary>
/// <returns>HTML Konstrukt was eine Custom Message anzeigt.</returns>
public static MvcHtmlString ShowCustomMessage(this HtmlHelper helper)
{
    //Eine neue Messageliste initialisieren
    List<Message> messages = new List<Message>();

    //Prüfen ob der passende Einträge im TempData vorhanden sind, die wird dort selbst abgelegt haben
    if (helper.ViewContext.Controller.TempData[CustomMessage.TempMessageString] != null)
    {
        //den Tempdata Liste der Nachrichten abrufen
        messages = (List<Message>)helper.ViewContext.Controller.TempData[CustomMessage.TempMessageString];
    }

    //Nur prüfen ob Fehler im Modelstate sind, wenn dieser auch nicht valide ist.
    if (!helper.ViewData.ModelState.IsValid)
    {
        //Nach Meldungen die Vom System im Modelstatus abgelegt wurden suchen
        //Ebenfalls den aktuellen Modelstatus nach meldungen durchsuchen, dabei handelt es sich immer um Fehlermeldungen!
        foreach (var key in helper.ViewData.ModelState.Keys)
        {
            foreach (var err in helper.ViewData.ModelState[key].Errors)
            {
                //Bei den Meldungen im Modelstate handelt es sich immer um einen Fehler. Die Fehler dem Modelstate hinzufügen
                messages.Add(new Message(helper.Encode(err.ErrorMessage), MessageTypes.error));
            }
        }    
    }

    string html = string.Empty;
    //Unsere Messages erstellen. Dabei wird jede Message in einer eigenen Fehlermeldung ausgegeben und sortiert ausgeben von Fehler nach OK
    foreach (Message message in messages.OrderByDescending(p => p.MessageType))
    {
        //Festlegen um welchen Fehlertyp es sich handelt
        string errorClass = GetMessageTypeCssString(message.MessageType);

        //Den HTML String zusammenbauen mit den Messages
        html += string.Format("<div class=\"{0}\"><button class=\"close\" data-dismiss=\"alert\" type=\"button\">×</button>{1}</div>", errorClass, message.Text);
    }

    //Damit der HTML String auch als HTML auf der Webseite ausgegeben werden kann, diesen noch umwandeln und den Rückgabewert des Helpers anpassen.    
    return new MvcHtmlString(html);
}

/// <summary>
/// Gibt den passenden CSS Code für den übergebenen Messagetype zurück
/// </summary>
/// <param name="message">Der MessageType für den der passende CSS Code zurück gegeben werden soll</param>
private static string GetMessageTypeCssString(MessageTypes message)
{
    string errorClass = string.Empty;
    switch (message)
    {
        case MessageTypes.error:
            errorClass = "alert alert-error";
            break;
        case MessageTypes.warning:
            errorClass = "alert";
            break;

        case MessageTypes.ok:
            errorClass = "alert alert-success";
            break;

        case MessageTypes.message:
            errorClass = "alert alert-info";
            break;
        default:
            errorClass = "alert";
            break;
    }

    return errorClass;
}

Die eigenen Messages setzten sich dabei aus einem Messagestring und einem Messagetyp zusammen. Der Messagetyp gibt an um welche Art von Meldung es sich handelt, z.B. Fehler, Warnung, Ok oder Meldung.

/// <summary>
/// Gibt an, welcher MessageType auf der Oberfläche angezeigt werden soll, wird im Viewbag abgelegt.
/// </summary>
public enum MessageTypes
{
    ok,
    warning,
    error,
    message
}

/// <summary>
/// Wird zum Darstellen von Nachrichten auf der Webseite benötigt, wenn diese über Views hinweg "versendet" werden.
/// </summary>
public class Message
{
    public string Text { get; set; }
    public MessageTypes MessageType { get; set; }

    /// <summary>
    /// Konstruktor für die Message
    /// </summary>
    /// <param name="text">Der Text der angezeigt werden soll</param>
    /// <param name="messageTypes">Um die Art der Nachricht die angezeigt werden soll</param>
    public Message(string text, MessageTypes messageTypes)
    {
        MessageType = messageTypes;
        Text = text;
    }
}

Das Verwalten der CustomMessages wird mit der folgenden Klasse umgesetzt. Wichtig ist hier, das wir immer den Aktuellen Controller mit übergeben müssen, damit wir auf TempData zugreifen können um die Messages hinzufügen zu können. Im Tempdata befindet sich nur eine Liste mit den jeweils von uns zuletzt hinzugefügten CustomMessages und wenn wir eine neue Message hinzufügen, wird die Liste um diese Meldung erweitert.

/// <summary>
/// Custom Message, damit Nachrichten auch über Views hinweg dargestellt werden können.
/// </summary>
public class CustomMessage
{
    #region static
    /// <summary>
    /// Gibt eine Instanz von CustomMessage zurück um Benutzerdefinierte Messages über Views hinweg anzeigen zu können.
    /// http://stackoverflow.com/questions/4642845/asp-net-mvc-how-to-preserve-modelstate-errors-across-redirecttoaction
    /// </summary>
    /// <param name="controller">Der CurrentController damit auf TempData zugegriffen werden kann.</param>
    /// <returns></returns>
    public static CustomMessage CurrentMessage(Controller controller)
    {
        return new CustomMessage(controller);
    }
    #endregion

    #region Member
    /// <summary>
    /// Constante die für den Tempdata[TempMessageString] benutzt wird.
    /// </summary>
    public const string TempMessageString = "CMTempMessageString";

    /// <summary>
    /// Der aktuelle CurrentController um auf 
    /// </summary>
    public Controller CurrentController { get; set; }
    #endregion

    #region Konstruktor
    /// <summary>
    /// Initialisieren der Methode, der CurrentController wird benötigt damit man auf das TempData zurückgreifen kann
    /// </summary>
    /// <param name="controller">Der aktuelle CurrentController damit TempData verwendet werden kann</param>
    private CustomMessage(Controller controller)
    {
        CurrentController = controller;
    }
    #endregion

    #region Public Functions
    /// <summary>
    /// Hinzufügen der Custommessage zu den TempData, damit dieser Mittels des passendne HTMLHelpers 
    /// auf der passenden Seite angezeigt werden kann.
    /// </summary>
    /// <param name="message">Die Message die angezeigt werden soll</param>
    /// <param name="messageType">Der Messagetyp der angezeigt werden soll</param>
    public void AddMessage(string message, MessageTypes messageType)
    {
        if (message != null)
        {
            //Eine Liste erstellen, damit wird jetzt jede Meldung hinzugefügt und alle können angezeigt werden.
            List<Message> messages = (List<Message>) CurrentController.TempData[TempMessageString];
            //Wenn noch keine Nachrichten hinterlegt wurden, muss die Liste initialisiert werden
            if (messages == null)
            {
                messages = new List<Message>();
            }

            messages.Add(new Message(message, messageType));

            //Die Message im TempData hinterlegen, damit diese dann von der Passenden Helper Methode dargestellt werden kann.
            CurrentController.TempData[TempMessageString] = messages;
        }
    }
    #endregion
}

Das Hinzufügen von CustomMessages ist überall da möglich wo Ihr Zugriff auf euren Controller habt, ich übergebe meist auch an mein Model den aktuellen Controller, um gleich in der Logik die passenden Messages hinzufügen zu können.

 CustomMessage.CurrentMessage(this).AddMessage("Warnung 1", MessageTypes.warning);
 CustomMessage.CurrentMessage(this).AddMessage("Warnung 2", MessageTypes.warning);
 CustomMessage.CurrentMessage(this).AddMessage("Bitte passen Sie auf!", MessageTypes.message);
 CustomMessage.CurrentMessage(this).AddMessage("Speichervorgang erfolgreich", MessageTypes.ok);

Im View selbst wird nur der HTML Helper “ShowCustomMessage” aufgerufen und dieser rendert jeden Fehlermeldung in einer Eigenen Box.

<div class="row">
    <div class="span12">
        @Html.ShowCustomMessage()
    </div>
</div>

Damit das ganze auch “gut” aussieht, ist noch die Einbindung von Twitter Bootstrap notwendig. Ihr könnt aber auch selbst die HTML Templates an eure Bedürfnisse anpassen.