.NET – Blog https://blog.christianabele.de Christian Abele Wed, 24 Jul 2019 05:06:37 +0000 de-DE hourly 1 https://wordpress.org/?v=5.6 https://blog.christianabele.de/wp-content/uploads/2017/06/cropped-Unbenannt-1-32x32.jpg .NET – Blog https://blog.christianabele.de 32 32 SharePoint Workflow – DateTime und abweichende Stunden https://blog.christianabele.de/2019/07/24/sharepoint-workflow-datetime-und-abweichende-stunden/ https://blog.christianabele.de/2019/07/24/sharepoint-workflow-datetime-und-abweichende-stunden/#comments Wed, 24 Jul 2019 05:04:56 +0000 https://blog.christianabele.de/?p=534 „SharePoint Workflow – DateTime und abweichende Stunden“ weiterlesen]]> In einem SharePoint Workflow habe ich verschiedenste Berechnung mit Daten (Datum). Sei es, dass ich zwei Daten voneinander subtrahiere um eine Zeitspanne zu erhalten oder eine definierte Zeit zu einem Datum dazu rechne um das Fälligkeitsdatum einer Aufgabe zu bestimmen.

Dabei bin ich immer wieder auf das Selbe Problem gestoßen. Der Workflow reagierte auf meine gesetzte Daten manchmal 2h später als angegeben.

Nach langer Suche stellt sich heraus, dass das Problem darin besteht wie SharePoint Daten speichert. Tatsächlich konvertiert SharePoint Daten nach UTC….! Ich habe also Berechnungen mit Daten zweier verschiedenen Zeitzonen durchgeführt, da z.B. Benutzereingaben in meiner Umgebung in der aktuellen MEZ angegeben werden. Das Ergebnis lag somit manchmal 2h in der Vergangenheit, ein anderes mal 2h in der Zukunft.

Ich habe im SharePoint-Designer in einem 2010er Workflow noch keine möglichkeit gefunden ein Datum automatisiert in die richtige Zeitzone zu konvertieren. Lediglich ein paar Drittanbieter-Actions habe ich gesehen die das scheinbar können.

Wenn du also im Code/Workflow mit Datum arbeitest, vergesse nicht, in UTC zu konvertieren bzw. sicherzustellen, dass alle Eingaben und Vergleichsdaten in UTC vorliegen.!

]]>
https://blog.christianabele.de/2019/07/24/sharepoint-workflow-datetime-und-abweichende-stunden/feed/ 1
[c#] Objekte ohne Namensraum und Deklaration in XML serialisieren. https://blog.christianabele.de/2019/07/18/c-objekte-ohne-namensraum-und-deklaration-in-xml-serialisieren/ https://blog.christianabele.de/2019/07/18/c-objekte-ohne-namensraum-und-deklaration-in-xml-serialisieren/#comments Thu, 18 Jul 2019 11:04:33 +0000 https://blog.christianabele.de/?p=531 Heute wollte ich ein Objekt nach Plain XML ohne Namespaces und ohne XML-Deklaration serialisieren. Der XmlSerializer fügt jedoch einen Standard Namespace und die XML-Deklaration automatisch ein. Um das zu vermeiden gibt es die folgende Möglichkeit:

public string ToXml()
{
   //Ohne XML-Doc-Deklaration
   var settings = new XmlWriterSettings() {
                   Indent = false, OmitXmlDeclaration = true };
 
   var stream = new MemoryStream();
   using (XmlWriter xw = XmlWriter.Create(stream, settings))
   {
      //Leere Namespace-Deklaration
      var ns = new XmlSerializerNamespaces(
                         new[] { XmlQualifiedName.Empty });
      var x = new XmlSerializer(GetType(), "");
      x.Serialize(xw, this, ns);
   }
 
   return Encoding.UTF8.GetString(stream.ToArray()); 
}
]]>
https://blog.christianabele.de/2019/07/18/c-objekte-ohne-namensraum-und-deklaration-in-xml-serialisieren/feed/ 1
WinForms Cue TextBox https://blog.christianabele.de/2018/07/10/winforms-cue-textbox/ https://blog.christianabele.de/2018/07/10/winforms-cue-textbox/#respond Tue, 10 Jul 2018 09:22:52 +0000 https://blog.christianabele.de/?p=373 „WinForms Cue TextBox“ weiterlesen]]> Eine Möglichkeit mit wenig Aufwand eine TextBox mit einem Platzhalter (Cue-Banner) zu erstellen. Erstelle hierfür eine neue Klasse in deinem Projekt und füge den unten gezeigten Code ein, dann kompilieren. Platziere nun das neue Steuerelement/Control in deiner Form und setze die Cue-Eigenschaft.

Du erhälst eine Live-Vorschau des Cue-Wertes im Designer, lokalisiert auf die Spracheigenschaft des Formulars.

using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;

class CueTextBox : TextBox {
    [Localizable(true)]
    public string Cue {
        get { return mCue; }
        set { mCue = value; updateCue(); }
    }

    private void updateCue() {
        if (this.IsHandleCreated && mCue != null) {
            SendMessage(this.Handle, 0x1501, (IntPtr)1, mCue);
        }
    }

    protected override void OnHandleCreated(EventArgs e) {
        base.OnHandleCreated(e);
        updateCue();
    }

    private string mCue;

