February 2013 - Development Simply Put

A blog simplifies main concepts in IT development and provides tips, hints, advices and some re-usable code. "If you can't explain it simply, you don't understand it well enough" -Albert Einstein

  • Development Simply Put

    If you can't explain it simply, you don't understand it well enough.

    Read More
  • Integrant

    Based in the U.S. with offshore development centers in Jordan and Egypt, Integrant builds quality custom software since 1992. Our staff becomes an extension of your team to eliminate the risks of software development outsourcing and our processes...

    Read More
  • ITWorx

    ITWorx is a global software professional services organization. Headquartered in Egypt, the company offers Portals, Business Intelligence, Enterprise Application Integration and Application Development Outsourcing services to Global 2000 companies.

    Read More
  • Information Technology Institute

    ITI is a leading national institute established in 1993 by the Information and Decision Support Centre.

    Read More

2013-02-27

Items Combinations Generation Library

[Update] This library is now replaced with a new one. The new one is more advanced and enhanced. You can check it on Possibilities Cube Library - A Library Smart Enough To Calculate All Possibilities With Logical Conditions


Sometimes you have a set of items (could be numbers, names, custom entities, .....) and you need to get all possible combinations each consists of a given number of items from the bigger set.

To understand what I am saying, imagine that you need to write a program by which a user can define some birthday gifts. Each gift has an id, name, description, price, ...... Your program is expected to provide all possible combinations of gifts that a father can get to his son given that the number of gift items doesn't exceed 5 and the price doesn't exceed LE 150.

To solve the problem above, which is a mathematical problem in the first place, you can use some of the mathematical algorithms. But, only for the sake of demonstration, I will assume that we will use a brute force approach to solve the problem.

So, to do the job, at some point in your code, you will need to generate all the possibilities and combinations of gift items that the father can buy for his son. Sure not all these combinations are valid and you will need to filter them according to your business but at least it is a starting point.

So, to get all possible combinations, you can use the same logic used in the binary tables. For example, in binary, any bit can be 0 or 1 and nothing else. So, if we need to have all possible sets consisting of 2 bits, we will get
0 , 0
0 , 1
1 , 0
1 , 1

These are all possible combinations you can get in this case. But, in case of sets consisting of 3 bits instead of 2, we will get
0 , 0 , 0
0 , 0 , 1
0 , 1 , 0
0 , 1 , 1
1 , 0 , 0
1 , 0 , 1
1 , 1 , 0
1 , 1 , 1

and so on........

So, this leads us to the "Items Combinations Generation Library" that I am presenting. This library provides a class with some methods which you can use to get all possible combinations of any set of items. It returns an array of indexes of items you have. So, when you get [(0 , 0), (0 , 1), (1 , 0), (1 , 1)] these numbers refer to the indexes of the items in your collection of items.

Ok, this is the time for the code.


The Library Code

