C# TypeProviders ?!

Last week at the great community conference NRW Conf 2013 in Wuppertal i heard Steffen Forkmann speaking about F# TypeProviders. This was the second time i listened to this topic – sometimes it needs a repetitive consumption of a topic to trigger a reaction.

Excited by the F# TypeProviders i tried to also have TypeProviders in C#.

As an example i have written the Regex TypeProvider in C#.

Unfortunately the C# can not infer dynamically generated types like F# interactive does. So the type information is not available at edit time.

Editor View

The debugger instead can see the dynamically generated type and show the properties.

Debugger View

For full source to try yourself see GitHub:

https://github.com/FrankPfattheicher/CSharpx

I am interested in your opinion about the usefulness of this approach.

Veröffentlicht unter Uncategorized | 1 Kommentar

WPF Application with Current Culture

This is a personal snippet reminder Zwinkerndes Smiley

      FrameworkElement.LanguageProperty.OverrideMetadata(
                      typeof(FrameworkElement),
                      new FrameworkPropertyMetadata(XmlLanguage.GetLanguage(CultureInfo.CurrentCulture.IetfLanguageTag)));

(untwitterable)

Veröffentlicht unter Uncategorized | Kommentar hinterlassen

Mein Traum vom Open Space Süd 2014

Bereits vier Mal haben wir mit der .NET User Group Karlsruhe den .NET Open Space Süd in Karlsruhe veranstaltet. Wie die letzten Male war es ein ungemein interessantes Ereignis.

Meine Hauptgründe für diese Veranstaltung sind der ungetrübte Blick auf aktuelle Trends und noch mehr der unglaubliche Motivationsschub, den ich mitnehmen kann.

Selbstverständlich freue ich mich jedes mal wieder alte und neue Gesichter zu sehen
“Meet your timeline Zwinkerndes Smiley

Trotzdem gibt es bei dieser Veranstaltung Verbesserungspotential!

Was mich immer so ein Bisschen stört, ist, dass obwohl es der Sinn und Zweck eines Open Space ist, Gespräche unterbrochen werden, weil einige „noch mal schnell ins Hotel” oder “kurz nach Hause” wollen, der Veranstaltungsort für die Party gewechselt wird oder auch einige mit dem angebotenen Kaffee nicht zufrieden sind und sich deshalb anderweitig versorgen – ein kommen und gehen…

Mein Traumvorstellung ist ein kombinierter Ort für die Veranstaltung und die Übernachtung der Gäste. Man kann sich jederzeit für eine kurze Zeit ausklinken, wenn man eine Pause benötigt.

Da ich mit meinem Traum nicht bis zum nächsten Jahr warten konnte hab ich mich gleich auf die Suche gemacht.

Hier ist mein Traum für einen künftigen Open Space

Das Forum Hohenwart für Bildung und Begegnung:

http://www.hohenwart-forum.de/

Hohenwart3

  • Alle Teilnehmer finden hier ein Zimmer für die Zeit der Veranstaltung
  • Es gibt mehr als ausreichend Räume unterschiedlicher Größe
  • Der gesamte Bereich ist mit entsprechender Technik ausgerüstet
  • Neben den Räumen stehen vielfältige Außenbereiche zur Verfügung
  • Auch die Verpflegung ist geregelt
  • Mitten im Grünen für kurze Ausflüge zur Entspannung oder Vertiefung
  • Abseits von Lärm und sonstigen Ablenkungen
  • Die Kosten pro Person sind überschaubar
  • Sponsoren haben die Möglichkeit sich zu präsentieren

Hohenwart1

In dieser Umgebung können stundenlang anregende Gespräche stattfinden.

Hohenwart4

Bis in die späte Nacht…

Hohenwart2

Überall stehen weitere Sitzgruppen zur Verfügung.

Hohenwart5

Leider ist kein Termin mehr für 2014 frei!!!

Ich finde diese “Location” so interessant, dass ich mich um eventuelle Termine für 2015 oder 2016 bemühen werde.

