Tuesday, June 1, 2010

Lambdas as EventHandlers

At the moment I’m writing a guide to do design review for .NET 4.0 applications writen in C#. One of the small questions I had was what to do with event handlers that use lambda expressions and closures.

The problem of closures is that by using members that are on the scope of the object defining the lambda they create references to those members and can cause unexpected leaks.

One of the things I wanted to try is to see if using the same lambda (Test1) to unsubscribe would remove it from the invocation list of the event. The answer is NO it does not. I have seen code that uses this but as this test shows it does nothing. The only way to remove it from the invocation list is to hold the reference to the lamdba in a variable and use that to subscribe and unsubscribe (Test2). The code loses the beauty of using the lamdba to shorten it and I am considering to allow only the use of lamdbas that do not use members of the object.

 

class Program
{
   static void Main(string[] args)
   {
       Console.WriteLine("Test 1 : Do not hold the lambda in a variable:");
       Console.WriteLine();
       Test1();

       Console.WriteLine("Test 2 : Hold the lambda in a variable.");
       Console.WriteLine();
       Test2();
   }

   private static void Test1()
   {
       EventPublisher ep = new EventPublisher();
       ep.TestEvent += (o, e) => { };
       Console.WriteLine("Number of subscribers = {0}", ep.NumberOfSubscribers);
       ep.TestEvent -= (o, e) => { };
       Console.WriteLine("Number of subscribers = {0}", ep.NumberOfSubscribers);
       Console.ReadLine();
   }

   private static void Test2()
   {
       EventPublisher ep = new EventPublisher();

       EventHandler<EventArgs> t = (o, e) => { };

       ep.TestEvent += t;
       Console.WriteLine("Number of subscribers = {0}", ep.NumberOfSubscribers);
       ep.TestEvent -= t;
       Console.WriteLine("Number of subscribers = {0}", ep.NumberOfSubscribers);
       Console.ReadLine();
   }
}

class EventPublisher
{
   public event EventHandler<EventArgs> TestEvent;

   public int NumberOfSubscribers
   {
       get
       {
           if (this.TestEvent != null)
           {
               return this.TestEvent.GetInvocationList().Length;
           }

           return 0;
       }
   }

   public void Publish()
   {
       this.OnTestEvent(new EventArgs());
   }

   protected virtual void OnTestEvent(EventArgs e)
   {
       if (this.TestEvent != null)
       {
           this.TestEvent(this, e);
       }
   }
}

The output of this small program is the following:

Test 1 : Do not hold the lambda in a variable:

Number of subscribers = 1
Number of subscribers = 1

Test 2 : Hold the lambda in a variable.

Number of subscribers = 1
Number of subscribers = 0

As you can see beware of lambdas in Event Handlers.

Have fun,

Thursday, April 22, 2010

Techdays 2010 – Just bought some new toys

Techdays is almost over, as always there are way too many products on the table and it is time to choose what to buy and take home. This year I would like to highlight a couple of stars. One was here before but has grown from a promising idea to a great tool, PEX:

Pex and Mole

The other nominee I would describe it with the idea of chaos theory where the butterfly’s wings might be the igniter for a tornado! The tools is Rx Extensions. The idea is basically if you have iterators that you can use to pull data out of collections why can’t you have iterators that throw data at you! Instead of having to continuously checking for data availability you get notified. What this bring is a shift from programs that way of users to interact with them to programs that react to changes and do things. Programs will always be interactive in some way but this can be a starting point to create new compelling experiences.

Rx Extensions

And the next one is The toy for architects. If you want to amaze with the latest craziest stunt then you should go event driven and start processing tens of millions of events using StreamInsight. Get your backbones fibered and your cores lubed :)

Stream Insight 

And last but not least a toy to use when you are tired after eight hours of coding really scientific applications that do something as challenging as inserting data into a database and  you want to do stupid coding such as autonomous robots this is what you need. .NET Micro Framework.

.NET Micro Framework

Just heard about this really nice (cheap) platform: TinyClr

Have fun,

Wednesday, April 21, 2010

Monday, April 19, 2010

I will be on Techdays 2010 presenting the product I’ve been working on

My session is about software industrialization. I’ve working on a Domain Driven Development framework on Primavera and this is the first public presentation we are doing about it. The last months have been hard but are starting to payoff. You can find better details here:

The age of software industrialization – Combining Domain Driven Design with Code Generation