Possibilities.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevelopmentSimplyPut.CommonUtilities
{
    public class Possibilities
    {
        #region Properties
        int numberOfItems;
        public int NumberOfItems
        {
            get { return numberOfItems; }
            set 
            {
                if (value > 0)
                {
                    numberOfItems = value;
                }
                else
                {
                    throw new Exception("NumberOfItems must be +ve and greater than 0.");
                }
            }
        }
        int numberOfInstancesPerPossibility;
        public int NumberOfInstancesPerPossibility
        {
            get { return numberOfInstancesPerPossibility; }
            set
            {
                if (value > 0)
                {
                    numberOfInstancesPerPossibility = value;
                }
                else
                {
                    throw new Exception("NumberOfInstancesPerPossibility must be +ve and greater than 0.");
                }
            }
        }
        int maxRowIndex;
        int maxColumnIndex;
        #endregion Properties

        #region Constructors
        public Possibilities(int _numberOfItems, int _numberOfInstancesPerPossibility)
        {
            NumberOfItems = _numberOfItems;
            NumberOfInstancesPerPossibility = _numberOfInstancesPerPossibility;
            maxRowIndex = intPow(NumberOfItems, NumberOfInstancesPerPossibility) - 1;
            maxColumnIndex = NumberOfInstancesPerPossibility - 1;
        }
        #endregion Constructors

        #region Methods
        public int[,] GetPossibilities()
        {
            int[,] result = new int[maxRowIndex + 1, maxColumnIndex + 1];

            for (int i = 0; i <= maxRowIndex; i++)
            {
                int[] rowResults = GetPossiblityByIndex(i);
                for (int k = 0; k < rowResults.Length; k++)
                {
                    result[i, k] = rowResults[k];
                }
            }
            
            return result;
        }
        public int[] GetPossiblityByIndex(int rowIndex)
        {
            int[] result = null;

            if (rowIndex >= 0)
            {
                if (rowIndex <= maxRowIndex)
                {
                    result = new int[maxColumnIndex + 1];

                    for (int i = 0; i <= maxColumnIndex; i++)
                    {
                        result[i] = GetPossiblityByIndex(rowIndex, i);
                    }
                }
                else
                {
                    throw new Exception(string.Format("rowIndex can not be greater than {0}", maxRowIndex));
                }
            }
            else
            {
                throw new Exception("rowIndex must be +ve or equal to 0.");
            }

            return result;
        }
        public int GetPossiblityByIndex(int rowIndex, int columnIndex)
        {
            int result = 0;

            if (rowIndex >= 0 && columnIndex >= 0)
            {
                if (rowIndex > maxRowIndex)
                {
                    throw new Exception(string.Format("rowIndex can not be greater than {0}", maxRowIndex));
                }
                else if (columnIndex > maxColumnIndex)
                {
                    throw new Exception(string.Format("columnIndex can not be greater than {0}", maxColumnIndex));
                }
                else
                {
                    int numberOfHops = intPow(NumberOfItems, columnIndex);
                    result = GetPossiblityByIndex(NumberOfItems, numberOfHops, rowIndex);
                }
            }
            else
            {
                throw new Exception("rowIndex and columnIndex must be +ve or equal to 0.");
            }

            return result;
        }
        private int GetPossiblityByIndex(int numberOfItems, int numberOfHops, int rowIndex)
        {
            int result = 0;
            int maxItemIndex = numberOfItems - 1;
            result = rowIndex / numberOfHops;
            result = result % numberOfItems;
            return result;
        }
        private int intPow(int a, int b)
        {
            int result = 0;

            if (0 == b)
            {
                result = 1;
            }
            else if (1 == b)
            {
                result = a;
            }
            else
            {
                result = a;
                for (int i = 0; i < b - 1; i++)
                {
                    result *= a;
                }
            }
            
            return result;
        }
        #endregion Methods
    }
}


Testing Windows Forms Application

MainForm.Designer.cs
namespace TestApp
{
    partial class MainForm
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.btnRun = new System.Windows.Forms.Button();
            this.label1 = new System.Windows.Forms.Label();
            this.label2 = new System.Windows.Forms.Label();
            this.txtNumOfItems = new System.Windows.Forms.TextBox();
            this.txtNumOfInstances = new System.Windows.Forms.TextBox();
            this.rtxtOutput = new System.Windows.Forms.RichTextBox();
            this.SuspendLayout();
            // 
            // btnRun
            // 
            this.btnRun.Location = new System.Drawing.Point(264, 6);
            this.btnRun.Name = "btnRun";
            this.btnRun.Size = new System.Drawing.Size(47, 54);
            this.btnRun.TabIndex = 0;
            this.btnRun.Text = "Run";
            this.btnRun.UseVisualStyleBackColor = true;
            this.btnRun.Click += new System.EventHandler(this.btnRun_Click);
            // 
            // label1
            // 
            this.label1.AutoSize = true;
            this.label1.Location = new System.Drawing.Point(4, 12);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(85, 13);
            this.label1.TabIndex = 1;
            this.label1.Text = "Number of items";
            // 
            // label2
            // 
            this.label2.AutoSize = true;
            this.label2.Location = new System.Drawing.Point(4, 40);
            this.label2.Name = "label2";
            this.label2.Size = new System.Drawing.Size(105, 13);
            this.label2.TabIndex = 2;
            this.label2.Text = "Number of instances";
            // 
            // txtNumOfItems
            // 
            this.txtNumOfItems.Location = new System.Drawing.Point(116, 9);
            this.txtNumOfItems.Name = "txtNumOfItems";
            this.txtNumOfItems.Size = new System.Drawing.Size(137, 20);
            this.txtNumOfItems.TabIndex = 3;
            // 
            // txtNumOfInstances
            // 
            this.txtNumOfInstances.Location = new System.Drawing.Point(115, 40);
            this.txtNumOfInstances.Name = "txtNumOfInstances";
            this.txtNumOfInstances.Size = new System.Drawing.Size(137, 20);
            this.txtNumOfInstances.TabIndex = 4;
            // 
            // rtxtOutput
            // 
            this.rtxtOutput.Location = new System.Drawing.Point(8, 66);
            this.rtxtOutput.Name = "rtxtOutput";
            this.rtxtOutput.Size = new System.Drawing.Size(299, 217);
            this.rtxtOutput.TabIndex = 5;
            this.rtxtOutput.Text = "";
            // 
            // MainForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(315, 291);
            this.Controls.Add(this.rtxtOutput);
            this.Controls.Add(this.txtNumOfInstances);
            this.Controls.Add(this.txtNumOfItems);
            this.Controls.Add(this.label2);
            this.Controls.Add(this.label1);
            this.Controls.Add(this.btnRun);
            this.Name = "MainForm";
            this.Text = "Test Application";
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion

        private System.Windows.Forms.Button btnRun;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.Label label2;
        private System.Windows.Forms.TextBox txtNumOfItems;
        private System.Windows.Forms.TextBox txtNumOfInstances;
        private System.Windows.Forms.RichTextBox rtxtOutput;
    }
}

MainForm.cs
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.IO;
using DevelopmentSimplyPut.CommonUtilities;

namespace TestApp
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            rtxtOutput.Text = string.Empty;

            Possibilities container = new Possibilities(int.Parse(txtNumOfItems.Text), int.Parse(txtNumOfInstances.Text));
            int[,] allPossibilities = container.GetPossibilities();

            for (int i = 0; i < allPossibilities.GetLength(0); i++)
            {
                for (int k = 0; k < allPossibilities.GetLength(1); k++)
                {
                    rtxtOutput.Text += allPossibilities[i, k].ToString() + " , ";
                }

                rtxtOutput.Text += Environment.NewLine;
            }

            MessageBox.Show("Done");
        }
    }
}

Running this program you will get the results in the screenshots below

Items Combinations Generation Library

Items Combinations Generation Library

Items Combinations Generation Library


Finally, you can download the source code from here


2013-02-22

Extensible Logging Library For Sharepoint With ULS Logging Support

What I am presenting here is a library used for logging in Sharepoint 2010.

What makes this library a good choice?
  1. Its code is clean and maintainable
  2. Its code is extensible as you can easily add support to many third party logging services with just some few code lines
  3. It provides a single entry point static class for usage instead of many classes

Which logging services does this library currently support?
Currently the library supports the OOTB Unified Logging Service (ULS) but for sure you can add the support for other logging services like log4net and others with just some few lines of code.


Is the code simple or complicated?
  1. The first code part: The main library code is simple and follow the "Bridge" and "Factory" design patterns. I had already wrote a post on these two design patterns with an example of how to use them. If you didn't read this post and it is your first time to hear about these two design patterns, I really encourage you to read One Of The Methodologies To Write Clean, Maintainable & Extensible Software
  2. The second code part: The main entry point static class which enables you to use the library in an easy way. This class is so simple and clear
  3. The third code part: The implementations of the logging services you wish the library can support. The complexity of this part depends on the logging service itself. Some may be simple and others may be complex

Can we see the code?

LoggerDefinitions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DevelopmentSimplyPut.CommonUtilities.Logging
{
    public enum LoggingLevel
    {
        Debug = 0,
        Info = 1,
        Warn = 2,
        Error = 3,
        Fatal = 4
    }

    public interface ILogger
    {
        void Configure(Dictionary<string,object> settings);
        void Log(string message, LoggingLevel level);
        void Log(Exception exception, LoggingLevel level);
        void Log(Exception exception, string message, LoggingLevel level);
    }

    public abstract class Logger : ILogger
    {
        public abstract void Configure(Dictionary<string, object> settings);
        public abstract void Log(string message, LoggingLevel level);
        public abstract void Log(Exception exception, LoggingLevel level);
        public abstract void Log(Exception exception, string message, LoggingLevel level);
    }
}

LoggerFactory.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevelopmentSimplyPut.CommonUtilities.Logging.ULS;

namespace DevelopmentSimplyPut.CommonUtilities.Logging
{
    public static class LoggerFactory
    {
        public static ILogger GetLoggerInstance(SystemLoggerType loggerType, Dictionary<string, object> settings)
        {
            ILogger result = null;

            switch (loggerType)
            {
                case SystemLoggerType.ULS:
                    result = ULSLogger.Current;
                    break;
                default:
                    result = ULSLogger.Current;
                    break;
            }

            result.Configure(settings);
            return result;
        }
    }
}

