Sony Arouje

a programmer's log

Archive for the ‘.NET’ Category

Aeroponic V3 – controlled by Arduino an overview

with 9 comments

Last couple of months I was building a new version of my Aeroponic controlling system. This time I dropped Raspberry pi and moved to Arduino. One of the reason I moved to Arduino is, it’s a micro controller and has no OS. So the system will not crash, in case of power failures. Raspberry pi is on the other hand runs Linux and frequent power failures might damage the OS. The new system has all the features of my old version, plus some additional features.

Overview

I decided to use Arduino Nano, for my development. Nano has a small foot print and can plug into a PCB. I also designed a PCB to hold all the pieces together, will see the PCB shortly.

I went through several iterations of PCB design. Initially I started with onboard relay modules, later I decided to remove on board relay modules and plug external relay modules. The reason to use external relay is, I can change the relays depends on the water pump’s ampere. Also I can easily change relays if it got fried.

Mobile Application: Just like last version I created an Android app to control the system but this time I wrote a native app, previously I used Cordova to build the app.

Communication: Mobile app and Arduino communicates via bluetooth. I used HC-06 bluetooth module. To make the system simple, I skipped WiFi module. May be in later version I can include WiFi or I can use Arduino MKR1000 which has inbuilt WiFi.

Power: The system runs in 12V DC. The board can be powered in two different ways, either connect a 12V power adapter with a standard 2.1mm barrel jack or use a DC converter and supply power via normal screw terminal.

 

Features of the Controller system

Controlling Water Pump: One of the crucial part of Hydroponic/Aeroponic system is the cycling of water in periodic intervals. A water pump is used to cycle the water. The controller should be able to switch on motor in a particular interval and keep it on for a configured time. Say run motor every 30 mins and keep it on for 3 mins. This settings can be configured from the mobile application.

Nutrient Feeder: In Aeroponic/Hydroponic the fertilizers (called as nutrients) are mixed into the water. In normal scenario we need to add it manually, the system uses two dosage pumps to add nutrients. We can add nutrients two way, either via the mobile app or by manually pressing a button. Through mobile app, we can specify how may ml of nutrients need to mixed to water.

Nutrient Mixer: Used a small wave maker to mix the nutrients while adding it.

Maintain Reservoir Water Level: One of the important thing to consider is, the water pump should not dry run, if it does then ready to buy a new one. In this version, used water level sensors to know the water level. The system used a solenoid valve, which is connected to a water source. When the water level goes down to a set level, system will activate the valve and start filling the reservoir. Once the water reaches a set level, system will switch off the valve.

PCB

I spent a lot of time in designing the board and come up with a very simple board with pluggable external relay modules. I am a beginner in PCB and electronics world. I had to spend my nights assembling the system in a bread board to see how each components behave. For me programming is easy but not playing with electronic components. At last I come up with a board design. Next big task was to find a shop to manufacture the prototype board. I was in touch with so many vendors and some never responded. I choose Protocircuits to do the PCB manufacturing.

Snapseed (55) 

Protocircuits manufactured a beautiful board for me. I etched several boards at home but this was awesome. I spend another night to solder the components to the board, see the assembled board below.

 

Snapseed (53)

 

Here Arduino and Bluetooth modules are not soldered instead plugged to a female header. External relay modules can be plugged via screw terminals.

About Protocircuits

I had a very good experience with Protocircuits. They are very professional in dealing with me and answering all my queries. I should thank Jeffrey Gladstone, Director Business development for his prompt replies and answering to all my queries. If anyone want to prototype a board, I highly recommend Protocircuits. You can reach them at info@protocircuits.in

Buying Components: I highly recommend to buy any electronic components directly from the market than from any ecom providers. I did a comparison with price in the market and some online electronic shops and the price was very less in market. Take an e.g. of a chip 24LC256, in ebay.in it cost 100rs for one, from market I bought the same for 40rs. If you are in Bangalore, take a ride to SP Road and I am sure you will get all the components you want.

Advertisements

Written by Sony Arouje

April 23, 2016 at 1:34 am

Posted in .NET

My IoT Experimental desk

leave a comment »

Snapseed (30)

Written by Sony Arouje

February 13, 2016 at 5:33 pm

