lundi 21 novembre 2011

C# WPF, Dynamic Loading / Late Binding / Reflection with AvalonEdit

The point here is to optionnaly allow to use AvalonEdit (formerly known as Avalon) in an (wpf) application.


The basics

Specific using:
using System.IO;
using System.Reflection;
using System.Xml; //only for "the not so basic"
As you can see, none of them concerns AvanlonEdit...

When to Load :
String AvalonEditDllName = "ICSharpCode.AvalonEdit.dll";
if ( File.Exists(AvalonEditDllName) ) {/*...*/}

How to load:
Assembly u = Assembly.LoadFile(Path.GetFullPath(AvalonEditDllName));

What to instanciate:
Type tAvalonEditTextEditor = u.GetType("ICSharpCode.AvalonEdit.TextEditor");
if ( tAvalonEditTextEditor != null ) {/*...*/}

How to instanciate:
System.Windows.UIElement aeui = 
    (System.Windows.UIElement)Activator.CreateInstance(tAvalonEditTextEditor);

From now, you can use your System.Windows.UIElement in your WPF form just like this:
MainGrid.Children.Add(aeui);
where MainGrid is, for example, a System.Windows.Controls.Grid.

The basics of properties

Do you want line numbers ?
First let's look for the property of the type :
PropertyInfo propShowLineNumbers = 
    tAvalonEditTextEditor.GetProperty("ShowLineNumbers");
Then let's make the property true :
propShowLineNumbers.SetValue(aeui, true, null);

The not so basic of properties

And what about syntax hihgligting ?? Good question indeed !
Some more types and properties:
Type tAvalonEditHightingLoader = 
    u.GetType("ICSharpCode.AvalonEdit.Highlighting.Xshd.HighlightingLoader");
Type tAvalonEditHightingManager = 
    u.GetType("ICSharpCode.AvalonEdit.Highlighting.HighlightingManager");

PropertyInfo propSyntaxHighlighting = tAvalonEditTextEditor.GetProperty("SyntaxHighlighting");
PropertyInfo spropAEHMInstance = tAvalonEditHightingManager.GetProperty("Instance");

And the loading himself (I try to keep the variables consistant with the previous pieces of code):
String XshdFileName = "t-sql.xshd";
using ( XmlTextReader reader = new XmlTextReader(XshdFileName) ) {
    propSyntaxHighlighting.SetValue( //let's set the property of the text editor
        aeui,
        tAvalonEditHightingLoader.InvokeMember(
            "Load", //by loading the xshd file with HightingLoader.Load
            BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | 
                BindingFlags.InvokeMethod,
            null, null,
                   //with the following parameters
            new Object[] { reader, spropAEHMInstance.GetValue(null, null) }
                   //one of them being the static property
                   //HighlightingManager.Instance
        ),
        null
    );
 }

mercredi 2 novembre 2011

Sales Force and WCF

Hello,
The following is a 2 hours testing session resulting of the following sentence : "Our client wants to interface our Production tool with Sales Force...". Of course I heard of Sales Force before, but nothing more.
I assume that you have downloaded the wsdl file from your Sales Force Account.
Then you use the svcutil tool to generate your proxy class. Something like :
"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\x64\svcutil" *.wsdl /language:C#

From this point you should realise that svcutil gives you a cs file but also an app.config part to use in your project to configure the proxy class.
Then the following code should list, on the console, the Accounts of your Sales Force Application. In this code "Soap" is a "false friend" coming from my minimalistic svcutil command line.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace sfBySoap {
  class Program {
    static void Main(string[] args) {
      try {
        SoapClient sfClient = new SoapClient();
        String sfLogin = "***@***.***";
        String sfPassword = "***";
        String sfSecurityToken = "***";
        LoginResult lr = sfClient.login(
          null, 
          sfLogin, 
          sfPassword + sfSecurityToken);
        Console.WriteLine("{0}\r\n{1}",
            lr.sessionId, 
            lr.serverUrl);
        SoapClient sc = new SoapClient(
            "Soap", 
            new EndpointAddress(new Uri(lr.serverUrl)));

        SessionHeader sh = new SessionHeader();
        sh.sessionId = lr.sessionId;

        QueryResult qr = sc.query(
              sh, //SessionHeader
              null, //QueryOptions
              null, //MruHeader
              null, //PackageVersion
              "select NAME, DESCRIPTION, TYPE, " +
                  "CREATEDBYID from Account");

        while (true) {
          foreach (Account a in qr.records) {
              Console.WriteLine("{0} - {1}\r\n    :{2}",
                  a.Name,
                  a.Type,
                  a.Description);
          }

          if (qr.done) {
              break;
          } else {
              qr = sc.queryMore(sh, null, qr.queryLocator);
          }
        }

        //sfClient.logout();
        sc.Close();
        sfClient.Close();
      } catch (Exception ex) {
          ExToConsole(ex);
      }
    }

    static void ExToConsole(Exception ex) {
        if (ex != null) {
            Console.WriteLine(ex.Message);
            ExToConsole(ex.InnerException);
        }
    }
  }
}