Mein Wunsch an Euch ist eine Rückmeldung, wie Ihr zu einem Open Space in dieser Form steht. Welche Bedenken und Einwände sind da?

Erwartungsvolle Grüße aus Karlsruhe

Frank

Veröffentlicht unter Open Space | Verschlagwortet mit | 6 Kommentare

MongoDB Client-Trigger mit Reactive Extensions (Rx)

Ich bin also nicht so der Datenbanktyp, deshalb habe ich mich beim aktuellen Projekt für NoSQL entschieden. Ich denke man findet nur in einem wirklichen Projekt die Schmerzen einer Technologie. Ich will auch nicht in JavaScript programmieren, also ist meine Software in C# implementiert.

Ziel

Eine meiner ersten Anforderungen war, einen clientseitigen Trigger zu bekommen, der von der Datenbank ausgelöst wird, wenn ein Datensatz geändert wird – kann die Datenbank natürlich nicht so. Damit’s später auch schön zu verwenden ist wollte ich es mit den Reactive Extensions implementieren.

So soll’s verwendet werden:

      var elementsChanged = new MongoTrigger(dbClient)
.Where(trigger => trigger.Context == "MyDatabase.Elements");
      elementsChanged.Subscribe(trigger => MessageBox.Show(trigger.ToString()));

Ich habe eine Datenbank “MyDatabase” mit einer Collection “Elements”. Immer wenn Änderungen in dieser Collection erfolgen soll die angegebene Funktion (hier Lambda mit MessageBox) ausgeführt werden.

Der Vorteil ist die Verwendung der Reactive Extensions mit deren Hilfe ganz Einfach eine Filterung über Linq oder die Ausführung auf einem anderen Thread mit ObserveOn möglich.

Recherche

Nach kurzer suche im Internet findet man den Hinweis, dass alle Änderungen der Datenbank bei replizierten Installationen in der Collection oplog gespeichert werden.

Diese Implementierung erfordert, dass die Datenbank als Replica Set konfiguriert ist! (Mehr zu Replikation)

Der nächste Hinweis ist die Existenz von sogenannten tailablen Cursorn. Alles zusammen ergibt eine Abfrage, die bei neuen Einträgen das nächste Ergebnis liefert. Das ist im Prinzip schon die Anforderung für IObservable!

Da die Abfrage natürlich im MoveNext blockiert bis der nächste Eintrag erzeugt wird ist ein Backgroundworker notwendig der das asynchron erledigt.

Implementierung

Damit die Ereignisse alle Änderungsinformationen mitliefern können also zunächst mal eine TriggerArgs Klasse. Damit diese universell eingesetzt werden kann ist die id als string angegeben.

using MongoDB.Bson;
 
namespace ReactiveMongo
{
  
class MongoTriggerArgs
  {
    
public string Context { get; private set
; }
    
public string Operation { get; private set
; }
    
public string Id { get; private set
; }
    
public BsonDocument Document { get; private set
; }
     public MongoTriggerArgs(string context, string operation, string id, BsonDocument document)
     {
       Context = context;
       Operation = operation;
       Id = id;
       Document = document;
     }
    
public override string
ToString()
     {
      
return string.Format("{0}:{1}[{2}]", Operation, Context, Id);
     }
   } }

Als Context wird die Datenbank und die Collection mit Punkt getrennt angegeben (siehe oplog). Operation wird als “u”, “i”, “d” für update, insert, delete angegeben.

In Document steht der gesamte neue Datensatz zur Verfügung.

Hier also die Implementierung:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Threading;
using MongoDB.Bson;
using MongoDB.Driver;
using MongoDB.Driver.Builders;
 