SystemLogger.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DevelopmentSimplyPut.CommonUtilities.Helpers;

namespace DevelopmentSimplyPut.CommonUtilities.Logging
{
    public enum SystemLoggerType
    {
        ULS = 0
        //, Log4Net = 1
    }

    public static class SystemLogger
    {
        private static ILogger logger;
        private static void SetLogger(SystemLoggerType loggerType)
        {
            switch (loggerType)
            {
                case SystemLoggerType.ULS:
                    Dictionary<string, object> settings = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
                    settings.Add("ProductDiagName", "DevelopmentSimplyPut");
                    logger = LoggerFactory.GetLoggerInstance(SystemLoggerType.ULS, settings);
                    break;
            }
        }

        /// <summary>
        /// Gets current initialized system logger. If not already initialized, initializes a new default logger and returns it.
        /// </summary>
        public static ILogger Logger
        {
            get
            {
                if (logger == null)
                {
                    SetLogger(SystemLoggerType.ULS);
                }
                return logger;
            }
        }
        /// <summary>
        /// Resets current system logger to the default logger and finally returns this logger instance.
        /// </summary>
        /// <returns></returns>
        public static ILogger ResetLogger()
        {
            return ResetLogger(SystemLoggerType.ULS);
        }
        /// <summary>
        /// Resets current system logger to a specific logger type and finally returns this logger instance.
        /// </summary>
        /// <param name="loggerType"></param>
        /// <returns></returns>
        public static ILogger ResetLogger(SystemLoggerType loggerType)
        {
            SetLogger(loggerType);
            return logger;
        }
    }
}

ULSLogger.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;
using System.Globalization;

namespace DevelopmentSimplyPut.CommonUtilities.Logging.ULS
{
    public class ULSLogger : Logger
    {
        private string productDiagName = string.Empty;
        private ULSLogger()
        {
        }
        
        private static ULSLoggingService CurrentServices
        {
            get;
            set;
        }

        private static ULSLogger current;
        public static ULSLogger Current
        {
            get
            {
                if (current == null)
                {
                    current = new ULSLogger();
                }
                return current;
            }
        }
        
        public override void Configure(Dictionary<string, object> settings)
        {
            if (settings != null && settings.Count > 0 && settings.Any(record => record.Key.ToUpperInvariant() == "ProductDiagName".ToUpperInvariant()))
            {
                productDiagName = Convert.ToString(settings["ProductDiagName"]);
                CurrentServices = new ULSLoggingService(productDiagName);
            }
        }

        public override void Log(string message, LoggingLevel level)
        {
            Log(null, message, level);
        }
        public override void Log(Exception exception, LoggingLevel level)
        {
            Log(exception, exception.Message + Environment.NewLine + Environment.NewLine + exception.StackTrace, level);
        }
        public override void Log(Exception exception, string message, LoggingLevel level)
        {
            string msg =
                (null == exception) ? (message) :
                string.Format(CultureInfo.InvariantCulture, "{0}\n\n{1}\n\n{2}", message, exception.Message, exception.StackTrace);

            CurrentServices.Log(msg, level);
        }
    }
}

ULSLoggingService.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.SharePoint.Administration;

namespace DevelopmentSimplyPut.CommonUtilities.Logging.ULS
{
    public class ULSLoggingService : SPDiagnosticsServiceBase
    {
        public ULSLoggingService(string productName) : base(productName, SPFarm.Local)
        {
        }
        
        protected override IEnumerable<SPDiagnosticsArea> ProvideAreas()
        {
            List<SPDiagnosticsArea> areas = new List<SPDiagnosticsArea>
            {
                new SPDiagnosticsArea
                (Name, new List<SPDiagnosticsCategory>
                    {
                        new SPDiagnosticsCategory("Debug", TraceSeverity.None, EventSeverity.None),
                        new SPDiagnosticsCategory("Error", TraceSeverity.Unexpected, EventSeverity.Error),
                        new SPDiagnosticsCategory("Info", TraceSeverity.Monitorable, EventSeverity.Information),
                        new SPDiagnosticsCategory("Warn", TraceSeverity.Medium, EventSeverity.Warning),
                        new SPDiagnosticsCategory("Fatal", TraceSeverity.High, EventSeverity.ErrorCritical),
                    }
                )
            };

            return areas;
        }