Posted in .NET

Node js error handling using modules inherited from EventEmitter

leave a comment »

In node js most of the operations are asynchronous and normal try-catch will not work. In case of any error and we didn’t handle it properly, our node process will crash. In this post I will explain how to handle errors properly using EventEmitter.

In this e.g. we are going to read some data from a SQLite db, I use dblite as my node module to deal with SQLite db. For this e.g. I created a UserRepository module and inherited from EventEmitter

UserRepository.js

var dblite = require('dblite');
var util = require('util');
var EventEmitter = require('events').EventEmitter;

var UserRepository = function () {
    var self = this;

    self.getUser = function (userid, callback) {
        db.query('select * from USER where USER_ID=:id', [], { id: userId },
        function (err, rows) {
            if (err)
                publishErr(err); 

            callback(rows);
        });
    };

    var publishErr = function (err) {
        self.emit('error', err);
    };
};


util.inherits(UserRepository, EventEmitter);
module.exports = UserRepository;

 

Using util.inherits, we inherits the UserRepository module from EventEmitter. Later we export that module to use in other node modules. The publishErr() function will emit an ‘error’ event in case of any error and calling module can subscribe to that event and handle the error.

Let’s use the above module in another node module. Say an express rest api.

restApi.js

var express = require('express');
var bodyParser = require('body-parser')

var UserRepository = require('./UserRepository');
var userRepo = new UserRepository();

var app = express();
app.use(bodyParser.json());
app.listen(8080);

userRepo.on('error', function (err) {
    console.log(err);
});

app.get('/users/;id', function (req, res) {
    userRepo.getUser(req.params.id, function (record) { 
        res.send(record);
    });

});

 

Let’s go through the lines in bold.

Here we are creating the instance of UserRepository module.

var UserRepository = require('./UserRepository');
var userRepo = new UserRepository();

The calling module should subscribe for the error event, that’s what we are doing here. I am just writing the error to the console. You can do whatever you want with that err object.

userRepo.on('error', function (err) {
    console.log(err);
});

 

This way we can ensure that our errors are handled properly in an elegant way.

Node js has an uncaughtException event and use it as a last resort.

process.on('uncaughtException', function (err) {
    console.log(err);
})

Written by Sony Arouje

November 7, 2014 at 5:47 pm

Posted in .NET

Chat application using SignalR 2.1

with 8 comments

Around two years ago I published a post about SignalR. Recently some readers requested an updated post using SignalR 2.1, here is the updated one.

For this post I created a very simple chat application that hosted in IIS, developed in .NET 4.5. Below is the project structure.

  • SignalrTracer.ChatServer: An empty ASP.NET Web Application which host the SignalR hub.
  • SignalrTracer.Publisher: A class library project that has SignalR hubs. I created this project just to isolate SignalR hubs from the ChatServer.
  • SignalrTracer.ChatClient: Another empty ASP.Net Web Application act as the client.

 

SignalrTracer.Publisher

As I mentioned above, this project contains the SignalR hubs. We can add SignalR framework using Nuget package manager.

Open Package Manager Console from Tools->Nuget Pacakger Manager and choose SignalrTracer.Published as the Default Project in the console window, then enter

PM> Install-Package Microsoft.AspNet.SignalR.Core

The command will add the SignalR and dependent frameworks. It’s time to create our chat hub.

ChatHub.cs

using Microsoft.AspNet.SignalR;
namespace SignalrTracer.Publisher
{
    public class ChatHub:Hub
    {
        public void Subscribe(string chatId)
        {
            Groups.Add(Context.ConnectionId, chatId);
        }

        public void Publish(string toChatId, string message)
        {
            Clients.Group(toChatId).flush(message);
        }
    }
}

 

SignalR 2.1 relies on OWIN to host it. For that we need to create a Startup class as shown below.

using Microsoft.Owin;
using Owin;
using Microsoft.AspNet.SignalR;
[assembly: OwinStartup(typeof(SignalrTracer.Publisher.Startup))]
namespace SignalrTracer.Publisher
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=316888
            var hubConfig = new HubConfiguration();
            hubConfig.EnableDetailedErrors = true;
            hubConfig.EnableJSONP = true;
            app.MapSignalR("/chatserver", hubConfig);

            app.Run(async context =>
            {
                await context.Response.WriteAsync("Chat server started");
            });
        }
    }
}

