My Experience with WordPress, Office Live and Google sites

during the last year I was using GoogleSites and MS Office live to host my site. I was spending lot of time just to implement things like RSS or enable users to comments on articles I am posting there. I trust MS and Google so I thought they are providing a good tool and will not find a better ready product at low cost.

after couple of days trying WordPress (free product), I found I was making a huge mistake by hosting my site on MS Office Live or Google sites. with couple of clicks I am doing things I was spending days to implement similar functionality at MS office and google sites.

I would strongly encourage you to try WordPress as platform to host your blog and I am pretty sure you will never say “I was mistaken by using WordPress”

Enable Remote Access for MS SQL Express Edition

By Default when you install SQL Server express edition on a machine you will not be able to connect to it  from another machine by using Microsoft SQL Server Management Studio or application. You need to do specific steps to enable SQL Server Express to accept connections from remote clients.

Recently I read a nice article posted to CodeKicks site about this issue, I would strongly recommend reading that article, to read it click hear

Loops Performance differences in .Net

I never thought there will be a big different when you use different approaches to iterate through a collection of objects. I knew there are some differences between FOREACH/WHILE/FOR loops, but I never thought the different will be as much as an article I read recently in an article published on codekicks site.

The article was demonstrate how using the foreach/while/For loops will affect the performance of your application. The first time I read the article posted there I got convened and posted a recommendation to read it to my personal site. a friend of mine read the article and we had a discussion about it. He had a very true observation about the test applied to come into the conclusion. The main issue raised by Ahmad (my friend who raised the issue) was about the internal operations done by each loop. For example, in FOREACH loop, it is doing an internal object retrieval and assignment to object reference which none of other loops doing it. Even if take this note into consideration, there will be some sort of performance differences between FOREACH/While/FOR loops.

So I still recommending reading the article but please keep into consideration that the test applied is not perfect.

How to Change the Remove Desktop (RDP) Port

You can use "Remote Desktop Connection" tool to connect to other PC and mange them remotely. It is a great tool that is really helpful specially when are talking about outsourcing industry. I do not mean this is only helpful only in IT outsourcing industry, but what I meant it is providing a huge help on that industry because you need to work on windows based machines while you are setting in a different country.

For me, I exposed my personal PC at home to be accessible from public internet network in order to be able to connect to it while I am travelling or at work. But this means I am also exposing my personal PC for hacking risk specially when I am not having a very good secured network infra-structure at home.

Hiding the Remote Desktop port is one step is to make my personal hard to hack. The default remote desktop’s port is 3389. so I decided to change it to something else to make it harder for hackers to attack on my PC. Below is the steps of how to do it:

1. Click on Start menu
2. Choose Run , this will open the RUN dialog box
3. Type REGEDIT and click on ok, this will launch the Registry Editor for you
4. Locate the following key in the registry
  HKEY_LOCAL_MACHINE\System\Current\ControlSet\Control\Terminal Server\WinStations\RDP-Tcp\PortNumber

5. Double click on PortNumber and choose "Decimal" option then change the port number there to something else, let’s say you changed it to be 3333

6. Click OK , then quit Registry Editor
EditDWORDRegistryValue
To connect to the PC, you need to type the port number along with PC’s name or IP just like blow examples:
1. PCNAME:333
2. 192.168.1.100:333

How to register a Plugin inside MS CRM 4.0 using Registration tool shipped with CRM SDK 4.0 Plugins

Plugins on CRM 4.0 replaces Callouts on CRM 3.0.. Mainly Plugins/Callouts is a custom code that should run to response for an action taken place against specific entity. actions like : Create / Update… and so on. Plugins can response to more events than Callouts.. the more events mean more complexity on registering Plugins if we comparing it with Callouts. Thanks for MS, MS released a registration tool with CRM Sdk 4.0 to make out life easier. I listed below main steps to register Plugins inside CRM 4.0.

