Archiv für den Monat Januar 2015

AngularJS ng-pattern mit CamelCase Pattern als Beispiel


AngularJS bietet die unterschiedlichsten Direktiven zum Validieren von Eingabefeldern an und darunter befindet sich auch die Direktive “ng-pattern” mit der Eingabewerte über Reguläre Ausdrücke validiert werden können. Da ich mit Regulären Ausdrücken nicht so viel zu tun habe, habe ich mich bei der ersten Verwendung etwas schwer getan und leider gab es auch kein direktes Beispiel in der Dokumentation.

Ich habe mir einen Regulären Ausdruck erstellt der prüfen soll ob die Eingabe in “CamelCase” Schreibweise eingegeben wurde.

Regulärer Ausdruck:  /^((^[A-Z][a-z0-9]+)([A-Z][a-z0-9]+)*)$/

Wenn hier jemand eine effektiveren Ausdruck kennt dann freue ich mich sehr über einen passenden Kommentar.

In AngularJS kann der Reguläre Ausdruck direkt dem “ng-pattern” übergeben werden

<input type="text" 
             name="ccName" 
             data-ng-model="ViewModel.CamelCaseName" 
              data-ng-pattern="/^((^[A-Z][a-z0-9]+)([A-Z][a-z0-9]+)*)$/" 
              placeholder="Enter CamelCase String">

oder man speichert ihn im Controller in einer Variablen und übergibt diese dem “ng-pattern”. Achtung um das Regex Pattern keine Anführungszeichen setzen!

...
  $scope.ViewModel = {
        CamelCaseName: "TestCamleCase",
        CamelCasePattern: /^((^[A-Z][a-z0-9]+)([A-Z][a-z0-9]+)*)$/
    };
...

im “ng-pattern” die Variable setzen statt des Patterns.

<input type="text" 
             name="ccName" 
             data-ng-model="ViewModel.CamelCaseName" 
              data-ng-pattern="ViewModel.CamelCasePattern"
              placeholder="Enter CamelCase String">

Zum Erstellen und überprüfen von Regulären Ausdrücken verwende ich auch gern die folgende Webseite:

https://regex101.com/r/gM3qM0/1#javascript

Das ganze Codebeispiel findet man auch wieder in Codeplex.

Advertisements

IIS Applications regelmäßig aufrufen und vor dem Shutdown/Restart bewahren


Wenn eine Webseite im IIS nicht regelmäßig aufgerufen wird, dann stoppt der IIS die Seite und die Seite muss beim nächsten aufrufen wieder neu gestartet werden. Leider kann der Neustart einer Webseite unter Umständen recht lang dauern, denn hier kommt es darauf an wie aufwendig z.B. der Application Start ist und ob auch der Applicationpool neugestartet werden muss.

Ab dem IIS 8.0 bietet Microsoft zwar die Möglichkeit das man einem Applicationpool mit der Erweiterung “Anwendungsinitialisierung” für den IIS so konfigurieren kann das der Applicationpool automatisch startet . Für die Webseiten ist mir dies bisher leider nicht gelungen. Das IIS Modul steht auch für den IIS 7.0/7.5 zur Verfügung.

image

In den erweiterten Applicationpool Einstellungen kann man dann den Startmodus des Applicationpools festlegen.

image

Auf Anwendungsebene gibt es dann in den Erweiterten Einstellungen die Option “Vorabladen aktiviert”.

image

Leider scheint es beim Vorabladen immer noch Probleme zu geben, vor allem wenn man bei seinen Webseiten Windows-Authentifizierung für den Login verwendet, scheint diese Variante zumindest mit IIS 7.X nicht zu funktionieren.

Eine alternative Lösung ist z.B. eine Konsolenanwendung die auf dem Server ausgeführt wird, auf dem die Webseiten im gehostet werden. Die Konsolenanwendung  wird in regelmäßigen Abständen aufgerufen und durchsucht den lokalen IIS nach allen Webseiten und ruft diese auf.