The description is only available in Portuguese but most of the contents are in United States English.

Our platform will support the product lines of the next generation of Primavera ERPs. We have achieved a high level of automation by using Microsoft DSL tools and T4 templates to generate a very large portion of the software. Our objective is to reach 100% of generated code! This is very very hard but we are highly motivated to pursuit it.

Tuesday, April 13, 2010

Silverlight Serialization – Avoiding having public setters in Properties

In Silverlight you cannot use Reflection to call a non-public setter on a class unless you are in the scope of the class. This has a side-effect in serialization because it requires having public setters for all properties that must be serialized. Well that is not really the case. You can make them internal and use the InternalsVisibleTo attribute to expose those internals to the Microsoft serialization assemblies like this:

   1: [assembly: InternalsVisibleTo("System.Runtime.Serialization, PublicKey="
   2:     + "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
   3:     + "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
   4:     + "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
   5:     + "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
   6:     + "37AB", AllInternalsVisible = true)]
   7:  
   8: [assembly: InternalsVisibleTo("System.ServiceModel.Web, PublicKey="
   9:     + "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
  10:     + "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
  11:     + "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
  12:     + "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
  13:     + "37AB", AllInternalsVisible = true)]
  14:  
  15: [assembly: InternalsVisibleTo("System.Runtime.Serialization.Json, PublicKey="
  16:     + "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
  17:     + "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
  18:     + "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
  19:     + "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
  20:     + "37AB", AllInternalsVisible = true)]

Once this is done you can make your setters internal and prevent outside code from calling them.

Have fun,

Tuesday, February 9, 2010

WCF RIA Services – Short Notes – Refreshing data from the server

By default if an Entity arriving from the server has the same Identity has one already in the DomainContexts at the client it is discarded. This behavior can be changed by calling the Load method of the DomainContext giving a MergeOption. It can be:

  1. MergeOption.OverwriteCurrentValues – What is comming from the server overrides the changes on the client.
  2. MergeOption.KeepCurrentValues – What is on the client remains the same what comes from the server is discarded.
  3. MergeOption.KeepChanges – Changes that where made on the client are maintained and everything else is replaced from what is on the server.

Have fun,

WCF RIA Services – Short Notes – Transactions

You can easily integrate transactions in a DomainService by overloading the Submit method on the service and creating the transaction scope there:

   1: using (var tx = new TransactionScope( TransactionScopeOption.Required, 
   2:     new TransactionOptions { IsolationLevel = IsolationLevel.ReadCommitted })) 
   3: { 
   4:     base.Submit(changeSet); 
   5:     tx.Complete(); 
   6: }

The Insert*, Update* and Delete* methods will be called one by one inside the given scope.

Have fun,

WCF RIA Services – Short Notes – Custom logic on solving concurrency errors

DomainServices have solving concurrency errors as a first class scenario. If you want to override the framework default logic you should.

Have an update operation for the entity.

Have a method that handles the concurrency and that:

  1. Begins with the word Resolve plus the name of the entity.
  2. Follows the signature template:
   1: public bool ResolveEntityA(EntityA current, EntityA original, EntityA store, bool deleteOperation)

Have fun,

WCF RIA Services – Short Notes – Server Side sequence of operations

When the domain service is processing a changeset the sequence of operation is:

Submit – This is the entry point for a submit operation.
AuthorizeChangeSet – In this point the entries in the changeset should be checked against the authorization rules.
ValidateChangeSet – The entries in the changeset should be checked against business rules.
ExecuteChangeSet – The business methods in the domain service are called from this method one by one.
PersistChangeSet – The changeset is persisted.
ResolveChangeSet – If there are any concurrency conflicts they are resolved here.

Kind Regards,

Pedro

WCF RIA Services – Advanced Topics – Fully supporting inheritance

One of the limitations on WCF RIA Services is not support inheritance though making EF inheritance feature impossible to use with LinqToEntities. When you try to set a property of a base class you get this error:

Entity type 'Square' does not contain a public property named 'ShapeId'.

I found that this error is actually a problem with Silverlight reflection. Because of the new restrictions on reflection the change tracking code is unable to get the value of the property. But there is a workaround for it. Let’s illustrate the problem. I have this object model:

Overview

There are several things you have to do to make this model work. First you need to put the correct annotations on your model.

   1: public class RootEntity
   2: {
   3:     [Key]
   4:     public Guid Id
   5:     {
   6:         get;
   7:         set;
   8:     }
   9:  
  10:     public Guid ChildId
  11:     {
  12:         get;
  13:         set;
  14:     }
  15:  
  16:     public string Name
  17:     {
  18:         get;
  19:         set;
  20:     }
  21:  
  22:     [Composition]
  23:     [Association("RootEntity_ChildEntity", "ChildId", "Id")]
  24:     public ChildEntity Child
  25:     {
  26:         get;
  27:         set;
  28:     }       
  29: }
  30:  
  31: public class ChildEntity
  32: {
  33:     public ChildEntity()
  34:     {
  35:         this.SubChildren = new List<SubChildEntity>();
  36:     }
  37:  
  38:     [Key]
  39:     public Guid Id
  40:     {
  41:         get;
  42:         set;
  43:     }       
  44:  
  45:     [Composition]
  46:     [Association("ChildEntity_SubChildEntity", "Id", "ChildEntityId")]
  47:     public IList<SubChildEntity> SubChildren
  48:     {
  49:         get;
  50:         private set;
  51:     }
  52: }
  53:  
  54: public class SubChildEntity
  55: {
  56:     public SubChildEntity()
  57:     {            
  58:     }
  59:  
  60:     [Key]
  61:     public Guid Id
  62:     {
  63:         get;
  64:         set;
  65:     }
  66:  
  67:     public Guid ChildEntityId
  68:     {
  69:         get;
  70:         set;
  71:     }
  72:  
  73:     [Include]
  74:     [Association("SubChildEntity_Shape", "Id", "SubChildEntityId")]
  75:     public Shape Shape
  76:     {
  77:         get;
  78:         set;
  79:     }
  80: }
  81:  
  82: [KnownType(typeof(Square))]
  83: [KnownType(typeof(Circle))]
  84: public abstract class Shape
  85: {
  86:     [Key]
  87:     public Guid ShapeId
  88:     {
  89:         get;
  90:         set;
  91:     }
  92:  
  93:     public Guid SubChildEntityId
  94:     {
  95:         get;
  96:         set;
  97:     }
  98:  
  99:     public int CenterX
 100:     {
 101:         get;
 102:         set;
 103:     }
 104:  
 105:     public int CenterY
 106:     {
 107:         get;
 108:         set;
 109:     }
 110: }
 111:  
 112: public class Circle : Shape
 113: {
 114:     public int Radius
 115:     {
 116:         get;
 117:         set;
 118:     }
 119: }
 120:  
 121: public class Square : Shape
 122: {
 123:     public int RoudingRadius
 124:     {
 125:         get;
 126:         set;
 127:     }
 128:  
 129:     public bool RoundCorners
 130:     {
 131:         get;
 132:         set;
 133:     }
 134: }

You have to notice the Composition attribute and the KnownType attribute.