    // PInvoke
    [DllImport("user32.dll", CharSet = CharSet.Unicode)]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, string lp);
}

 

]]>
https://blog.christianabele.de/2018/07/10/winforms-cue-textbox/feed/ 0
Cache, Session, ViewState und warum überhaupt? https://blog.christianabele.de/2017/03/16/cache-session-viewstate-und-warum-ueberhaupt/ https://blog.christianabele.de/2017/03/16/cache-session-viewstate-und-warum-ueberhaupt/#respond Thu, 16 Mar 2017 18:10:17 +0000 https://blog.christianabele.de/?p=45 „Cache, Session, ViewState und warum überhaupt?“ weiterlesen]]> Bei einem meiner letzten Kundenprojekte kam kürzlich die Meldung rein, die Anwendung würde nicht mehr und/oder nur langsam reagieren. Kann nicht sein, dacht ich mir. Eine kurzer Blick in den IIS und die offenen Anfragen belehrte mich dann doch recht beeindruckend – es waren einige hunderte, gar tausende Anfragen offen. Ein paar Tests und einiges an Recherche später war der Übeltäter schnell ausgemacht. Sein Name – HttpSessionState.

Unwissenheit und Faulheit brachte mich dazu das Session-Objekt der aktuellen Sitzung als Caching-Mechanismus zu missbrauchen. Der Plan: Das Ergebnis sich oft wiederholender und statischer Datenbankabfragen zwischen zu speichern um dadurch die Anzahl der Zugriffe zu minimieren und die schlussendlich die Performance zu verbessern. Das Problem: Eine Anfrage an eine .NET-Webanwendung führt zu einem Session-Lock der erst nach Auslieferung der Antwort wieder gelöst wird. IIS arbeitet Anfragen die das Session-Objekt nutzen also nicht parallel sondern nacheinander ab.

Um zu dieser Erkenntnis zu kommen musste ich das Thema Caching jedoch erst einmal verstehen.

Die Session

Eine Session ist definiert durch eine bestimmte Zeit die zwischen einer Web-Anwendung und dem Benutzer geteilt wird.Jeder Benutzer einer Web-Anwendung hat eine eigene Session. In einer Session können Elemente/Objekte gespeichert werden die sich dann als diese für den Nutzer definiert. Zugriff auf die gespeicherten Werte erfolgt durch einen eindeutigen Schlüssel ähnlich einer Hash-Tabelle. Gelöscht wird eine Session durch die Anwendung selbst oder einem definierbaren TimeOut.

Session["key"] = value;

Das Session-Objekt sollte nur in Bezug auf den aktuellen Benutzer verwendet werden. Es speichert Informationen auf der Server-Seite. Der Unterschied zum Cache ist, dass der Cache auf globaler bzw. Anwendungsebene verfügbar ist. Jede Anfrage verwendet also den Selben Cache, unabhängig vom Benutzer. Es können zwar beliebig große Objekte in einem Session-Objekt gespeichert werden, jedoch belastet, besonders bei einem hohen Benutzer-Aufkommen extrem den Speicher, da jeder Benutzer eine eigene Kopie im Speicher vorhällt und außerdem wie eingangs bereits erwähnt, bei jeder Anfrage ein Session-Lock auftritt. Dieser kann nur umgangen werden, wenn man mittels Anfrage nur lesend auf die Session zugreift.

Ein möglicher Workaround wäre also den SessionState auf ReadOnly zu setzen.

<% @Page EnableSessionState="ReadOnly" %>

Dies funktioniert jedoch nur, wenn die Anfrage niemals schreibenden Zugriff auf das Session-Objekt benötigt. Darauf wollte ich mich nicht verlassen, also ging ich auf die Suche nach einer anderen, besseren Lösung um komplexe Datenstrukturen richtig zwischen zu speichern.

Der ViewState

Der ViewState ist ein verstecktes Formularfeld innerhalb einer .NET-Seite. Änderungen werden mittels Postback mitgeteilt. Alle Server-Steuerelemente haben einen eigenen ViewState der mittels EnableViewState-Eigenschaft gesteuert werden kann.

Befinden sich viele Daten im ViewState, büst eine Website an Performance ein, da bei jedem PostBack der gesamte ViewState zurück an den Server geschickt wird. Beliebige Daten können im ViewState gespeichert werden, jedoch gilt zu beachten das der ViewState nur bis zum Ende des LifeCycles der Seite bestand hat.

ViewState["key"] = value;

Der Cache

Den Cache kann man sich als Erinnerung der Anwendung vorstellen. Aus ihm kommt der gesamte Quellcode und in Ihm können beliebige Daten gespeichert werden die jederzeit und global wiederverwendet werden könne. Die perfekte Stelle also um das Ergebnis von komplexen Berechnungen zwischen zu speichern, vor allem wenn deren Datenbasis sich selten ändert. Ein Cache-Objekt wird entweder durch die Anwendung oder durch ein definierbares Ablaufdatum gelöscht und Daten können direkt aus dem Cache gebunden werden.

public void AddItemToCache(string key, object value)
{
if (Cache[key] == null){
Cache.Add(key,
value,
null,
DateTime.Now.AddSeconds(60),
TimeSpan.Zero,
CacheItemPriority.High,
null);
}
}

public void RemoveItemFromCache(string key)
{
if(Cache[key] != null)
Cache.Remove(key);
}

Fazit

Für meine Anforderung, nämlich Daten aus Performancegründen zwischen zu speichern, kommt eigentlich nur der Cache in Frage. Einmal hinterlegte Daten können Benutzerunabhängig geladen werden und beschleunigen so die Anwendung extrem. Es muss nur darauf geachtet werden das die Objekte im Cache bei einer Änderung in der Anwendung auch aktualisiert/entfernt/hinzugefügt werden, damit der Cache immer auf aktuellem Stand ist.

]]>
https://blog.christianabele.de/2017/03/16/cache-session-viewstate-und-warum-ueberhaupt/feed/ 0