That’s it we created our SignalR hub. Let’s host it in our ChatServer.

SignalrTracer.ChatServer

This project is a OWIN host, to do that we need to refer another Nuget package called Microsoft.Owin.Host.SystemWeb.

Open the Nuget Package Manager Console and set Default project as SignalrTracer.ChatServer, then enter

PM> Install-Package Microsoft.Owin.Host.SystemWeb

Once all the package installed, just refer SignalrTracer.Publisher project and run the project. If every thing is fine then you can see an Internet Explorer with a string Chat server started. This means SignalR hub is up and running and any clients can connect now.

 

SignalrTracer.ChatClient

I used Javascript to connect to SignalR server. Open Nuget Package Manager Console and enter

PM> Install-Package Microsoft.AspNet.SignalR.JS

It will install JQuery and JQuery extension of SignalR client. I created an index.html and added the code below.

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <script src="Scripts/jquery-1.6.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.1.2.min.js"></script>
    <script type="text/javascript">
    $(function () {
        var connection = $.hubConnection('http://localhost:35144/chatserver');
        var proxy = connection.createHubProxy('ChatHub');
        connection.start()
                .done(function () {
                    $('#messages').append('<li>Connected to chat</li>');
                })
                .fail(function () { alert("Could not Connect!"); });

        proxy.on('flush', function (msg) {
            $('#messages').append('<li>' + msg + '</li>');
        });

        $("#send").click(function () {
            proxy.invoke('Publish', $("#sendTochatId").val(), $("#message").val());
        });

        $("#connect").click(function () {
            proxy.invoke('subscribe', $("#chatId").val());
            $('#messages').append('<li>subscribed to chat</li>');
        });
    });
    </script>

    <title></title>
</head>
<body>

    <label>Chat id</label> <input type="text" id="chatId" /><input type="button" id="connect" value="Connect" /><br />
    <label>Send To</label> <input type="text" id="sendTochatId" /><br />
    <label>Message</label> <input type="text" id="message" />
    <input type="button" id="send" value="Send"/>
    <div>
        <ul id="messages"></ul>
    </div>
</body>
</html>

 

You might need to change the url of hubConnection marked in bold.

Once the connection established messages section will get appended with ‘Connected to chat’ message.

Enter a unique Id in Chat Id text and click Connect, open multiple window and connect with different chat id’s.

 

As you can see it’s a very basic and simple chat system based on SignalR.

Source Code

Happy coding…

Written by Sony Arouje

September 18, 2014 at 12:49 am

Posted in .NET

Tagged with ,

Compile SQLite for WinRT with FTS4 unicode61 support

leave a comment »

I was experimenting with the FTS3/FTS4 feature of SQlite in a WinRT app. The default tokenizer ‘simple’ wont tokenize special character like $, @, etc. The solution is to use ‘unicode61’ tokenizer. Unfortunately the SQLite installer for WinRT8.1 comes without unicode61 tokenizer. I searched a lot to get a SQlite WinRT build that supports unicode61 but I was not lucky enough to get one, so I decided to build one myself.

Tim Heuer have a great post explaining about creating a build of SQLite for WinRT, I went through that and acquired all the tools to build, including the SQLite source code. I did exactly the same way Tim explained in the video, finally I got my build. But again it has the same issue, not supporting unicode61 tokenizer. I tried several builds and all these time I build with DSQLITE_ENABLE_FTS4_UNICODE61=1 and other flags I mentioned below.

After several attempt with so many permutations and combinations, I got it working. Tim’s video is a very good reference for building SQLite for WinRT. But if you want unicode61 support then follow the below steps, it’s same as Tim’s explained with some exclusion.

  1. mkdir c:\sqlite
  2. cd sqlite
  3. fossil clone http://www.sqlite.org/cgi/src sqlite3.fossil
  4. fossil open sqlite3.fossil
  5. fossil checkout winrt, never issue this command, it will never include unicode61
  6. Added this step to enable unicode61 tokenizer. Append the below config to Makefile.msc, you can see some config already existing append the below config to it.

    OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4=1

    OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS3_PARENTHESIS=1

    OPT_FEATURE_FLAGS = $(OPT_FEATURE_FLAGS) -DSQLITE_ENABLE_FTS4_UNICODE61=1

  7. Compile the code by issuing nmake -f Makefile.msc sqlite3.dll FOR_WINRT=1

 