Second you have to put methods to the CUD the detail objects on the server. This will force the EntitySets on the DomainContext to allow all kinds of changes. Also notice the fixup I have to do on the Ids that are involved in the associations in the InsertRootEntityMethod.

   1: [EnableClientAccess]
   2: public class RootEntityService : DomainService
   3: {
   4:     private static List<RootEntity> dataSource = new List<RootEntity>();
   5:  
   6:     public IQueryable<RootEntity> GetRootEntities()
   7:     {
   8:         var q = from r in dataSource
   9:                 //from src in r.Child.SubChildren
  10:                 select r;
  11:  
  12:         return q.AsQueryable();
  13:     }
  14:  
  15:     public IQueryable<ChildEntity> GetChildEntities(Guid parentId)
  16:     {
  17:         var q = from r in dataSource
  18:                 where r.Id == parentId
  19:                 select r.Child;
  20:  
  21:         return q.AsQueryable();
  22:     }
  23:  
  24:     public IQueryable<SubChildEntity> GetSubChildren(Guid parentId)
  25:     {
  26:         var q = from r in dataSource
  27:                 from s in r.Child.SubChildren
  28:                 where r.Id == parentId
  29:                 select s;
  30:  
  31:         return q.AsQueryable();
  32:     }
  33:  
  34:     public IQueryable<Shape> GetShapes(Guid parentId)
  35:     {
  36:         var q = from r in dataSource
  37:                 from sc in r.Child.SubChildren                    
  38:                 where r.Id == parentId
  39:                 select sc.Shape;
  40:  
  41:         return q.AsQueryable();
  42:     }
  43:  
  44:     public void InsertRootEntity(RootEntity value)
  45:     {
  46:         if (dataSource.Find(entity => entity.Id == value.Id) != null)
  47:         {
  48:             throw new InvalidOperationException("Cannot add two entities with the same key");
  49:         }
  50:  
  51:         dataSource.Add(value);
  52:         value.ChildId = value.Child.Id;
  53:         foreach (var sub in value.Child.SubChildren)
  54:         {
  55:             sub.ChildEntityId = value.Child.Id;
  56:             sub.Shape.SubChildEntityId = sub.Id;
  57:         }            
  58:     }
  59:  
  60:     public void UpdateRootEntity(RootEntity value)
  61:     {
  62:         var desiredEntity = dataSource.Find(entity => entity.Id == value.Id);
  63:         if (desiredEntity == null)
  64:         {
  65:             throw new InvalidOperationException("The given entity is not part of the data source");
  66:         }
  67:  
  68:         dataSource.Remove(desiredEntity);
  69:         dataSource.Add(value);
  70:  
  71:         value.ChildId = value.Child.Id;
  72:     }
  73:  
  74:     public void DeleteEntity(RootEntity value)
  75:     {
  76:         var desiredEntity = dataSource.Find(entity => entity.Id == value.Id);
  77:         if (desiredEntity == null)
  78:         {
  79:             throw new InvalidOperationException("The given entity is not part of the data source");
  80:         }
  81:  
  82:         dataSource.Remove(desiredEntity);
  83:     }
  84:  
  85:     public void InsertChildEntity(ChildEntity value)
  86:     {
  87:     }
  88:  
  89:     public void UpdateChildEntity(ChildEntity value)
  90:     {
  91:     }
  92:  
  93:     public void DeleteChildEntity(ChildEntity value)
  94:     {
  95:     }
  96:  
  97:     public void InsertSubChildEntity(SubChildEntity value)
  98:     {
  99:     }
 100:  
 101:     public void DeleteSubChildEntity(SubChildEntity value)
 102:     {
 103:     }
 104:  
 105:     public void UpdateSubChildEntity(SubChildEntity value)
 106:     {
 107:     }
 108:  
 109:     public void InsertCircle(Circle circle)
 110:     {
 111:     }
 112:  
 113:     public void UpdateCircle(Circle circle)
 114:     {
 115:     }
 116:  
 117:     public void DeleteCircle(Circle circle)
 118:     {
 119:     }
 120:  
 121:     public void InsertShape(Shape Shape)
 122:     {
 123:     }
 124:  
 125:     public void UpdateShape(Shape Shape)
 126:     {
 127:     }
 128:  
 129:     public void DeleteShape(Shape Shape)
 130:     {
 131:     }
 132:  
 133:     public override System.Collections.IEnumerable Query(QueryDescription queryDescription, out IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> validationErrors, out int totalCount)
 134:     {
 135:         return base.Query(queryDescription, out validationErrors, out totalCount);
 136:     }
 137:  
 138:     public override bool Submit(ChangeSet changeSet)
 139:     {
 140:         return base.Submit(changeSet);
 141:     }
 142:  
 143:     public override void Initialize(DomainServiceContext context)
 144:     {
 145:         base.Initialize(context);
 146:     }
 147:  
 148:     public override object Invoke(DomainOperationEntry operation, object[] parameters, out IEnumerable<System.ComponentModel.DataAnnotations.ValidationResult> validationErrors)
 149:     {
 150:         return base.Invoke(operation, parameters, out validationErrors);
 151:     }
 152:     
 153:     protected override bool AuthorizeChangeSet(ChangeSet changeSet)
 154:     {
 155:         return base.AuthorizeChangeSet(changeSet);
 156:     }
 157:     
 158:     protected override bool ExecuteChangeSet(ChangeSet changeSet)
 159:     {
 160:         return base.ExecuteChangeSet(changeSet);
 161:     }
 162:  
 163:     protected override bool ValidateChangeSet(ChangeSet changeSet)
 164:     {
 165:         return base.ValidateChangeSet(changeSet);
 166:     }
 167:  
 168:     protected override bool PersistChangeSet(ChangeSet changeSet)
 169:     {
 170:         return base.PersistChangeSet(changeSet);
 171:     }
 172:  
 173:     protected override bool ResolveChangeSet(ChangeSet changeSet)
 174:     {
 175:         return base.ResolveChangeSet(changeSet);
 176:     }
 177:  
 178:     protected override bool Resolve(object current, object original, object store, ResolveOption resolveOption)
 179:     {
 180:         return base.Resolve(current, original, store, resolveOption);
 181:     }
 182:  
 183:     protected override int Count<T>(IQueryable<T> query)
 184:     {
 185:         return base.Count<T>(query);
 186:     }
 187:  
 188:     protected override void OnError(DomainServiceErrorInfo errorInfo)
 189:     {
 190:         base.OnError(errorInfo);
 191:     }        
 192: }