Here it is.... you are connected to Sales Force.

vendredi 2 septembre 2011

C# MongoDb - the really basics

I came from http://www.mongodb.org/display/DOCS/CSharp+Driver+Tutorial#CSharpDriverTutorial-InsertBatchmethod, where I spent a little hour.

I found that a more explicit sample was missing. So here it is the C# version of the article.

The real question I'm trying to answer is : how to map a POCO to MongoDb.

using System;

using MongoDB.Driver;
using MongoDB.Bson;
using MongoDB.Bson.Serialization;

namespace mdbBacASable {
  class Program {
    static void Main(String[] args) {
      try {
        String connectionString = 
            "mongodb://localhost:27017";
        MongoServer mdbServer = 
            MongoServer.Create(connectionString);
        MongoDatabase mdbTest = 
            mdbServer.GetDatabase("test");
        MongoCollection<BsonDocument> bsDocBooks = 
          mdbTest.GetCollection<BsonDocument>("books");
        bsDocBooks.RemoveAll();
        BsonDocument bsDocBook = new BsonDocument {
          { "Author", "Ernest Hemingway" },
          { "Title", "For Whom the Bell Tolls" }
        };
        
        bsDocBooks.Insert(bsDocBook);
        BsonDocument[] batch = {
          new BsonDocument {
            { "Author", "Kurt Vonnegut" },
            { "Title", "Cat's Cradle" }
          },
          new BsonDocument {
            { "Author", "Kurt Vonnegut" },
            { "Title", "Slaughterhouse-Five" }
          }
        };
        bsDocBooks.InsertBatch(batch);
          
        //-----------------------------------------------
        
        BsonClassMap.RegisterClassMap<Book>(cm => {
          cm.AutoMap();
          cm.SetIdMember(cm.GetMemberMap(c => c.Id));
        });
        MongoCollection<Book> Books = 
            mdbTest.GetCollection<Book>("books");
        Book oBook = new Book() { 
          Author = "JRR Tolkien", 
          Title = "Lord of the Ring" };
        Books.Insert(oBook);

        //----------------------------------------------
        
        Book Book = Books.FindOne();
        Console.WriteLine("{0} : {1}", 
          Book.Author, Book.Title);

        Console.WriteLine("\r\n------------------------\r\n");

        foreach ( Book b in Books.FindAll() ) {
          Console.WriteLine("{0} : {1} : {2}", 
            b.Id, b.Author, b.Title);
        }
      } catch (Exception ex) {
        Console.WriteLine(ex.Message);
      }
    }
  }

  public class Book {
    public ObjectId Id { get; set; }
    public String Author { get; set; }
    public String Title { get; set; }
  }
}

dimanche 28 août 2011

Managing default values for entities in EF: the from birth way

I recently face the problem of setting default value for entities when using entity framework.

After some walk around, here is a part of my actual solution.

This is not really the default values of the properties, but the default values of the types of the properties.

Please consider the following class:

using System;
using System.Linq;
using System.Reflection;


namespace AppXYZ.Entities {
    public static class EntityTools {
        public static readonly DateTime dtDef = new DateTime(1900, 1, 1, 0, 0, 0);