I could build X86 and X64 using VS2012 command prompt for X86 and X64. But when I tried to compile for ARM I was getting some errors, I was fortunate enough to find a solution in StackOverflow. Followed that solution and I got the SQLite builds for X86, X64 and ARM.

I don’t want to spend time in creating a vsix package and install it in my machine, instead I took the backup of SQLite for WinRT version 3.8.5, in my machine the installed path is C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1\ExtensionSDKs\SQLite.WinRT81. Then went into each folder and replaced the lib and sqlite dll with the respective builds I created.

Leave your comments if you have any questions.

 

Happy coding…

Written by Sony Arouje

July 17, 2014 at 6:06 pm

Posted in .NET, WinRT

Tagged with , , , , , ,

WinRT TextBlock with HyperLinks

with 5 comments

I was doing some experiments with Window 8 app development. I wanted to show the text in a TextBlock with any URL as a clickable hyperlink, so that user can click on it and navigate to that webpage. We can do this easily via xaml as shown below. I googled a lot to find a way to do the same in MVVM approach. With no solution in hand I decided to come up with a solution using Attached Properties.

<TextBlock x:Name="textValue" TextWrapping="Wrap">
     <TextBlock.Inlines>
         <Run Text="This is an example of how Hyperlink can be used in a paragraph of text.
               It might be helpful for you look to"></Run>
         <Hyperlink NavigateUri="www.bing.com">bing</Hyperlink>
         <Run Text="for more answers in the future."></Run>
      </TextBlock.Inlines>
</TextBlock>

 

I am using Caliburn Micro to bind the text, so the above approach will not suit my requirement. The solution I come up with is Custom Attached Properties. In the Attached properties I applied the above logic but via code. Have a look at the code.

using System;
using System.Text;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Documents;

namespace Test.App.AttachedProps
{
    public class HyperLinkedTextBlock
    {
        public static string GetText(TextBlock element)
        {
            if (element != null)
                return element.GetValue(ArticleContentProperty) as string;
            return string.Empty;
        }

        public static void SetText(TextBlock element, string value)
        {
            if (element != null)
                element.SetValue(ArticleContentProperty, value);
        }

        public static readonly DependencyProperty ArticleContentProperty =
            DependencyProperty.RegisterAttached(
                "Text",
                typeof(string),
                typeof(HyperLinkedTextBlock),
                new PropertyMetadata(null, OnInlineListPropertyChanged));

        private static void OnInlineListPropertyChanged(DependencyObject obj, 
             DependencyPropertyChangedEventArgs e)
        {
            var tb = obj as TextBlock;
            if (tb == null)
                return;
            string text = e.NewValue as string;
            tb.Inlines.Clear();

            if (text.ToLower().Contains("http:") || text.ToLower().Contains("www."))
                AddInlineControls(tb, SplitSpace(text));
            else
                tb.Inlines.Add(GetRunControl(text));
        }

        private static void AddInlineControls(TextBlock textBlock, string[] splittedString)
        {
            for (int i = 0; i < splittedString.Length; i++)
            {
                string tmp = splittedString[i];
                if (tmp.ToLower().StartsWith("http:") || tmp.ToLower().StartsWith("www."))
                    textBlock.Inlines.Add(GetHyperLink(tmp));
                else
                    textBlock.Inlines.Add(GetRunControl(tmp));
            }
        }

        private static Hyperlink GetHyperLink(string uri)
        {
            if (uri.ToLower().StartsWith("www."))
                uri = "http://" + uri;

            Hyperlink hyper = new Hyperlink();
            hyper.NavigateUri = new Uri(uri);
            hyper.Inlines.Add(GetRunControl(uri));
            return hyper;
        }

        private static Run GetRunControl(string text)
        {
            Run run = new Run();
            run.Text = text + " ";
            return run;
        }