Finally and very important you need to apply this workaround on the client side:

   1: public partial class Square
   2: {
   3:     public new Guid ShapeId
   4:     {
   5:         get
   6:         {
   7:             return base.ShapeId;
   8:         }
   9:  
  10:         set
  11:         {
  12:             base.ShapeId = value;
  13:         }
  14:     }
  15:  
  16:     public new int CenterX
  17:     {
  18:         get
  19:         {
  20:             return base.CenterX;
  21:         }
  22:  
  23:         set
  24:         {
  25:             base.CenterX = value;
  26:         }
  27:     }
  28:  
  29:     public new int CenterY
  30:     {
  31:         get
  32:         {
  33:             return base.CenterY;
  34:         }
  35:  
  36:         set
  37:         {
  38:             base.CenterY = value;
  39:         }
  40:     }
  41: }

And you will be able to run this code on client side:

   1: RootEntity rootEntity = new RootEntity();
   2: rootEntity.Id = Guid.NewGuid();
   3: rootEntity.Name = "A";
   4:  
   5: ChildEntity child = new ChildEntity();
   6: child.Id = Guid.NewGuid();
   7: rootEntity.Child = child;
   8:  
   9: SubChildEntity subChild = new SubChildEntity() { Id = Guid.NewGuid() };
  10: child.SubChildren.Add(subChild);                
  11:  
  12: Square square = new Square { ShapeId = Guid.NewGuid(), CenterX = 10, CenterY = 10 };
  13: subChild.Shape = square;
  14:  
  15: this.domainContext.RootEntities.Add(rootEntity);
  16:  
  17: var submitOperation = this.domainContext.SubmitChanges();
  18: submitOperation.Completed += (o, ee) =>
  19:     {
  20:         var op = (SubmitOperation)o;
  21:         if (op.HasError)
  22:         {
  23:             this.errors.Add(op.Error);
  24:         }
  25:     };

I was able to do the update using this code:

   1: bool flag2 = false;
   2: bool flag3 = false;
   3: bool flag4 = false;
   4:  
   5: private void btRunTest2_Click(object sender, RoutedEventArgs e)
   6: {
   7:     try
   8:     {
   9:         var op = this.domainContext.Load(this.domainContext.GetRootEntitiesQuery());                
  10:  
  11:         op.Completed += (o, ee) =>
  12:             {                                                
  13:                 var entity = this.domainContext.RootEntities.First();
  14:                 var op2 = this.domainContext.Load(this.domainContext.GetChildEntitiesQuery(entity.Id));
  15:                 op2.Completed += (oo, eee) =>
  16:                     {
  17:                         flag2 = true;
  18:                         OnEditEntity();
  19:                     };
  20:  
  21:                 var op3 = this.domainContext.Load(this.domainContext.GetSubChildrenQuery(entity.Id));
  22:                 op3.Completed += (oo, eee) =>
  23:                     {
  24:                         flag3 = true;
  25:                         OnEditEntity();
  26:                     };
  27:  
  28:                 var op4 = this.domainContext.Load(this.domainContext.GetShapesQuery(entity.Id));
  29:                 op4.Completed += (oo, eee) =>
  30:                     {
  31:                         flag4 = true;
  32:                         OnEditEntity();
  33:                     };                       
  34:             };
  35:     }
  36:     catch (Exception ex)
  37:     {
  38:         this.errors.Add(ex);
  39:     }
  40: }
  41:  
  42: private void OnEditEntity()
  43: {
  44:     if (flag2 && flag3 && flag4)
  45:     {
  46:         var entity = this.domainContext.RootEntities.First();
  47:         entity.Name = "B";
  48:         this.domainContext.SubmitChanges();
  49:     }
  50: }

Notice that ALL related entitysets must have the entities loaded for the associations to be correctly initialized.

Have fun,