static void Main(string[] args)
{
    //Diese DLL einbinden für den ServerManager:
    //c:\Windows\System32\inetsrv\Microsoft.Web.Administration.dll 

    //Servermanager verwenden um auf den lokalen IIS zuzugreifen
    ServerManager manager = new ServerManager();
    List<string> pages = new List<string>();

    // Die Auflistung aller Seiten auf dem Server ermitteln
    string sitedisplay = string.Empty;
    foreach (Site site in manager.Sites)
    {
        sitedisplay = sitedisplay + site.Name + ": ID= " + site.Id + "\n";
        string bindingdisplay = string.Empty;
        string port = string.Empty;
        string protokoll = "http";
        string host = "localhost";
        string appPath = string.Empty;

        foreach (Microsoft.Web.Administration.Binding binding in site.Bindings)
        {
            if (binding.EndPoint != null && (binding.Protocol == "http" || binding.Protocol == "https"))
            {
                bindingdisplay = "  Binding:";
                bindingdisplay += "\n   Host: " + binding.Host;
                bindingdisplay += "\n   Port: " + binding.EndPoint.Port;
                bindingdisplay += "\n   Protocol: " + binding.Protocol + "\n\n";

                port = binding.EndPoint.Port.ToString();
                protokoll = binding.Protocol;
                host = string.IsNullOrEmpty(binding.Host) ? "localhost" : binding.Host;
            }
        }

        foreach (Application app in site.Applications)
        {
            appPath = app.Path;
            //Alle Seiten URLs ermitteln
            var url = string.Format("{0}://{1}:{2}{3}", protokoll, host, port, appPath);
            pages.Add(url);
            Console.WriteLine(url);
        }

        sitedisplay = "\n" + sitedisplay + bindingdisplay;
    }

    Console.WriteLine(sitedisplay);
    
    //Callback Funktion für SSL-Zugriffe festlegen.
    ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(AcceptAllCertifications);

    //Alle Seiten die wir ermittelt haben mit einem WebRequest starten.
    //dieser WebRequest verwendet die Anmeldeinformationen der Konsolenanwendung.
    foreach (string page in pages)
    {
        Stopwatch stopwatch = new Stopwatch();
        try
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(page);
            request.Method = "GET";
            request.UseDefaultCredentials = false;
            request.PreAuthenticate = true;
            request.Credentials = CredentialCache.DefaultCredentials;
            Console.WriteLine("Page: {0} | Starting...", page);
            stopwatch.Start();
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            Console.WriteLine("Page: {0} | Status: {1}", page, response.StatusCode);
        }
        catch (Exception exception)
        {
            Console.WriteLine("Page: {0} | Status: {1} | Message: {2}", page, "Error", exception.Message);
        }
        finally
        {
            stopwatch.Stop();
            Console.WriteLine("Page: {0} | Startdauer: {1} ms \n\n", page, stopwatch.ElapsedMilliseconds);
        }
    }

    Console.WriteLine("DONE!");
    Console.ReadLine();
}

/// <summary>
/// Callback Funktion für SSL Aufrufe immer mit True bestätigen auch wenn das Zertifikat evtl. nicht valide ist. Für z.B. selbstsignierte Zertifikate im IIS
/// </summary>
public static bool AcceptAllCertifications(object sender, System.Security.Cryptography.X509Certificates.X509Certificate certification, 
                                           System.Security.Cryptography.X509Certificates.X509Chain chain, System.Net.Security.SslPolicyErrors sslPolicyErrors)
{
    return true;
}

Wichtig ist das der Benutzer der die Konsolenanwendung ausführt als lokaler Administrator eingerichtet ist, denn die Anwendung greift auf den lokalen IIS zu. Außerdem muss der Benutzer als Domainuser eingetragen sein, wenn die Anwendung auch auf Webseiten zugreifen soll für die Windows-Authentifizierung eingerichtet ist.

Der Quellcode steht auch unter Codeplex zur Verfügung.

.NET DateTime ISO Format Probleme in JavaScript für Chrome und Firefox


Wenn ich Werte von .NET per JSON an eine Webseite sende dann verwendete ich für Datumswerte aktuell meist die ToString Funktion mit “O”, was das Datum im ISO Format als String ausgibt (dachte ich). Leider hängt der Ausgabestring aber davon ab, wie das Date Objekt erstellt wurde und der Datumsstring kann daher entsprechend “variieren”. Denn wenn man DateTime.Now.ToString(“O”) verwendet dann wird ebenfalls die Zeitzone (bei mir UTC +1) im String mit ausgegeben z.B.:

2015-01-04T00:00:00.0000000+01:00

Wenn man aber ein neues DateTime Objekt erstellt mit

new DateTime(2015, 1, 1,15,12,0).ToString("O")

wird natürlich keine Zeitzone einberechnet und man erhält den folgenden String:

2015-01-01T15:12:00.0000000

Das stellt in der .NET Welt erst einmal noch kein Problem dar. Wenn man die Datums- und Zeitwerte aber im Browser benötigt und die Uhrzeit bearbeiten möchte, hat man aktuell ein Problem mit dem Format ohne dem UTC+1. Denn wenn der Wert verwendet wird, dann ergibt das in unterschiedlichen Browsern unterschiedliche Zeitangaben.

var dat = new Date("2014-12-15T14:59:29.7370000");
var datumStr = dat.toLocaleString();
//FireFox und IE: 15.12.2014 14:59:29
//Chrome: 15.12.2014 15:59:29

Daher achte ich aktuell darauf das ich das String Format für DateTime Werte “selbst” definiere und nicht auf die Standard ISO Konvertierung von .NET setze. Ich verwende z.B. den folgenden Format String, mit diesem kommt es nicht zum oben angegebenen Problem.

string datum = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
//Ausgabe: 2015-01-04T19:10:50.801Z

Quelle:

http://rupertmaier.wordpress.com/2014/04/25/parsing-c-datetime-without-timezone-indication-to-a-cross-browser-valid-date-object-2/