        public static void SetDefaults (object o) {
            Type T = o.GetType();
            foreach ( MemberInfo m in T.GetProperties() ) {
                PropertyInfo P = T.GetProperty(m.Name);
                switch ( Type.GetTypeCode(P.PropertyType) ) {
                    case TypeCode.String :
                        if ( P.GetValue(o, null) == null ) 
                            P.SetValue(o, String.Empty, null); 
                        break;
                    case TypeCode.DateTime :
                        if ( (DateTime)P.GetValue(o, null) == DateTime.MinValue )
                            P.SetValue(o, EntityTools.dtDef, null); 
                        break;
                }
            }
        }

        //T must have a constructor with 0 argument
        public static T GetNewEntity<T> () {
            T e;
            try {
                e = Activator.CreateInstance<T>();
            } catch {
                e = default(T);
            }
            SetDefaults(e);


            return e;
        }
    }
}

Since, I discover at least another way: the just on time way

mercredi 17 août 2011

Entity Framework: Code-First, Foreign Key One-To-Many

The object of this article is to (try to) illustrate two ways for configuring a one to many relation by using entity framework 4.1. For the need of the sample I use a very small and anecdotic part of the data model of Cegid Business Applications. That is I use code first on an existing database !!! :)

To help understanding differences, I comment code from one version to the other.

Of course you will need a connecion string:




Please note:

  • the activation of MARS

First: by using the Data Annotations

namespace ef {
    class Program {
        static void Main (string[] args) {
             CegidContext cc = new CegidContext();
            foreach ( gThirdParty gtp in (from t in cc.gThirdParties where t.GBusinesses.Count() > 0 select t) ) {
                 Console.WriteLine("{0,-17} : {1}", gtp.T_TIERS, gtp.GBusinesses.Count());
            }
        }
    }

    [Table("AFFAIRE")]
    public class gBusiness {
        [Key]
         public string AFF_AFFAIRE {get; set;}
         public string AFF_LIBELLE { get; set; }
         public string AFF_TIERS { get; set; }
 
        [ForeignKey("AFF_TIERS")]
         public virtual gThirdParty GThirdParty { get; set; }
    }

    [Table("TIERS")]
    public class gThirdParty {
         public gThirdParty () { 
            GBusinesses = new List<gBusiness>();
        }

        [Key]
         public string T_TIERS { get; set; }
         public string T_LIBELLE { get; set; }
         public virtual ICollection<gBusiness> GBusinesses { get; set; }
    }


    /*public class gBusinessConfiguration
        : EntityTypeConfiguration<gBusiness> {
        public gBusinessConfiguration ()
            : base() {
            HasKey(p => p.AFF_AFFAIRE);
            HasRequired(p => p.GThirdParty).WithMany(t => t.GBusinesses).Map(x => x.MapKey("AFF_TIERS")); 
        }
    }

    public class gThirdPartyConfiguration
        : EntityTypeConfiguration<gThirdParty> {
        public gThirdPartyConfiguration ()
            : base() {
            HasKey(p => p.T_TIERS);
        }
    }*/    
    
    public class CegidContext : DbContext {
        public DbSet<gBusiness> gBussinesses { get; set; }
        public DbSet<gThirdParty> gThirdParties { get; set; }

        /*protected override void OnModelCreating (DbModelBuilder modelBuilder) {
            modelBuilder.Configurations.Add(new gBusinessConfiguration());
            modelBuilder.Configurations.Add(new gThirdPartyConfiguration());
            base.OnModelCreating(modelBuilder);
        }*/
    }
}

Second: by using the fluent API

namespace ef { 
    class Program { 
        static void Main (string[] args) {
            CegidContext cc = new CegidContext();
            foreach ( gThirdParty gtp in (from t in cc.gThirdParties where t.GBusinesses.Count() > 0 select t) ) {
                 Console.WriteLine("{0,-17} : {1}", gtp.T_TIERS, gtp.GBusinesses.Count());
            }
        }
    }

    [Table("AFFAIRE")]
    public class gBusiness { 
        //[Key] 
         public string AFF_AFFAIRE {get; set;} 
         public string AFF_LIBELLE { get; set; } 
         //public string AFF_TIERS { get; set; } 
              
        //[ForeignKey("AFF_TIERS")] 
         public virtual gThirdParty GThirdParty { get; set; } 
    }

