Sony Arouje

a programmer's log

Posts Tagged ‘.NET

DDPClient.NET–.NET client for Meteor’s Distributed Data Protocol

with 3 comments

Last couple of hours I was working on a small .NET client library to connect to Meteor js application using Distributed Data Protocol (DDP). This post will give some insight to the library I am working on. You can see more details of DDP here.

Using DDPClient.NET you can subscribe to published items or call a Meteor method and display the same in your ASP.NET or Desktop applications.

First let’s go through the server code in my meteor application.

if(Meteor.is_server)
{
    Meteor.publish("allproducts", function(){
        return Products.find();
    });
    Meteor.startup(function(){
        console.log("starting Point of sale application.....");
      });

    Meteor.methods({
        addProduct: function (prodCode, prodDesc) {
            return "Product Name: " + prodDesc + " Product Code: " + prodCode;
        }
    });
}

 

From the Meteor application we are publishing an item called ‘allproducts’ and have a server method called ‘addProduct’ that takes two parameters. Now let’s see how to subscribe to published item and call the server method using DDPClient.NET.

Subscribe to Published items

 

class Program
{
    static void Main(string[] args)
    {
        IDataSubscriber subscriber = new Subscriber();
        DDPClient client = new DDPClient(subscriber);

        client.Connect("localhost:3000");
        client.Subscribe("allproducts");
    }

}
public class Subscriber:IDataSubscriber
{
    public void DataReceived(dynamic data)
    {
        try
        {
            if (data.type == "sub")
            {
                Console.WriteLine(data.prodCode + ": " + data.prodName + 
                                         ": collection: " + data.collection);
            }
        }
        catch(Exception ex)
        {
            throw;
        }
    }
}

 

As you can see it’s very easy to connect to Meteor application using DDPClient.NET. Just call the Connection function with the url. Then call the subscribe function to subscribe to any published item in Meteor application.

In the above code I subscribed to ‘allproducts’ item. After you subscribed successfully to the meteor application, we will receive all the products stored in the db. Once our client is subscribed any insert/delete/update will streamed to the .NET client. You can test it by adding a some products via the web application and you can see the newly added product get displayed in the console.

 

How to call a Meteor Method?

class Program
{
    static void Main(string[] args)
    {
        IDataSubscriber subscriber = new Subscriber();
        DDPClient client = new DDPClient(subscriber);

        client.Connect("localhost:3000");
        client.Call("addProduct", "NS5", "IRobot");
        Console.ReadLine();
    }
}
public class Subscriber:IDataSubscriber
{
    public void DataReceived(dynamic data)
    {
        try
        {
            if (data.type == "method")
                Console.WriteLine(data.result);
        }
        catch(Exception ex)
        {
            throw;
        }
    }
}

As you can see the Meteor method ‘addProduct’ take two arguments prodCode and prodDesc. So when we call the method we have to pass the parameter as well. We can do that by invoking the ‘Call’ function with the method name and arguments as shown below.

client.Call(“addProduct”, “NS5”, “IRobot”);

 

Also you will get notification if any data get deleted from the database. You can check the same as shown below.

else if (data.type == "unset")
{
    Console.WriteLine("deleleted item with id: " + data.id); 
}

so you will get the id of the data it deleted, you can search for the product with this id and remove or do what ever you wanted to do.

 

DDPClient.NET is checked into Github. The meteor code I referred here is added to the one I used in  Getting Started with meteor.

Written by Sony Arouje

September 22, 2012 at 6:17 pm

Transparent Persistence with db4o

with 2 comments

I was working on a small Invoicing application for my brother and I uses db4o for data persistence. Again I used db4o here because of it’s simplicity and ease of doing future updates.

I started with POCO entities and db4o handles the insertions and deletion quiet well. I started experiencing trouble when I try to update object graphs. For e.g. I created a SaleOrder with two Items then I retrieve the order and added one more item and save the changes. db4o will never save the newly added Item, it always shows the items that added initially. Because db4o couldn’t make out the changes in the object graph. There are two ways to let db4o handle this scenario.

UpdateDepth

There is a problem with UpdateDepth, we have to define a depth say 5, 10, etc and db4o will traverse the graph to identify the changes, that means we should forecast our object graph depth. This also introduce performance issues. So I decided not to use it.

Transparent Persistence

With Transparent Persistence (TP) the object will tell which all the fields got modified and db4o will update the changed fields efficiently.

To enable Transparent Persistence we have to do some changes in

  • repository level
  • entity level.
  •  

    Let’s start with repository, I used the same kind of repository I created for iTraveller with some changes in creating the db4o context/container. The change is as shown below.

    public IObjectContainer Context
    {
        get
        {
            if (_context == null)
                this.CreateContext();
            return _context;
        }
    }
    
    public void CreateContext()
    {
        if (_context == null)
        {
            IEmbeddedConfiguration config = Db4oEmbedded.NewConfiguration();
            config.Common.Add(new TransparentActivationSupport());
            config.Common.Add(new TransparentPersistenceSupport());
            _context = Db4oEmbedded.OpenFile(config, DBNAME);
        }
    }
    

     

    It’s the time to do some modification in Entity level.

    using System;
    usingDb4objects.Db4o.Activation;
    usingDb4objects.Db4o.Collections;

    usingDb4objects.Db4o.TA;
    namespaceNet.Sales.Manager.Domain
    {
        public classSaleOrderHeader : IActivatable
      
    {
            [System.NonSerialized]
            privateIActivator _activator;

            publicSaleOrderHeader ()
            {
               
                this.OrderDate = DateTime.Now;
                this.SaleOrderItems = newArrayList4<SaleOrderItem>();
            }

            public int OrderId { get; set; }

            private IList<SaleOrderItem> _salesOrderItems;
            public IList<SaleOrderItem> SaleOrderItems 
            {
                get 
                {
                    this.Read();
                    return this._salesOrderItems;
                }
                private set
                {
                    this._salesOrderItems = value;
                    this.Write();
                }
            }
    
            private double _discount;
            public double Discount
            {
                get
                {
                    this.Read();
                    return _discount;
                }
                set
                {
                    this.Write();
                    this._discount = value;
                }
            }
            public void With(SaleOrderItem saleOrderItem)
            {
                if(this.SaleOrderItems==null)
                    this.SaleOrderItems = new ArrayList4<SaleOrderItem>();
                this.Read();
                this.SaleOrderItems.Add(saleOrderItem);
            }
    
    
            public void Activate(ActivationPurpose purpose)
            {
                if (this._activator != null)
                    _activator.Activate(purpose);
                
            }
    
            public void Bind(IActivator activator)
            {
                if (_activator == activator)
                    return;
                
                if (activator != null && null != _activator)
                    throw new System.InvalidOperationException();
                
                _activator = activator;
            }
    
            public void Read()
            {
                this.Activate(ActivationPurpose.Read);
            }
    
            public void Write()
            {
                this.Activate(ActivationPurpose.Write);
            }
    
        }
    }
    
    

    For simplicity I removed some functions and properties from the above class. As you can see the SalesOrderHeader is implemented IActivatable. All classes that implements IActivatable is a candidate for Transparent Activation and Transparent Persistence. IActivatable will add two methods Activate and Bind. Make sure you implement the functions as shown above. I also added two helper methods Read and Write to ease the use of Activate function. Have a look at the property Discount and see how we are using it.

    private double _discount;
    public double Discount
    {
        get
        {
            this.Read();
            return _discount;
        }
        set
        {
            this.Write();
            this._discount = value;
        }
    }
    

     

    It is as simple as that.

    If we a have collection and that needs TA and TP enabled then we have to use ArrayList4. It’s inherited from IList. In the above e.g. SaleOrderItem is a collection, see how we implemented it.

    private IList<SaleOrderItem> _salesOrderItems;
    public IList<SaleOrderItem> SaleOrderItems 
    {
        get 
        {
            this.Read();
            return this._salesOrderItems;
        }
        private set
        {
            this._salesOrderItems = value;
            this.Write();
        }
    }
    

     

    Now we have to implement IActivatable in SaleOrderItem entity as well, the approach is same as mentioned above so skipping the code.

    We are done, now db4o can handle Transparent Activation and Transparent Persistence and no need to provide any graph depth. Even if we provide Update or Activate depth db4o will ignore it.

    Note

    We don’t need to implement IActivatable in top level class if it’s not dealing with a collection. Say for e.g. we have Customer and Address class and Customer has an instance of Address. Then implement IActivatable in Address no need to implement it in Customer as by default db4o will update top level object.

    Query TA/TP enabled objects

    You can see that in my Generic Repository I query data using Lambda expression, and the query is created as shown below.

    public IList<TEntity> Find<TEntity>(Func<TEntity, bool> criteria) where TEntity : class
    {
        return this.Query<TEntity>().Where<TEntity>(criteria).ToList<TEntity>();
    }
    
    
    private IList<TEntity> Query<TEntity>() where TEntity : class
    {
        return  this.Context.Query<TEntity>();
    }
    

     

    _repository.Find<SaleOrderHeader>(soh => soh.OrderId == salesOrderNumber);
    

     

    This Query model is not working if we enable TA and TP. First or Find of SaleOrder always return null. I think I need to check with db4o devs.

    The alternative is use Query by Example (QBE) as shown below.

    public IList<TEntity> Find<TEntity>(TEntity criteria) where TEntity : class
    {
        return this.Context.QueryByExample(criteria).Cast<TEntity>().ToList<TEntity>();
    }
    
    public SaleOrderHeader getSalesOrder(int salesOrderNumber)
    {
        return _repository.First<SaleOrderHeader>(new SaleOrderHeader(salesOrderNumber));
    }
    

    You can find more details from db4o online help.

    I will be releasing the entire source to Github soon.

    Written by Sony Arouje

    August 8, 2012 at 12:44 pm

    Posted in .NET

    Tagged with , ,

    POCO Support in Entity Framework 4

    with 2 comments

    In this post I am going to explain a small experiment I did with Entity Framework CTP4. My intention was to create some Entity classes and use it with the code first approach provided with EF4.

    Till now I haven’t touched EF because I am not a big fan of auto generated code and config files generated by EF. When I saw some article about the new features of EF that comes with v4 release, especially the code first approach and POCO support. I thought of wetting my hands in EF 4. POCO support in EF 4 was really good, no auto generated codes, no edmx files, you can write pretty clean codes.

    Let’s jump into the code. My project is not structured just very plain. Entities, Context and UI,.. every thing in single project. As I said this is just a tracer to see how things works.

    Table Structure

    CREATE TABLE [dbo].[User](
       
    [ID] [int] IDENTITY(1,1) NOT NULL,
       
    [UserCode] [varchar](10) NOT NULL,
       
    [UserName] [varchar](50) NOT NULL,
       
    [Password] [varchar](50) NOT NULL,
       
    [UserEmail] [varchar](50) NULL,
    CONSTRAINT [PK_Users] PRIMARY KEY CLUSTERED
    (
       
    [ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY]

    GO

    CREATE TABLE[dbo].[ImageComment](
      
    [CommentId] [int] IDENTITY(1,1) NOT NULL,
      
    [CommentDescription] [varchar](max) NULL,
      
    [UserName] [varchar](50) NULL,
      
    [UserId] [int] NOT NULL,
      
    [CommentDate] [datetime] NOT NULL,
    CONSTRAINT[PK_ImageComments] PRIMARY KEY CLUSTERED
    (
      
    [CommentId] ASC
    )WITH(PAD_INDEX =OFF,STATISTICS_NORECOMPUTE =OFF,IGNORE_DUP_KEY=OFF,ALLOW_ROW_LOCKS =ON,ALLOW_PAGE_LOCKS =ON)ON[PRIMARY]
    )ON[PRIMARY]

    GO

    SET ANSI_PADDING OFF
    GO

    ALTER TABLE[dbo].[ImageComments]  WITH CHECK ADD  CONSTRAINT[FK_ImageComments_Users] FOREIGN KEY([UserId])
    REFERENCES[dbo].[Users] ([ID])
    GO

    User.UserId is a foreign key in ImageComment.

    Entity Classes

    public class User
    {
        public User()
        {
            this.Comments = new List<UserComment>();
        }
    
        [Key,StoreGenerated(StoreGeneratedPattern.Identity)]
        public int UserID { get; set; }
        public string UserCode { get; set; }
        public string UserName { get; set; }
        public string Password { get; set; }
        public string UserEmail { get; set; }
        public ICollection<UserComment> Comments { get; set; }
    }
    
    public class UserComment
    {
        public UserComment() { }
        [Key, StoreGenerated(StoreGeneratedPattern.Identity)]
        public int CommentId { get; set; }
        public string Comment { get; set; }
        public virtual int UserId { get; set; }
        public virtual User User1 { get; set; }
        public DateTime CommentDate { get; set; }
    }
    

     

    Nothing much to explain just plain Entity classes. To add Key Attribute (just above the identity column) I added the System.ComponentModel.DataAnnotations;name space to the above classes. You might think that why I added Key Attribute to the indentity, the reason is EF4 POCO supports on Conventions. In some scenarios it may not identify the key property and will throw error “Unable to infer a key for entity type”. We need to attach [Key] to mark the identity key for EF.

    Let’s see the Configuration classes.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data.Objects;
    using Microsoft.Data.Entity.Ctp;
    using System.Data.Entity.ModelConfiguration;
    namespace EntityFrameWorkTracer_CodeFirstModel
    {
        public class UserConfigurationen:EntityConfiguration<User>
        {
            public UserConfigurationen()
            {
                Property(c => c.UserID).IsIdentity();
                Property(c => c.UserName).HasMaxLength(50).IsRequired();
                Property(c => c.UserCode).HasMaxLength(10).IsRequired();
                Property(c => c.Password).HasMaxLength(50).IsRequired();
                Property(c => c.UserEmail).HasMaxLength(50);
                this.HasMany(c => c.Comments);
                this.MapHierarchy(c => new
                {
                    UserName = c.UserName,
                    UserCode = c.UserCode,
                    Password = c.Password,
                    UserEmail = c.UserEmail,
                    ID = c.UserID
                }).ToTable("Users");
            }
        }
    
        public class CommentConfiguration : EntityConfiguration<UserComment>
        {
            public CommentConfiguration()
            {
                Property(c => c.CommentId).IsIdentity();
                Property(c => c.Comment).HasMaxLength(5000);
                this.HasRequired(c => c.User1).WithMany(a => a.Comments).WillCascadeOnDelete().HasConstraint((c, y) => c.UserId == y.UserID);
                this.MapHierarchy(c => new
                {
                    CommentId=c.CommentId,
                    CommentDescription = c.Comment,
                    UserId = c.UserId,
                }).ToTable("ImageComments");
            }
        }
    }
    
     
     

    The configuration class is the important piece of code here. This configuration class maps the Entity to the respective tables. We can also specify the meta property of the column like Required property, size of the field, etc.

    You can see one important line of code in CommentConfiguration (marked in bold italics). It specifies the relation between UserComment and User table.

    Object Context class

    The derived object context class is used of Saving and Retrieving data from the db.

    using System;
    usingSystem.Collections.Generic;
    usingSystem.Linq;
    usingSystem.Text;
    usingSystem.Data.Objects;
    usingSystem.Data.EntityClient;
    namespaceEntityFrameWorkTracer_CodeFirstModel
    {
        public classAWModel:ObjectContext
      
    {
            publicAWModel(EntityConnection connection)
                : base(connection)
            {

            }
            publicIObjectSet<User> User
            {
                get{ return base.CreateObjectSet<User>(); }
            }
        }
    }

    UI Code

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Data.SqlClient;
    using System.Data.Entity.ModelConfiguration;
    namespace EntityFrameWorkTracer_CodeFirstModel
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            private void Form1_Load(object sender, EventArgs e)
            {
                try
                {
                    SqlConnection con = new SqlConnection("Data Source=SQLserver;Initial Catalog=ImagePublisher;User ID=sony;PWD=sony;MultipleActiveResultSets=True;");
    
                    var builder = new ModelBuilder();
                    builder.Configurations.Add(new UserConfigurationen());
                    builder.Configurations.Add(new CommentConfiguration());
                    var model = builder.CreateModel();
                   
                    var context = model.CreateObjectContext<AWModel>(con);
                    context.ContextOptions.LazyLoadingEnabled = false;
                    var query = from c in context.User select c;
                    foreach (var u in query)
                    {
                        context.LoadProperty(u, "Comments"); //Explicity loads Comments property in User object.
                        MessageBox.Show(u.UserName); 
                        foreach (UserComment comment in u.Comments)
                        {
                            MessageBox.Show(comment.Comment); 
                        }
                    }
                    
                    //Uncomment and see how data save will work
                    //User usr = new User
                    //{
                    //    UserName = "Kevin",
                    //    Password = "Kevin",
                    //    UserEmail = "Kevin@gmail",
                    //    UserCode = "gh"
                    //};
                    //context.User.AddObject(usr);
                    //context.SaveChanges();
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                }
            }
    
        }
    }
    
    

    I struggled a lot to figure out how to load the related objects, like Comments in the User object. My architect forwared a MSDN link and solved my puzzle. From the link I got to know about the Context.LoadProperty and implemented, viola it worked.

    CTP4 supports the above code only support of configuration, before that you have to provide the edmx file as the configuration. Download CTP4.

    Let’s see how to achieve Many to Many relation ship in POCO model

    Many to Many Relation ship

    To experiment many to many relation ship I added a new table to my db, Role and UserRoles as shown below

    image

    I modified the User entity to add the below property.

    public ICollection<Role> UserRoles { get; set; }
    

     

    This property holds all the Roles associated to the User.

    Role Entity is very straight forward as shown below

    using System;
    usingSystem.Collections.Generic;
    usingSystem.Linq;
    usingSystem.Text;
    usingSystem.ComponentModel.DataAnnotations;
    namespaceEntityFrameWorkTracer_CodeFirstModel
    {
        public classRole
      
    {
            publicRole()
            {
                this.Users = newList<User>();
            }
            [Key]
            public int RoleId { get; set; }
            public stringRoleName { get; set; }
            publicICollection<User> Users { get; set; }
        }
    }

    The important piece of code is the RoleConfiguration class. Let see the configuration class

    public classRoleConfiguration : EntityConfiguration<Role>
    {
        publicRoleConfiguration()
        {
            Property(r => r.RoleId).IsIdentity();
            this.HasMany(r => r.Users).WithMany(u => u.UserRoles).Map(“dbo.UserRoles”, (role, user) =>new
           
    {
                RoleId=role.RoleId,
                UserId=user.UserID
            });

           
            this.MapHierarchy(r => new
          
    {
                RoleId=r.RoleId,
                RoleName=r.RoleName
            }).ToTable(“Role”);
        }
    }

     

    The code I marked in bold italics is our area of interest. Here I specified relationship between Role.Users and User.Roles. Also I specified the mapping table that holds the relation, here my mapping table is UserRoles. RoleId, RoleName, UserId I marked in big font is nothing but the columns in the respective tables in the db. It is a mapping between Table columns and entities property.

    Written by Sony Arouje

    September 24, 2010 at 3:41 pm