        private static string[] SplitSpace(string val)
        {
            string[] splittedVal = val.Split(new string[] {" "}, StringSplitOptions.None);
            return splittedVal;
        }
    }
}

 

In the above code I analyze the text for urls after splitting it, you can also do it using RegEx. As this code is just for protyping, I didn’t pay much attention to the quality of it.

In the xaml page I refer this attached property as shown below.

xmlns:conv="using:Test.App.AttachedProps"

 

In the Textblock, bind the text via the attached property as shown below.

<TextBlock conv:HyperLinkedTextBlock.Text="{Binding TextVal}"/>

 

If the TextVal has any words that starts with ‘http:’ or ‘www.’ then the above Custom Attached Property will create a HyperLink other wise create a Run control and add it to the Inline collection of the TextBlock.

 

Happy coding…

Written by Sony Arouje

July 16, 2014 at 2:45 pm

Indexing and Searching with ElasticSearch

with 2 comments

Last couple of days I was experimenting with ElasticSearch and different client libraries for .NET. In this post I will detailed the implementation of Indexing and searching using ElasticSearch in .NET. For detailed documentation of Elasticsearch visit official site or Joel Abrahamsson post.

I use PlainElastic.Net as my Elastic search client. PlainElastic is a very simple lightweight library for  Elasticsearch. It uses plain json for indexing and query, this gives me more freedom and tooling to create json from the user inputs for indexing and query.

To make it more flexible, our system gets data from the database using views. Datareader class converts this data to Dynamic objects. Then converts it to json and pass it to PlainElastic for indexing. Dynamic object makes life more easier as we can reuse this class with different views without worrying about strong types. Below is the Dynamic class I created.

    public class ElasticEntity:DynamicObject
    {
        private Dictionary<string, object> _members = new Dictionary<string, object>();

        public static ElasticEntity CreateFrom(Dictionary<string, object> members)
        {
            ElasticEntity entity = new ElasticEntity();
            entity.SetMembers(members);
            return entity;
        }

        public string GetValue(string property)
        {
            if (_members.ContainsKey(property))
            {
                object tmp= _members[property];
                if (tmp == null)
                    return string.Empty;
                else
                    return Convert.ToString(tmp);
            }
            return string.Empty;
        }

        public Dictionary<string, object> GetDictionary()
        {
            return _members;
        }

        internal void SetMembers(Dictionary<string, object> members)
        {
            this._members = members;
        }

        public void SetPropertyAndValue(string property, object value)
        {
            if (!_members.ContainsKey(property))
                _members.Add(property, value);
            else
                _members[property] = value;
        }
  
        public override bool TrySetMember(SetMemberBinder binder, object value)
        {
            if (!_members.ContainsKey(binder.Name))
                _members.Add(binder.Name, value);
            else
                _members[binder.Name] = value;

            return true;
        }
  
        public override bool TryGetMember(GetMemberBinder binder, out object result)
        {
            if (_members.ContainsKey(binder.Name))
            {
                result = _members[binder.Name];
                return true;
            }
            else
            {
                return base.TryGetMember(binder, out result);
            }
        }
  
        public override bool TryInvokeMember(InvokeMemberBinder binder, object[] args, out object result)
        {
            if (_members.ContainsKey(binder.Name)
                      && _members[binder.Name] is Delegate)
            {
                result = (_members[binder.Name] as Delegate).DynamicInvoke(args);
                return true;
            }
            else
            {
                return base.TryInvokeMember(binder, args, out result);
            }
        }

        public override IEnumerable<string> GetDynamicMemberNames()
        {
            return _members.Keys;
        }
    }

 

Indexing

Our views will fetch the data and return as IDataReader. While indexing data, the index helper will iterate through the reader and from the reader the data get loaded to Dynamic ElasticEntity as shown below.

        private ElasticEntity GetRecordAsElasticEntity(IDataReader reader)
        {
            ElasticEntity entity = new ElasticEntity();
            for (int i = 0; i < reader.FieldCount; i++)
            {
                entity.SetPropertyAndValue(reader.GetName(i), reader.GetValue(i));
            }

            return entity;
        }