To register Plugins on CRM 4.0 Please follow these steps:

  1. Your assembly should be strongly named.

  2. The Class that wills response to actions on activity should be implements IPlugin Interface.

  3. Move your assemblies to C:\Program Files\Microsoft Dynamics CRM\Server\bin\assembly\ folder with any resources needed[like XML configuration file, and so on.].

  4. Open Plugin Registration tool that is shipped with CRM Sdk 4.0
  5. Connect to CRM server, then to CRM instance [NB: Your User Should be in Deployment Manager group.
  6. Register your assembly… to open Register assembly dialog Press (Ctrl +A)
RegisterCRM Plugin Building

7.  Add step to your assembly to open Register new step Press(Ctrl + T).. Step is representing a response to an Action happened on CRM Entity..
For example: to response to an Update Event for Contact Entity.. You have to add a step like the following Picture:

Register%20CRM%20Plugin2

How to audit Privileges changes (Security Role) on MS CRM 4.0

One of the challenges that I face while I was working on auditing changes on the major entities at MS CRM 4.0 is to audit changes on Privileges… CRM 4.0 consider privilege entity as a special case this is why we need to build a special case for auditing changes here.

First of all, there is no supported Message (Event) to handle this case. So we have to enable couple of messages to be able to audit changes on security Roles. Those messages called:

1. AddPrivileges. –> this event will handle the creating of a new Security Role

2.  ReplacePrivileges. –> this message will handle adding/update/delete security privileges

The below script help you to enable those messages:

 

/*

Enable Privileges unsupported messages

*/

DECLARE @Message1   uniqueidentifier

DECLARE @Message2 uniqueidentifier

SET @Message1= (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = ‘ReplacePrivileges’)

SET @Message2 = (SELECT SdkMessageId FROM SdkMessageBase WHERE [Name] = ‘AddPrivileges’)

UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1

WHERE SdkMessageId = @Message1

UPDATE SdkMessageFilterBase SET IsCustomProcessingStepAllowed = 1

WHERE SdkMessageId = @Message2

After applying the above data script to MSCRM DB, you will be able to find those messages exposed for you on MS CRM 4.0 Plugin Registration tool so you will be able to register a plugin against those messages (Events). Now we need to build the Message handler to audit any changes, below steps showing you how to do that.

I am going to use the same code that audit regular entities with a little adjustments, the reasons of my adjustments are:

· The Pre-Image and Post-Image will not have enough info that needed by Audit handlers; thus I need to add a special handler for that.

· The Audit code that you can download from internet does not handle ReplacePrivileges/AddPrivileges Messages, thus we need to build a special case for that.

Note: To read more about default Audit component please refer to this article: "Auditing MS CRM 4.0 Record Changes"

To solve the problem (A), I have to add a Pre Handler for ReplacePrivilege Message, this is a very simple handler that will contains code to store the current Privileges (before doing update) on a shared Variable to be passed to the Post ReplacePrivilege message handler; below is the code of PreReplacePrivilege Message handler:

public class PreReplacePrivilege:IPlugin

{

#region IPlugin Members

public void Execute(IPluginExecutionContext context)

{

if (context.MessageName == "ReplacePrivileges")

{

if (context.InputParameters.Contains("RoleId"))

{

context.SharedVariables["PreRolePrivilagesValues"] =

Utilities.GetRolePrivilages(context.InputParameters.Properties["RoleId"].ToString(),

context.CreateCrmService(true));

context.SharedVariables["RoleId"] = context.InputParameters.Properties["RoleId"];

}

}

}

#endregion

}

static class Utilities

{

/// <summary>

/// Get privilages for Roles.

/// </summary>

public static Dictionary<string, string> GetRolePrivilages(string roleId, ICrmService crmService)

{

Microsoft.Crm.Sdk.Query.AllColumns cols = new Microsoft.Crm.Sdk.Query.AllColumns();

Dictionary<Guid, string> privileges = GetAllPrivilages(crmService); //Get list of all privileges

RetrieveRolePrivilegesRoleRequest request = new RetrieveRolePrivilegesRoleRequest();

request.RoleId = new Guid(roleId);

RetrieveRolePrivilegesRoleResponse response = (RetrieveRolePrivilegesRoleResponse)crmService.Execute(request);

Dictionary<string, string> rolePrigivleges = ResolvePrivilageNames(privileges, response.RolePrivileges);

return rolePrigivleges;

}

/// <summary>

/// Get all privilages on system

/// </summary>

/// <param name="crmService"></param>

/// <returns></returns>

private static Dictionary<Guid, string> GetAllPrivilages(ICrmService crmService)

{

Dictionary<Guid, string> privilages = new Dictionary<Guid, string>();

RetrievePrivilegeSetRequest requestp = new RetrievePrivilegeSetRequest();

requestp.ReturnDynamicEntities = true;

RetrievePrivilegeSetResponse responsep = (RetrievePrivilegeSetResponse)crmService.Execute(requestp);

foreach (DynamicEntity p in responsep.BusinessEntityCollection.BusinessEntities)

{

privilages.Add( ((Key)p["privilegeid"]).Value,p["name"].ToString());

}

return privilages;

}

/// <summary>

/// Resolving Privileges Names

/// </summary>

/// <param name="rolePrivilegesList"></param>

/// <param name="crmService"></param>

/// <returns></returns>

public static Dictionary<string, string> ResolvePrivilageNames(RolePrivilege[] rolePrivilegesList, ICrmServicecrmService)

{

Dictionary<Guid, string> privileges = GetAllPrivilages(crmService);

Dictionary<string, string> rolePrigivleges = new Dictionary<string, string>();

foreach (RolePrivilege r in rolePrivilegesList)

{

rolePrigivleges.Add(privileges[r.PrivilegeId], r.Depth.ToString());

}

foreach (KeyValuePair<Guid, string> pair in privileges)

{

if (!rolePrigivleges.ContainsKey(pair.Value))

rolePrigivleges.Add(pair.Value, "None");

}

return rolePrigivleges;

}

public static string GetPropertyValue(object property)

{

try

{

if (property.GetType() == typeof(CrmBoolean))

return ((CrmBoolean)property).Value.ToString();

else if (property.GetType() == typeof(CrmDateTime))

return ((CrmDateTime)property).UserTime.ToString();

else if (property.GetType() == typeof(Owner))

return ((Owner)property).Value.ToString();

else if (property.GetType() == typeof(Lookup))

return ((Lookup)property).Value.ToString();

else if (property.GetType() == typeof(Picklist))

return ((Picklist)property).Value.ToString();

else if (property.GetType() == typeof(StringProperty))

return ((StringProperty)property).Value.ToString();

else if (property.GetType() == typeof(LookupProperty))

return ((LookupProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(OwnerProperty))

return ((OwnerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(PicklistProperty))

return ((PicklistProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(CrmDateTimeProperty))

return ((CrmDateTimeProperty)property).Value.UserTime.ToString();

else if (property.GetType() == typeof(KeyProperty))

return ((KeyProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmBooleanProperty))

return ((CrmBooleanProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmDecimalProperty))

return ((CrmDecimalProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmFloatProperty))

return ((CrmFloatProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmMoneyProperty))

return ((CrmMoneyProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CrmNumberProperty))

return ((CrmNumberProperty)property).Value.Value.ToString();

else if (property.GetType() == typeof(CustomerProperty))

return ((CustomerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(CustomerProperty))

return ((CustomerProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(StatusProperty))

return ((StatusProperty)property).Value.name.ToString();

else if (property.GetType() == typeof(StateProperty))

return ((StateProperty)property).Value.ToString();

else if (property.GetType() == typeof(UniqueIdentifierProperty))

return ((UniqueIdentifierProperty)property).Value.Value.ToString();

else if (property == null)

return "";

else

return property.ToString();

}

catch

{ return ""; }

}

public static AuditDifferenceCollection AddDifferences(IMetadataService metaService, string entityName,DynamicEntity preImage, DynamicEntity postImage)

{

AuditDifferenceCollection col = new AuditDifferenceCollection();

System.Collections.Hashtable attributesMetadata =

MetadataHelper.GetEntityAttributeMetadata(metaService, entityName, Microsoft.Crm.Sdk.Metadata.EntityItems.IncludeAttributes);

//For any Message that has a Pre and/or Post Image. I will add the values to the Audit Differences.

foreach (Property prop in preImage.Properties)

{

if(prop.GetType()!= typeof(KeyProperty) && prop.Name!="modifiedby" && prop.Name != "modifiedon" && prop.Name != "createdby" && prop.Name != "createdon")

{

col.Add(new AuditDifference(prop.Name,attributesMetadata[prop.Name].ToString(),Utilities.GetPropertyValue(prop), ""));

}

}

foreach (Property prop in postImage.Properties)

{

if(prop.GetType()!= typeof(KeyProperty) && prop.Name!="modifiedby" && prop.Name != "modifiedon" && prop.Name != "createdby" && prop.Name != "createdon")

{

if (col.Contains(prop.Name))

{

AuditDifference diff = col[prop.Name];

diff.CurrentValue = Utilities.GetPropertyValue(prop);

col[prop.Name] = diff;

}

else

{

col.Add(new AuditDifference(prop.Name, attributesMetadata[prop.Name].ToString(),"",Utilities.GetPropertyValue(prop)));

}

}

}

return col;

}

public static AuditDifferenceCollection AddDifferences(IMetadataService metaService, string entityName,Dictionary<string, string> preValues, Dictionary<string, string> postValues)

{

AuditDifferenceCollection col = new AuditDifferenceCollection();

if (preValues != null && preValues.Count > 0)

{

foreach (KeyValuePair<string, string> entry in preValues)

{

col.Add(new AuditDifference(entry.Key + ":" + entry.Value, entry.Value, ""));

}

}

if (postValues != null & postValues.Count > 0)

{

foreach (KeyValuePair<string, string> entry in postValues)

{

if (col.Contains(entry.Key + ":" + entry.Value))

{

AuditDifference diff = col[entry.Key + ":" + entry.Value];

diff.CurrentValue = entry.Value;

col[entry.Key + ":" + entry.Value] = diff;

}

else

{

col.Add(new AuditDifference(entry.Key + ":" + entry.Value, "", entry.Value));

}

}

}

return col;

}

public static string AddAttributeToList(string value, string list)

{

if (list.IndexOf(value) == -1)

{

if (list == "")

list = value;

else

 

===================================

To solve problem (B) we need to adjust the Execute Method of  Create Class… this is the full code after adjustment for Create class:

==================================

public class Create : IPlugin

{

string m_config;

string m_secureConfig;

private string _relationshipAttribute = "";

private string _primaryAttribute = "";

public string Config

{

get { return m_config; }

set { m_config = value; }

}

public string SecureConfig

{

get { return m_secureConfig; }

set { m_secureConfig = value; }

}

public Create(string config, string secureConfig)

{

m_config = config;

m_secureConfig = secureConfig;

if (config.Trim() != "")

{

string[] configSettings = config.Split(‘;’);

for (int i = 0; i < configSettings.Length; i++)

{

string[] values = configSettings[i].Split(‘=’);

switch (values[0].ToString().ToLower())

{

case "primaryattribute":

_primaryAttribute = values[1].ToString().Trim().ToLower();

break;

case "relationshipattribute":

_relationshipAttribute = values[1].ToString().Trim().ToLower();

break;

}

}

}

}

public void Execute(IPluginExecutionContext context)

{

string attributes = "";

Audit audit = new Audit();

DynamicEntity PreImage = new DynamicEntity();

DynamicEntity PostImage = new DynamicEntity();

audit.Service = context.CreateCrmService(true);

audit.MetadataService = context.CreateMetadataService(true);

audit.EntityName = context.PrimaryEntityName;

audit.Type = context.MessageName;

audit.Name = context.PrimaryEntityName + " " + context.MessageName;

Dictionary<String, String> preValues = new Dictionary<string, string>();

Dictionary<String, String> postValues = new Dictionary<string, string>();

if (context.InputParameters.Properties.Contains("Target") &&

context.InputParameters.Properties["Target"] is Moniker)

{

Moniker moniker = (Moniker)context.InputParameters.Properties["Target"];

audit.RecordID = moniker.Id.ToString();

}

else if (context.InputParameters.Properties.Contains("EntityMoniker") &&

context.InputParameters.Properties["EntityMoniker"] is Moniker)

{

Moniker moniker = (Moniker)context.InputParameters.Properties["EntityMoniker"];

audit.RecordID = moniker.Id.ToString();

}

else if (context.InputParameters.Properties.Contains("Target") &&

context.InputParameters.Properties["Target"] is DynamicEntity)

{

//if the transaction is create then get the ID from the OutputParameters

if (context.OutputParameters.Contains("id"))

audit.RecordID = context.OutputParameters.Properties["id"].ToString();

//pull the KeyProperty from the entity.

foreach (Property prop in ((DynamicEntity)context.InputParameters.Properties["Target"]).Properties)

{

if (prop.GetType() == typeof(KeyProperty))

{

audit.RecordID = ((KeyProperty)prop).Value.Value.ToString();

break;

}

}

}

else if (context.MessageName == "ReplacePrivileges" ||

context.MessageName == "AddPrivileges" ||

context.MessageName == "RemovePrivilege") //Unsupported Message and it needs special handling

{

if(context.InputParameters.Properties.Contains("RoleId"))

audit.RecordID = ((Guid)context.InputParameters.Properties["RoleId"]).ToString();

else if(context.SharedVariables.Contains("RoleId"))

audit.RecordID = ((Guid) context.SharedVariables["RoleId"]).ToString();

//Pull Pre state of previleges from shared variable populated on PreStage plugin

if (context.SharedVariables.Contains("PreRolePrivilagesValues"))

preValues = (Dictionary<string, string>)context.SharedVariables["PreRolePrivilagesValues"];

else

preValues = new Dictionary<string, string>();

if (context.InputParameters.Contains("Privileges"))

{

postValues = Utilities.ResolvePrivilageNames(

(RolePrivilege[])context.InputParameters["Privileges"], audit.Service);

}

else

postValues = new Dictionary<string, string>();

}

//Get the Pre and Post Images

if (context.PreEntityImages.Properties.Contains("Images") && context.PreEntityImages.Properties["Images"] isDynamicEntity)

PreImage = (DynamicEntity)context.PreEntityImages.Properties["Images"];

if (context.PostEntityImages.Properties.Contains("Images") && context.PostEntityImages.Properties["Images"] isDynamicEntity)

PostImage = (DynamicEntity)context.PostEntityImages.Properties["Images"];

//Compare the images values.

//Messages not support Pre/Post images.

if (string.IsNullOrEmpty(PreImage.Name) && string.IsNullOrEmpty(PostImage.Name))

{

audit.AuditDifferences = Utilities.AddDifferences(audit.MetadataService, context.PrimaryEntityName, preValues, postValues);

}

else //Messages support Pre/Post images.

{

audit.AuditDifferences = Utilities.AddDifferences(audit.MetadataService, context.PrimaryEntityName, PreImage, PostImage);

}

foreach (AuditDifference diff in audit.AuditDifferences)

{

if (context.MessageName == "AddPrivileges" || context.MessageName == "ReplacePrivileges")

diff.ReplaceAttributeName = string.Format("Privilege:{0}", diff.AttributeName.Substring(0, diff.AttributeName.IndexOf(":")));

if (diff.CurrentValue != diff.PreviousValue)

attributes = Utilities.AddAttributeToList(diff.AttributeDisplayName, attributes);

}

if (_relationshipAttribute.Trim() != "" && audit.RecordID.Trim() != "" && context.MessageName != "Delete")

audit.Relationship = new EntityRelationship(_relationshipAttribute, new Guid(audit.RecordID));

audit.Attributes = attributes;

if (!context.PreEntityImages.Properties.Contains("Images")

&& !context.PostEntityImages.Properties.Contains("Images")

&& context.MessageName != "ReplacePrivileges")

{

audit.Create();

}

else

{

if (attributes.Trim() != "")

audit.Create();

}

}

I am attaching below the  3 classes I made changes on, I got the original classes and do the changes to them.

I hope you will have this useful and will solve your issue

 

Download Code

How to Know the Execution Time of SQL Statements in Simple Way

When client report to you a performance issue in certain area on your system, you start troubleshooting and tackling the issue. the performance bottleneck might be everywhere on your system, it might be on front-end, business layer, data access layer, … etc. The scope of this article is to check the execution time taken for certain SQL statement till you get the result out from the DB. this would  very helpful if the performance issue is at  data retrieval.  after figuring out the performance bottleneck is at data retrieval, the solution might be as easy as adding index for some of table’s columns. but in most cases you might get into a trouble of changing the body of SQL statements to have better performance. so you need a tool to assess your changes. SQL 2008 IDE shipped with a built-in tool that I found so much helpful and made my life much easier.

if you notice there is a small icon on tool bar called “Include Client Statistics”, it is by default not enabled. if you enable it and try to execute a sql statement, you will get a new tab at the result panel. below is snapshot of the new tab on the result panel

 

building

 

SQLClientStaticsResultPanel

 

Notice the statics between different trials. it will keep the statics up to 10 trials. The statics including with some visual graphics to let you note the effect of your changes weather it increase the execution time or it reduced it.
Try it and you will find it so useful!

Be Simple winner

"Be Simple winner" this is a phrase I heard from a friend of mine long a time ago. He was advising me in regards to couple of things. After thinking of it I believed it is totally a true statement. our discussion was about software development industry specifically but I believe this statement can be reflected to other industries as well, being a simple winner does not means to deliver a bad quality software that does not meet your client requirements. being simple winner means to develop a software that meets client requirements and not exceed the requirements to extra requirements that your client is not in need for it. You should not deliver something that is extra for your client and they might not get benefited from . This does not means to ignore the basic software requirements that your client did not ask for explicitly like security and performance requirements. actually ignoring such a basic requirements might make your product not useable at all and your efforts will ends up with a big failure because of ignoring these basic requirements.

Being simple winner is targeting to deliver software that will make your client happy and at the same time meets the project success factors like being within budget, deadline, high quality… etc deliverables.

Personally I believe being simple winner can be applied in all aspects on your life not only at work level.

Don’t Delete Negative Reviews/Comments

I had discussion with a friend of mine couple of days about negative reviews that somebody might have on their site. He was after convincing me to simply DELETE negative comments or reviews. His idea is simply hide that negative thing from being displaying on your website and protect yourself from it.

My opinion was totally against that. I believe I should keep negative comments just like keeping positive comments. There are many reasons that letting you doing that. Simply it is part of honest relationship between you and your readers/customers. It is a great chance to have conversation with your reader/customer and to get his feedback and if he/she has the correct opinion, then you need to fix that immediately.

What trigger me to write this article not only the conversation I have with my friend. The trigger is mainly an article I just read about the same subject. The author of this article is Lisa Barone s Co-Founder and Chief Branding Officer of Outspoken Media, Inc. I strongly recommend to read this article.

How to Make your URL shorter

For many reasons you might ends you having a very long URL for certain pages, distributing the long URL might be an issue for you as people usually does not remember long URLs and they like having short URLs.

Today there is many websites that make your long URLs shorter and make your life easier. Personally I checked http://tinyurl.com  site and it worked just perfectly for me. I am pretty sure there are more sites that are doing the same thing for you. But I am recommending this one for you.