    [Table("TIERS")] 
     public class gThirdParty { 
         public gThirdParty () { 
            GBusinesses = new List<gBusiness>(); 
        }

        //[Key] 
         public string T_TIERS { get; set; } 
         public string T_LIBELLE { get; set; } 
         public virtual ICollection<gBusiness> GBusinesses { get; set; } 
    }

    public class gBusinessConfiguration 
       : EntityTypeConfiguration<gBusiness> { 
        public gBusinessConfiguration () 
           : base() { 
           HasKey(p => p.AFF_AFFAIRE); 
           HasRequired(p => p.GThirdParty).
               WithMany(t => t.GBusinesses).
               Map(x => x.MapKey("AFF_TIERS")); 
       } 
    }

    public class gThirdPartyConfiguration 
        : EntityTypeConfiguration<gThirdParty> { 
         public gThirdPartyConfiguration () 
            : base() { 
            HasKey(p => p.T_TIERS); 
        } 
    }

    public class CegidContext : DbContext { 
         public DbSet<gBusiness> gBussinesses { get; set; } 
         public DbSet<gThirdParty> gThirdParties { get; set; }
 
         protected override void OnModelCreating (DbModelBuilder modelBuilder) { 
            modelBuilder.Configurations.Add(new gBusinessConfiguration()); 
            modelBuilder.Configurations.Add(new gThirdPartyConfiguration()); 
            base.OnModelCreating(modelBuilder); 
        } 
    } 
}

Enjoy

Pending question:

  • How to avoid lazy loading and force explicit loading as Linq to SQL allows with DataLoadOption in the DataContext.

Edit -----


About not lazy, here is the way: cc.gThirdParties.Include("GBusinesses")

lundi 1 août 2011

Ninject by the sample I

Here you will find 2 samples that I wrote to help me materializing the "magic" of Ninject and more generally of DI.

using System;

using Ninject;
using Ninject.Modules;

namespace simplInject {

class Program {
    static void Main (string[] args) {
        IKernel ik = new StandardKernel(new imod());
                  
        //constructor with 2 interfaces.
        I3 c = ik.Get<I3>(); // will "magically" instanciate C1 and C2 instances from the binding
        Console.WriteLine("{0} with {1} C1 instance", c.concat, C1.cpt);
        //constructor with 1 interface and 1 parameter.
        I4 c4 = ik.Get<I4>(); // // will "magically" instanciate another C1 instance from the binding
        Console.WriteLine("{0} with {1} C1 instance", c4.concat, C1.cpt);
    }
}

class imod : NinjectModule {
    public override void Load () {
        //Here the WithconstructorArgument is to trace the binding in the main method.
        Bind<I1>().To<C1>().WithConstructorArgument("s", "string I");
        Bind<I2>().To<C2>().WithConstructorArgument("s", "string II");
        Bind<I3>().To<C3>();
        Bind<I4>().To<C4>().WithConstructorArgument("s", "string III");
   }

}

public interface I1 {
    string s1 { get; set; }
}
public interface I2 {
    string s2 { get; set; }
}
public interface I3 {
    string concat { get; }
}
public interface I4 {
     string concat { get; }
}

public class C1 : I1 {
    public static int cpt = 0;
    private int _id;
    string _s;
          
    public C1 (string s) {
        _id = C1.cpt++;
        _s = s;
    }

    public int Id { get { return _id; } }
 
    public string s1 {
        get { return this._s; }
        set { this._s = value; }
    }
}

public class C2 : I2 {
    string _s;

    public C2 (string s) {
        this._s = s;
    }

    public string s2 {
        get { return this._s; }
        set { this._s = value; }
    }
}

public class C3 : I3 {
    I1 _c1; I2 _c2;
          
    public C3(I1 c1, I2 c2) {
        _c1 = c1; _c2 = c2;
    }

    public string concat {
        get { return _c1.s1 + " " + _c2.s2; }
    }
}

public class C4 : I4 {
    I1 _c1; string _s;

    public C4 (string s, I1 c1) {
        _c1 = c1;
        _s = s;
    }

    public string concat {
        get { return _s + " " + _c1.s1; }
    }
}

}