Before indexing the ElasticEntity, it will be serialized to json using the solution provided in Stackoverflow, it uses JavaScriptSerializer and is very fast. Same approach used while deserializing the json result from Elasticsearch while searching. For deserializing Elasticsearch result, I used json.net initially but deserializing is very slow compare to Javascript serializer.

Below is my Elasticsearch Indexer. It’s a very simple class that uses PlainElastic.Net.

    public class PlainElasticIndexer:Interfaces.IElasticIndexer
    {
        private ElasticConnection _connection;

        private string _indexName;
        private string _type;
        private string _defaultHost;
        private int _port;

        /// <summary>
        /// Default host to localhost and port to 9200. If the host and port is different
        /// then use the parameterized constructor and specify the details.
        /// </summary>
        private PlainElasticIndexer()
        {
            _connection = new ElasticConnection("localhost", 9200);
        }

        public PlainElasticIndexer(string host, int port, string indexName, string type)
        {
            this._defaultHost = host;
            this._port = port;
            _indexName = indexName;
            _type = type;
            _connection = new ElasticConnection(_defaultHost, _port);
        }

        /// <summary>
        /// Default host to localhost and port to 9200. If the host and port is different
        /// then use the parameterized constructor and specify the details.
        /// </summary>
        public PlainElasticIndexer(string indexName, string type):this()
        {
            _indexName = indexName;
            _type = type;
        }


        /// <summary>
        /// Add or update an index. If the ID exist then update the index with the provided json.
        /// </summary>
        /// <param name="json"></param>
        /// <param name="id"></param>
        public void Write(string json, string id)
        {
            string command = Commands.Index(_indexName, _type, id);
            string response = _connection.Put(command, json);
        }
    }

 

Search

Searching also uses a very simple class as shown below.

    public class PlainElasticSearcher:Interfaces.IElasticSearcher
    {
        ElasticConnection _connection;
        private string _indexName;
        private string _type;
        private string _defaultHost;
        private int _port;

        /// <summary>
        /// Default host to localhost and port to 9200. If the host and port is different
        /// then use the parameterized constructor and specify the details.
        /// </summary>
        private PlainElasticSearcher()
        {
            _connection = new ElasticConnection("localhost", 9200);
        }

        public PlainElasticSearcher(string host, int port, string indexName, string type)
        {
            this._defaultHost = host;
            this._port = port;
            _indexName = indexName;
            _type = type;
            _connection = new ElasticConnection(_defaultHost, _port);
        }

        /// <summary>
        /// Default host to localhost and port to 9200. If the host and port is different
        /// then use the other parameterized constructor and specify the details.
        /// </summary>
        public PlainElasticSearcher(string indexName, string type) : this()
        {
            _indexName = indexName;
            _type = type;
        }

        public string Search(string jsonQuery)
        {
            string command = new SearchCommand(_indexName, _type).WithParameter("search_type", "query_and_fetch")
                                    .WithParameter("size","100");
            string result = _connection.Post(command, jsonQuery);
            return result;
        }
    }

 

The Search function returns the result as plain json. The caller will convert the json to ElasticEntity using the function shown below.

        public static IList<ElasticEntity> ToElasticEntity(string json)
        {
            IList<ElasticEntity> results = new List<ElasticEntity>();
            JavaScriptSerializer jss = new JavaScriptSerializer();
            jss.RegisterConverters(new JavaScriptConverter[] { new DynamicJsonConverter() });

            JsonTextReader jsonReader = new JsonTextReader(new StringReader(json));

            var jObj = JObject.Parse(json); 
            foreach (var child in jObj["hits"]["hits"])
            {
                var tmp = child["_source"].ToString();
                dynamic dynamicDict = jss.Deserialize(tmp, typeof(object)) as dynamic;
                ElasticEntity elasticEntity = ElasticEntity.CreateFrom(dynamicDict);
                results.Add(elasticEntity);
            }

            return results;
        }