namespace ReactiveMongo
{
  
class MongoTrigger : IObservable<MongoTriggerArgs>, IDisposable
  {
    
private readonly List<IObserver<MongoTriggerArgs
>> observers;
    
private readonly MongoCollection
opLog;
    
private readonly BackgroundWorker
trigger;
    
public MongoTrigger(MongoClient
client)
     {
       observers =
new List<IObserver<MongoTriggerArgs
>>();
      
var local = client.GetServer().GetDatabase("local"
);
       opLog = local.GetCollection(
"oplog.rs"
);
       trigger =
new BackgroundWorker { WorkerSupportsCancellation = true
};
       trigger.DoWork += TriggerOnDoWork;
       trigger.RunWorkerAsync();
     }
    
private void TriggerOnDoWork(object sender, DoWorkEventArgs
doWorkEventArgs)
     {
var tmax = opLog.FindAllAs<BsonDocument>()
.SetSortOrder(SortBy.Descending(new string[] {"ts"}))
.SetLimit(1)
.First();
var timeStamp = (BsonTimestamp)tmax["ts"];
      
while
(!trigger.CancellationPending)
       {
        
var cursor = opLog.FindAs<BsonDocument>(Query.GTE("ts"
, timeStamp))
                     .SetFlags(
QueryFlags.AwaitData | QueryFlags.TailableCursor | QueryFlags
.NoCursorTimeout)
                     .SetSortOrder(
SortBy.Ascending("$natural"
));
        
using (var enumerator = (MongoCursorEnumerator<BsonDocument
>)cursor.GetEnumerator())
         {
enumerator.MoveNext();
          
while
(!trigger.CancellationPending)
           {
            
if
(enumerator.MoveNext())
             {
              
var
document = enumerator.Current;
              
if (document != null
)
               {
                
Debug
.WriteLine(document.ToString());
                
var context = document["ns"
].AsString;
                
var operation = document["op"
].AsString;
                
var doc = document["o"
].AsBsonDocument;
                
var id = doc["_id"
].AsBsonValue.ToString();
                 NextTrigger(
new MongoTriggerArgs
(context, operation, id, doc));
                 timeStamp = (
BsonTimestamp)document["ts"
];
               }
             }
            
else
            {
              
if
(enumerator.IsDead)
               {
                
break
;
               }
              
if
(!enumerator.IsServerAwaitCapable)
               {
                
Thread.Sleep(TimeSpan
.FromMilliseconds(100));
               }
             }
           }
         }
       }
     }
    
public IDisposable Subscribe(IObserver<MongoTriggerArgs
> observer)
     {
      
if
(!observers.Contains(observer))
         observers.Add(observer);
      
return new Unsubscriber
(observers, observer);
      }
    
private class Unsubscriber : IDisposable
    {
      
private readonly List<IObserver<MongoTriggerArgs
>> unsubscribeObservers;
      
private readonly IObserver<MongoTriggerArgs
> unsubscribeObserver;
      
public Unsubscriber(List<IObserver<MongoTriggerArgs>> observers, IObserver<MongoTriggerArgs
> observer)
       {
         unsubscribeObservers = observers;
         unsubscribeObserver = observer;
       }
      
public void
Dispose()
       {
        
if (unsubscribeObserver != null
&& unsubscribeObservers.Contains(unsubscribeObserver))
           unsubscribeObservers.Remove(unsubscribeObserver);
       }
     }
    
private void NextTrigger(MongoTriggerArgs
args)
     {
      
foreach (var observer in
observers)
       {
         observer.OnNext(args);
       }
     }
    
public void
EndTransmission()
     {
      
foreach (var observer in
observers.ToArray())
        
if
(observers.Contains(observer))
           observer.OnCompleted();
       observers.Clear();
     }
    
public void
Dispose()
     {
      
if (trigger != null)
       {
         trigger.CancelAsync();
       }
     }
   } }

Dies ist die erste Version der Implementierung, in ein paar Stunden erstellt. Ich denke, dass sich beim konkreten Einsatz noch Änderungen und Erweiterungen ergeben.

Link: Daniel Weber: HACK: Creating triggers for MongoDB

Ich bin dankbar für Anregungen…

Veröffentlicht unter Uncategorized | 1 Kommentar

NuGet Addin für MonoDevelop auch unter Ubuntu 12.10

Dank Matt Ward ist ein NuGet Addin für MonoDevelop verfügbar. Er hat es von der SharpDevelop Implementierung für MonoDevelop portiert. Es steht auf GitHub zum Download bereit.
Leider kann es erst ab Mono Version 3.0.5 installiert werden. Verwendet man MonoDevelop unter dem aktuellen Ubuntu 12.10 (Quantal Quetzal) ist MonoDevelop leider nur in der Version 3.0.3 verfügbar.
Ich habe das Addin für diese Version neu erstellt und ein entsprechendes Installationspaket zusammengestellt. Das ermöglicht den Einsatz unter Ubuntu und vereinfacht die Installation.

Update 10.2.2013: NuGet Addin V0.4
Download hier (Installationspaket für Ubuntu)

Veröffentlicht unter Uncategorized | 9 Kommentare

Siemens liefert Barbie-Puppen

Wir schreiben das Jahr 2021. Wieder erwarten ist die Welt vor neun Jahren nicht untergegangen. Die Mayas meinten mit dem bevorstehenden Ende nicht den Untergang der Welt wie wir sie kennen sondern nur das Ende einer Ära.

Nachdem sich Microsoft erfolgreich von der Herstellung von Business-Software verabschiedet hat und nun Consumer-Produkte vertreibt können sich andere Firmen nicht mehr halten!

Der Vorstand der Siemens AG hat festgestellt, dass in anderen Marktsegmenten wie der Spielzeugbranche Milliardenumsätze gemacht werden. In diesem Marktsegment hat Siemens bis dato keinerlei Marktanteil. Eine globale Umorientierung soll dies ändern.

Der von internen Uneinigkeiten mitgenommene Vorstand hat entschieden, dass ab der nächsten Produktserie neben den Retro-Produkten die entsprechenden Spielzeuge geliefert werden. Ergänzt wird das Angebot durch die neuen Simone-Puppen.

Die Altvorderen sagten zu so was schon: Schuster bleib bei deinen Leisten…

Veröffentlicht unter Uncategorized | Kommentar hinterlassen

Meine! Windows Roadmap

Jede Projektmanagement-Strategie fordert, dass zunächst ein Ziel/Produkt definiert werden soll, damit alle Beteiligten wissen wo die Reise hin gehen soll.

image

Was Entwicklern für Windows momentan fehlt ist eben diese Ziel!

Der große Trampel Steve hat dazu nur die Worte: Windows, Windows, Windows, … (nur lauter und mit aufstampfen)

Angefangen hat das Drama mit Windows Phone 7, das auch mit Mango keine wirkliche Bereicherung ist. Lieblos implementierte Features und teilweise fehlende Klassenimplementierungen. Ja, ich weiß, “Delivery is also a feature” – aber es sollte nicht das Einzige sein.

Jetzt stehen die WP7 Entwickler vor einem Scherbenhaufen und keiner will sagen wie es damit weiter gehen soll. Laufen denn WP7 Anwendungen auf WP8???

Ohne ein Ziel hat doch keiner Lust auf so eine Plattform zu setzen.

Die Fortsetzung kommt jetzt auf den Desktop. Was auf einem Tablett ganz gut funktioniert aber nicht auf meinem 30” am Arbeitsplatz. Acht mal acht Zentimeter große Kacheln und eine umständliche Bedienung mit der Maus.

Aus Entwicklersicht habe ich immer noch nicht klären können was nun mit .NET Anwendungen ohne WinRT auf ARM Plattform möglich sein wird. Und der unsägliche Schlingerkurs um .NET. Vor 10 Jahren begonnen hat man damals wohl alle Gegenargumente gesammelt, um sie jetzt selbst wieder anbringen zu können.

Also hier MEINE Roadmap:

  WP7 / WP8 Windows 8
Q2 2012 Marktanteil 1,4% fallend Consumer Preview
Q3 2012 Ankündigung WP8 Release Preview
Q4 2012   Release
Q1 2013 Marktanteil unter 1% Mehrere Milliarden in Werbung versenken
Q2 2013   Windows 8 Classic

Während ich WP7 keine weitere Beachtung schenke freue ich mich doch auf Windows 8 Classic, dann kann ich wieder vernünftig arbeiten.

Veröffentlicht unter Uncategorized | 1 Kommentar