        private void LogDebug(string message)
        {
            SPDiagnosticsCategory category = Areas[Name].Categories["Debug"];
            WriteTrace(0, category, category.TraceSeverity, message);
        }
        private void LogError(string message)
        {
            SPDiagnosticsCategory category = Areas[Name].Categories["Error"];
            WriteTrace(0, category, category.TraceSeverity, message);
        }
        private void LogInfo(string message)
        {
            SPDiagnosticsCategory category = Areas[Name].Categories["Info"];
            WriteTrace(0, category, category.TraceSeverity, message);
        }
        private void LogWarn(string message)
        {
            SPDiagnosticsCategory category = Areas[Name].Categories["Warn"];
            WriteTrace(0, category, category.TraceSeverity, message);
        }
        private void LogFatal(string message)
        {
            SPDiagnosticsCategory category = Areas[Name].Categories["Fatal"];
            WriteTrace(0, category, category.TraceSeverity, message);
        }
        public void Log(string message, LoggingLevel level)
        {
            switch (level)
            {
                case LoggingLevel.Debug:
                    LogDebug(message);
                    break;
                case LoggingLevel.Error:
                    LogError(message);
                    break;
                case LoggingLevel.Fatal:
                    LogFatal(message);
                    break;
                case LoggingLevel.Info:
                    LogInfo(message);
                    break;
                case LoggingLevel.Warn:
                    LogWarn(message);
                    break;
                default:
                    LogDebug(message);
                    break;
            }
        }
    }
}


How to use this library?
catch (NullReferenceException ex)
{
 SystemLogger.Logger.Log(ex, LoggingLevel.Error);
}

or

catch (NullReferenceException ex)
{
 SystemLogger.Logger.Log(ex, "This is custom error message for logging", LoggingLevel.Error);
}

or

catch (NullReferenceException ex)
{
 SystemLogger.Logger.Log("This is custom error message for logging", LoggingLevel.Warn);
}

or

SystemLogger.Logger.Log("This is just a hint message for logging", LoggingLevel.Info);

This is just a sample of what you can do using this library. You can browse through the code and you will get the whole thing. For sure you can customize the code to add any other functionality you wish to have or modify an existing one.

This code is already used in commercial solutions and it proved to be working efficiently among the regular needs but you can apply your changes as I said before.


That's it, hope you find this library useful and I will be waiting for your feedback.
Bye.


2013-02-01

How To Call WCF Web Service With Authentication Credentials

When you deal with WCF web services, sometimes you need to call a web service with certain authentication credentials -username (with/without domain) and password- to be able to take some high privilege actions.

Me myself faced such case and tried to find the proper way to do it. So, I found that the reference I created to the web service has a property called "Credentials" through which I can provide my credentials.

But, when I tried my code, I found that my request is still not authenticated. After further investigations, I decided to search msdn for all properties related to the authentication topic to see if I am missing something.

So, I found that my reference class to my web service inherits from "System.Web.Services.Protocols.SoapHttpClientProtocol" class. So, by the aid of google, I found some interesting results. It is not enough to set the "Credentials" property of my reference. I have three more properties to set to achieve what I want, so lets see some code.

//Creating a reference to your WCF web service
MyCustomService service = new MyCustomService();

/*
AllowAutoRedirect is "true" to automatically redirect the client to follow server redirects; otherwise, "false". The default is "false".

If you send authentication information, such as a user name and password,
you do not want to enable the server to redirect, because this can compromise security
*/
service.AllowAutoRedirect = false;

/*
PreAuthenticate is "true" to pre-authenticate the request; otherwise, "false". The default is "false".

When PreAuthenticate is false, a request is made to the Web service method
without initially attempting to authenticate the user. If the Web service allows anonymous
access, then the Web service method is executed, else, a 401 HTTP return code is sent back.
*/
service.PreAuthenticate = true;

/*
UseDefaultCredentials is "true" if the Credentials property is set to the value of the CredentialCache.DefaultCredentials property; otherwise, "false".
*/
service.UseDefaultCredentials = false;

//Providing credentials
service.Credentials = new NetworkCredential("userName", "password", "domain");

That's it, after setting the four properties "AllowAutoRedirect", "PreAuthenticate", "UseDefaultCredentials" and "Credentials" properly I could get my call to my web service authenticated.


References
System.Web.Services.Protocols.SoapHttpClientProtocol
HttpWebClientProtocol.AllowAutoRedirect
WebClientProtocol.PreAuthenticate
WebClientProtocol.UseDefaultCredentials
WebClientProtocol.Credentials