I added another class to convert the ElasticEntity to typed object. This helps the caller to convert the ElasticEntity to the Domain objects or to DTO.

    /// <summary>
    /// This class maps ElasticEntity to any DomainSpecific strongly typed class. Say for e.g.
    /// the requesting class wants the search result as a Customer class. This mapper will 
    /// create an instance of Customer and get the value from ElasticEntity and set 
    /// it to the Properties of Customer. One rule you should follow is
    /// the Columns in the index and Properties in the Domain class should match. 
    /// We can say it's a convention based mapping.
    /// </summary>
    public class EntityMapper
    {
        private string _pathToClientEntityAssembly;
        private Assembly _loadedAssembly = null;

        public EntityMapper(string pathToClientEntityAssembly)
        {
            _pathToClientEntityAssembly = pathToClientEntityAssembly;
        }

        internal T Map<T>(ElasticEntity entity) where T:class
        {
            T instance = this.GetInstance<T>();
            Type type = instance.GetType();
            PropertyInfo[] properties = type.GetProperties();

            foreach (PropertyInfo property in properties)
            {
                object value = entity.GetValue(property.Name);
                property.SetValue(instance, Convert.ChangeType(value, property.PropertyType), null);
            }
            return instance;
        }

        private T GetInstance<T>()
        {
            if(string.IsNullOrWhiteSpace(_pathToClientEntityAssembly))
                throw new NullReferenceException(string.Format("Unable to create {0}, path to the 
                                        assembley is not specified.", typeof(T).ToString()));

            if(_loadedAssembly==null)
                _loadedAssembly = Assembly.LoadFile(_pathToClientEntityAssembly);

            object instance = _loadedAssembly.CreateInstance(typeof(T).ToString());
            return (T)instance;
        }

    }

The client can call the search function as shown below.

var searcher = new SearchFacade(new PlainElasticSearcher(), assmPath);
IList<Customer> resultAsCustomer = searcher.Search("Customer", jsonQry).Results<Customer>();

 

where assmPath is the path to Assembly where Customer entity resides. If the user needs the result as ElasticEntity, then set the assmPath as null and make the call as shown below.

IList<ElasticEntity> searchResult = searcher.Search("Customer", jsonQry).Results();

 

Below code shows the implementation of SearchFacade.

    public class SearcherFacade
    {
        private IElasticSearcher _elasticSearcher;
        private string _pathToEntityAssembly;
        private IList<ElasticEntity> _searchResults;
        /// <summary>
        /// Use this constructor if the client will be dealing with dynamic ElasticEntity.
        /// </summary>
        /// <param name="elasticSearcher"></param>
        public SearcherFacade(IElasticSearcher elasticSearcher)
        {
            _elasticSearcher = elasticSearcher;
        }

        /// <summary>
        /// Use this constructor if the client wants to convert the ElasticEntity to domain specific class.
        /// </summary>
        /// <param name="elasticSearcher"></param>
        /// <param name="pathToEntityAssembly">path to Assembley to locate the Domain specific class</param>
        public SearcherFacade(IElasticSearcher elasticSearcher, string pathToEntityAssembly):this(elasticSearcher)
        {
            _pathToEntityAssembly = pathToEntityAssembly;
        }

        public SearcherFacade Search(string jsonQuery)
        {
            string jsonResult = _elasticSearcher.Search(jsonQuery);
            _searchResults=  DeserializeJson.ToElasticEntity(jsonResult);
            return this;
        }

        public IList<ElasticEntity> Results()
        {
            return _searchResults;
        }

        /// <summary>
        /// Converts dynamic ElasticEntity to strongly typed Domain Entity.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public IList<T> Results<T>() where T:class
        {
            if (string.IsNullOrWhiteSpace(_pathToEntityAssembly))
                throw new NullReferenceException(string.Format("Please provide the Path and Assembly 
                          name in which class {0} resides. Set the fully qualified Assembly path 
                          via the constructor that take two parameters.", typeof(T).ToString()));

            EntityMapper mapper = new EntityMapper(_pathToEntityAssembly);
            IList<T> convertedResults = new List<T>();

            foreach (ElasticEntity entity in _searchResults)
            {
                T instance = mapper.Map<T>(entity);
                convertedResults.Add(instance);
            }
            return convertedResults;
        }
    }

 

This post gives a very simplistic and basic view of our ElasticSearch layer that I created. We have more functionality tailored for our needs. Hope this post helps some one to build a system using ElasticSearch.

 

Happy Coding…

Written by Sony Arouje

February 27, 2014 at 11:35 am

%d bloggers like this: