Wednesday, March 20, 2013

Make Websites Startup Faster When Debugging

Currently I’m working on an ASP.net website that caches data during the Application_Start event of the Global.asax.cs.  Generally this is a great idea for a website, especially when deploying a website in a load balanced environment, because the penalty of loading cached data can be spent in one page load.  Take the server out of the load balancer, deploy your changes, hit the first page, verify that no errors occurred, and put the server back in the balancer.  This ensures that a user hitting the site, won’t have to pay the penalty of loading the cache data.

But, this is not so much fun when developing/debugging.  90% of the time a developer works on a single page at a time, and if the page uses only a small fraction of the cache, or none at all, they get to pay the cache load penalty each time they restart the website.  Having to wait even 20 seconds each time the website is restarted in Visual Studio is real productivity killer.

Some developers may opt to comment out the cache loading portion of the Application_Start.  But if they accidently commit the change into source control, production could be affected the next time it’s deployed.  And the next time they get latest from source control, they’ll loose their local commented out Application_Start.   So how does one ensure that production will always cache the data on Application_Start, without forcing developers to pay the cache load penalty?

System.Diagnostics.Debugger.IsAttached to the Rescue!

protected void Application_Start(object sender, EventArgs e)
{
     if (System.Diagnostics.Debugger.IsAttached)
     {
         // Speed up the first page load for debugging by not loading all of the Cache
         return;
     }
     PreloadCachedValues();
}
Debugger.IsAttached will check to see if a debugger is currently attached.  Since this will always be the case when developing the website locally, and never be the case in production (assuming there isn’t some catastrophic production event), developers can enjoy the productivity improvements when developing the website, without risking any performance issues in production.

Friday, March 8, 2013

Simplifying Retrieval of Aliased Values in CRM 2011

Aliased values have always annoyed me when performing a QueryExpression, or FetchXML Query.  It requires a lot of boiler plate code each time you attempt to retrieve an aliased value (checking for it to exist, including the entity logical name, casting the aliased value’s value to the correct type, etc).  Due to being a lazy developer who believes if I do something twice, that’s once too many, I created some extension methods to simplify the process.  I’m posting them here today for the world to enjoy.
First the code:  There are 5 methods. 
  1. GetAliasedValue<T> – This is the main method.  It’s an extension method on Entity, so it can be used on any entity, early bound or late.  It accepts the an attributeName which is the name of the aliased attribute.  As long as you don’t have duplicate aliased names (i.e. linking/joining on two different entities, and returning the same attribute name from both),  you don’t have to preappend the the logical name of the entity of the aliased value.  It is also generic, so that it will cast the value of the aliased value to the generic type.
  2. SplitAliasedAttributeEntityName – This helper method splits the attribute name passed in, by a period to determine if an entity logical name has been passed in, or only an attribute name.
  3. IsAttributeAliasedValue – This method determines if a particular aliased value is the aliased value requested by the user
  4. GetAliasedValueOrDefault<T> – By default GetAliasedValue<> will throw an exception if the aliased value wasn’t found, along with a list of the attributes contained in the collection.  This checks to see if the aliased value exists, and gets the default value for the generic type if isn’t doesn’t exist.
  5. HasAliasedAttribute – Used by GetAliasedValueOrDefault<T>.  Also helpful if you want to do some other logic besides getting the default value if it isn’t found
         /// <summary>
         /// Returns the Aliased Value for a column specified in a Linked entity
         /// </summary>
         /// <typeparam name="T">The type of the aliased attribute form the linked entity</typeparam>
         /// <param name="entity"></param>
         /// <param name="attributeName">The aliased attribute from the linked entity.  Can be preappeneded with the
         /// linked entities logical name and a period. ie "Contact.LastName"</param>
         /// <returns></returns>
         public static T GetAliasedValue<T>(this Entity entity, string attributeName)
         {
             string aliasedEntityName = SplitAliasedAttributeEntityName(ref attributeName);
             AliasedValue aliased;
             foreach (var attribute in entity.Attributes.Values)
             {
                 aliased = attribute as AliasedValue;
                 if(entity.IsAttributeAliasedValue(attributeName, aliasedEntityName, aliased))
                 {
                     try
                     {
                         return (T)aliased.Value;
                     }
                     catch (InvalidCastException)
                     {
                         throw new InvalidCastException(
                             String.Format("Unable to cast attribute {0}.{1} from type {2} to type {3}",
                                     aliased.EntityLogicalName, aliased.AttributeLogicalName,
                                     typeof(T).Name, aliased.Value.GetType().Name));
                     }
                 }
             }
             throw new Exception("Aliased value with attribute " + attributeName +
                 " was not found!  Only these attributes were found: " + String.Join(", ", entity.Attributes.Keys));
         }


         /// <summary>
         /// Handles spliting the attributeName if it is formated as "EntityAliasedName.AttributeName",
         /// updating the attribute name and returning the aliased EntityName
         /// </summary>
         /// <param name="attributeName"></param>
         /// <param name="aliasedEntityName"></param>
         private static string SplitAliasedAttributeEntityName(ref string attributeName)
         {
             string aliasedEntityName = null;
             if (attributeName.Contains('.'))
             {
                 var split = attributeName.Split(new char[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
                 if (split.Length != 2)
                 {
                     throw new Exception("Attribute Name was specified for an Alaised Value with " + split.Length +
                     " split parts, and two were expected.  Attribute Name = " + attributeName);
                 }
                 aliasedEntityName = split[0];
                 attributeName = split[1];
             }
             return aliasedEntityName;
         }


        private static bool IsAttributeAliasedValue(this Entity entity, string attributeName, string aliasedEntityName, AliasedValue aliased)
         {
             bool value =
            (aliased != null &&
                 (aliasedEntityName == null || aliasedEntityName == aliased.EntityLogicalName) &&
                 aliased.AttributeLogicalName == attributeName);

             /// I believe there is a bug in CRM 2011 when dealing with aggregate values of a linked entity in FetchXML.
             /// Even though it is marked with an alias, the AliasedValue in the Attribute collection will use the 
             /// actual CRM name, rather than the aliased one, even though the AttributeCollection's key will correctly
             /// use the aliased name.  So if the aliased Attribute Logical Name doesn't match the assumed attribute name
             /// value, check to see if the entity contains an AliasedValue with that key whose attribute logical name 
             /// doesn't match the key (the assumed bug), and mark it as being the aliased attribute
             if (!value && aliased != null && entity.Contains(attributeName))
             {
                 var aliasedByKey = entity[attributeName] as AliasedValue;
                 if (aliasedByKey != null && aliasedByKey.AttributeLogicalName != attributeName &&
                      Object.ReferenceEquals(aliased, aliasedByKey))
                 {
                     value = true;
                 }
             }
             return value;
         }


         /// <summary>
         /// Returns the Aliased Value for a column specified in a Linked entity, returning the default value for 
         /// the type if it wasn't found
         /// </summary>
         /// <typeparam name="T">The type of the aliased attribute form the linked entity</typeparam>
         /// <param name="entity"></param>
         /// <param name="attributeName">The aliased attribute from the linked entity.  Can be preappeneded with the
         /// linked entities logical name and a period. ie "Contact.LastName"</param>
         /// <returns></returns>
         public static T GetAliasedValueOrDefault<T>(this Entity entity, string attributeName)
         {
             T value;
             if (entity.HasAliasedAttribute(attributeName))
             {
                 value = entity.GetAliasedValue<T>(attributeName);
             }
             else
             {
                 value = default(T);
             }
             return value;
         }


         /// <summary>
         /// Returns the Aliased Value for a column specified in a Linked entity
         /// </summary>
         /// <typeparam name="T">The type of the aliased attribute form the linked entity</typeparam>
         /// <param name="entity"></param>
         /// <param name="attributeName">The aliased attribute from the linked entity.  Can be preappeneded with the
         /// linked entities logical name and a period. ie "Contact.LastName"</param>
         /// <returns></returns>
         public static bool HasAliasedAttribute(this Entity entity, string attributeName)
         {
             string aliasedEntityName = SplitAliasedAttributeEntityName(ref attributeName);
             return entity.Attributes.Values.Any(a =>
                 entity.IsAttributeAliasedValue(attributeName, aliasedEntityName, a as AliasedValue));
         }


Just add these methods to an Extension class and ease the burden aliased values incur:


        public Guid GetBusinessUnit(IOrganizationService service, Guid buildingId)
        {
             var qe = new QueryExpression("new_building");
             qe.ColumnSet.AddColumns("new_buildingid", "new_name");
             qe.Criteria.AddCondition("new_buildingid", ConditionOperator.Equal, buildingId);
             var location = qe.AddLink("new_location", "new_locationid", "new_locationid");
             location.Columns.AddColumn("new businessunitid");
             return service.RetrieveMultiple(qe).Entities.FirstOrDefault().GetAliasedValue<EntityReference>("new_businessunitid").Id;
        }