Skip to content
Oct 3 14

Why there no Windows 9

by Dave Corun

A few people have asked and I saw a post on Reddit yesterday from someone claiming to be a dev at MSFT.

It’s because of compatibility issues.  A ton of code was written back in Windows 95/98 days that does a .StartsWith(“Windows9”) check to see if the app can run.

So that pragmatic answers makes sense to me.

https://searchcode.com/?q=if%28version%2Cstartswith%28%22windows+9%22%29

This is technically Windows 6.4 for similar reasons.  Developers back in the day used to write code looking for things that were greater than 6.1 before running (back in Vista’s days).  If Windows reported itself as 7 a whole lot of code would fail.

internal bool SupportsTaskProgress() {
    if (System.Environment.OSVersion.Version.Major >= 6) {
        if (System.Environment.OSVersion.Version.Minor >= 1) {
            return true;
        }
    }
    return false;
}

http://www.gregcons.com/KateBlog/OperatingSystemVersionChecking.aspx

 image

// Dave

Sep 23 14

Querying Active Directory for Domain Names

by Dave Corun

When creating users through the CRM SDK you must specify the domain name.  However in some situations you may not have the user’s domain name if the environment has multiple Active Directory domains within a forest.

Here is a code snippet that queries Active Directory for their name.

 

   1: public string GetUserName(string username)

   2: {

   3:     string retval = string.Empty;

   4:  

   5:     var currentForest = Forest.GetCurrentForest();

   6:     var globalCatalog = currentForest.FindGlobalCatalog();

   7:  

   8:     using (var searcher = globalCatalog.GetDirectorySearcher())

   9:     {

  10:         using (var de = new DirectoryEntry(searcher.SearchRoot.Path))

  11:         {

  12:             using (var ds = new DirectorySearcher(de))

  13:             {

  14:                ds.ReferralChasing = ReferralChasingOption.All;

  15:  

  16:                ds.Filter = String.Format("(&(objectCategory=person)(objectClass=user)(SAMAccountName={0}))", username);

  17:                ds.PropertiesToLoad.Add("UserPrincipalName");

  18:  

  19:                SearchResult result = ds.FindOne();

  20:  

  21:                 if(result != null)

  22:                 {

  23:                     retval = result.Properties["UserPrincipalName"][0].ToString();

  24:                 }

  25:             }

  26:         }

  27:     }

  28:  

  29:     return retval;

  30: }

 

Thanks to Chris for the code!

Hope this helps!

// Dave

Oct 31 12

$ vs. jQuery

by Dave Corun

Short Version:

Use jQuery, not $

Long Version:

When I was a younger man, I had to battle a rather complex bug in an application with 6 different JavaScript frameworks and different versions of each one.  It was a mess.

When you use $ you’re simply using that character as an alias for jQuery.  Lots of people use $.  People write blogs and books and write $.

However, prototype.js also uses that alias.

Only one can “win” and unfortunately many other 3rd party libraries, including JavaScriptSpellchecker.com, have prototype.js in its gooey center.  This means that any page that has the spellcheck on it could effectively take ownership of $ when you least expect it.  It’s awesome.

There is a workaround, which is to call jQuery.noConflict() before you go to use jQuery, but I think we all agree that’s rather silly.

So please, type out jQuery and not $.

Example:

jQuery.ajax()

 

It’s only 5 more characters to type…

// Dave

Jan 5 12

CRM 2011–Retrieve Plugin

by Dave Corun

So you want to write a plugin that executes every time a user opens a record.

Usually this would be frowned upon because this code could easily present a performance issues, especially if the data you’re gathering is hosted on an external resource.

In the off-change you do need to do this, here is the solution:

 

First, create a new Plugin and sign the assembly with a key:

public void Execute(IServiceProvider serviceProvider)
{
    // Obtain the execution context from the service provider.
    Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)
        serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

    if (context.Depth == 1)
    {
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

        // Obtain the target entity from the input parmameters.
        EntityReference entity = (EntityReference)context.InputParameters["Target"];

        ColumnSet cols = new ColumnSet(
                             new String[] { "lastname", "firstname", "address1_name" });

        var contact = service.Retrieve("contact", entity.Id, cols);

        if (contact != null)
        {
            if (contact.Attributes.Contains("address1_name") == false)
            {
                Random rndgen = new Random();
                contact.Attributes.Add("address1_name", "first time value: " + rndgen.Next().ToString());
            }
            else
            {
                contact["address1_name"] = "i already exist";
            }
            service.Update(contact);
        }
    }
}

 

Next, hop over to the Plugin Registration Tool (included with the CRM SDK) and register the plugin as follows:

image

 

What you’ll end up with in this example is:

On first open of the record:

clip_image002

On all future opens of the record:

clip_image002[5]

 

 

This has not been tested with CRM 2011 Online.  Use at your own risk, your mileage may vary. Smile

 

// Dave

Jan 5 12

Creating Business Units and Teams Programmatically

by Dave Corun

Assumed Background Information:

Introduction to Entities in Microsoft Dynamics CRM

http://msdn.microsoft.com/en-us/library/gg309396.aspx

You may find yourself working on a complex CRM implementation where you need to create a number of Business Units and Teams.

You may find it helpful to create a utility to do this activity on your behalf.

This following code reads the list of Business Units and Teams from an XML file and calls the methods below to do the heavy lifting.

Creating a Business Unit

/// <summary>
/// Creates the BusinessUnit with the given name
/// </summary>
/// <param name="strParentName">ParentBusiness Unit Name</param>
/// <param name="strName">Name of Business Unit needs to be created</param>
private void CreateBusinessUnit(string strParentName, string strName)
{
    try
    {
        Entity e = new Entity("businessunit");
        e.Attributes["name"] = strName;

        //Get the Parent BusinessUnit Guid from the Parent BusinessUnit Name
        string strParentGuid = strParentName;

        //Check for the valid Guid. If it is not a guid retrieve the guid based on the name of the business unit
        if (!IsGUID(strParentGuid))
        {
            strParentGuid = GetParentUnitId(strParentName);
        }


        //If Guid Exists then place it into the ParentBusinessUnitId lookup field of BusinessUnit entity
        if (strParentGuid.Length > 0)
        {
            EntityReference erParentBusinessUnit = new EntityReference("businessunit", new Guid(strParentGuid));
            e.Attributes["parentbusinessunitid"] = erParentBusinessUnit;
        }

        //Create the BusinessUnit
        _service.Create(e);
        Console.WriteLine("Created BusinessUnit : " + strName + " Successfully");
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error While Creating a Business Unit :  " + strName + ". Error Message: " + ex.Message);
    }

}

 

 

Creating a Team

private void CreateTeam(string strBUName, string strTeamName)
{
    try
    {
        Entity e = new Entity("team");
        e.Attributes["name"] = strTeamName;

        //Get the Business Unit Name which the team belongs to
        string strBU = GetParentUnitId(strBUName);

        //If Guid Exists then place it into the BusinessUnit lookup field of Team entity
        if (strBU.Length > 0)
        {
            EntityReference erBusinessUnit = new EntityReference("businessunit", new Guid(strBU));
            e.Attributes["businessunitid"] = erBusinessUnit;
        }

        //Create the Team
        _service.Create(e);
        Console.WriteLine("Created Team : " + strTeamName + " Successfully under Business Unit: " + strBUName);
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error While Creating a Team:  " + strTeamName + ". Error Message: " + ex.Message);
    }

}

 

Getting the ID of the Business Unit

/// <summary>
///  Gets the BusinessUnitID when the Businessunit name is passed
/// </summary>
/// <param name="BUName">BusinessUnit Name</param>
/// <returns>Business Unit Guid</returns>
private string GetParentUnitId(string BUName)
{
    try
    {
        //Checks whether the BUName is empty or null and then proceed into the query 
        if (BUName != null && BUName.Length > 0)
        {
            QueryByAttribute qba = new QueryByAttribute("businessunit");
            //Condition parameters is Businessunit Name
            qba.AddAttributeValue("name", BUName);
            //Values need to be retrieved is the Guid of Business Unit
            qba.ColumnSet = new ColumnSet("businessunitid", "createdon");


            DataCollection<Entity> dcBUDetails;

            //Retrieve the value based on the condition given
            dcBUDetails = _serviceProxy.RetrieveMultiple(qba).Entities;

            //Return the Guid of the BusinessUnit
            if (dcBUDetails.Count == 1)
            {
                if (dcBUDetails[0] != null)
                {
                    if (dcBUDetails[0].Id != null)
                    {
                        return dcBUDetails[0].Id.ToString();
                    }
                }
            }
            else
            {

                //Where there are more than one BusinessUnit with the same name take the latest created business unit to create the team or business  unit
                string id = string.Empty;
                DateTime dtMax = new DateTime();
                //Get the date of creation of the first BU
                DateTime.TryParse(dcBUDetails[0].Attributes["createdon"].ToString(), out dtMax);
                for (int i = 1; i < dcBUDetails.Count; i++)
                {
                    //Compare all the BU with the same name and get the latest Business unit created to create a team
                    DateTime dt;
                    DateTime.TryParse(dcBUDetails[i].Attributes["createdon"].ToString(), out dt);
                    if (dt > dtMax)
                    {
                        dtMax = dt;
                        id = dcBUDetails[i].Id.ToString();
                    }

                }
                return id;
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine("Error While retrieving Guid of Business Unit " + ex.Message);
    }

    return "";

}
Jun 6 11

Learning SQL

by Dave Corun

Hey how are you?

What steps should I take to become a SQL Developer?

 

If I was just learning, I would start by installing the SQL Server Express edition locally (free):

http://www.microsoft.com/express/Database/

It should come with a number of tutorials and walkthroughs.

From there, I’d recommend looking at the MCTS Certification. It’s the baseline certification for those new to SQL Server:

http://www.microsoft.com/learning/en/us/certification/cert-sql-server.aspx#tab2

In particular, 70-433 is all about database development.

http://www.microsoft.com/learning/en/us/exam.aspx?ID=70-433&locale=en-us#tab3

If you look over the Skills Measured, you’ll get a good feel for what a typical SQL Developer needs to know. Under Preparation Materials you’ll find a number of resources, including eLearning and MSPress training kits. Typically you can find the training kit books on the cheap at amazon.com, because once someone has passed the cert, they don’t have a need for it anymore.

I’m not saying you should get the certification. It’s just a good way to have an outline and an ultimate goal. The learning material will also be a bit more structured this way.

Hope this helps!

// Dave

Feb 23 11

Dynamics CRM 4.0 –Custom ASPX Page in a Multi-Tenancy Environment

by Dave Corun

 

When OnPremise Dynamics CRM 4.0 is configured with a single organization, it sends the organization name in the query string.

When OnPremise Dynamics CRM 4.0 is configured with multiple organizations, it sends the organization name in the path.

Here’s how to do a quick fallback if you need the custom page to work in both environments.

// grab the incoming request parameters
Trace.Write("Request.ApplicationPath: " + Request.ApplicationPath);
Trace.Write("Request['orgname']: " + Request["orgname"]);

// Multi-tenant CRM installations will have the Org Name as part of the Application path.
if (Request.ApplicationPath != "/")
{
    _orgName = Request.ApplicationPath.Replace("/", "");
}
else
{
    _orgName = Request["orgname"];
}
Trace.Write("orgname: " + _orgName);

Hope this helps!

// Dave

Feb 23 11

Multi-Tenancy IFRAMEs in Dynamics CRM 4.0

by Dave Corun

Before

var url = "/userdefined/areas.aspx?oId=" + oId + "&oType=" + oType + "&security=" + security + "&tabSet=" + tabSet;

After

var url = prependOrgName("/userdefined/areas.aspx?oId=" + oId + "&oType=" + oType + "&security=" + security + "&tabSet=" + tabSet);

http://msdn.microsoft.com/en-us/library/cc905758.aspx

 

Hope this helps!

 

// Dave

Jan 28 11

Good Blog Post

by Dave Corun

10 Reasons Developers Should Blog

 

// Dave

Dec 4 10

Validation Messages – MVVM Approach

by Dave Corun

What follows is a simple way to carry along a collection of Validation Messages in your ViewModel, and then bind them to the UI at runtime.

 

The first step is to create an ObservableCollection of validation messages on the ViewModel class.  This is going to hold the messages at runtime.

public ObservableCollection<TLValidationMessage> ValidationMessages
{
    get { return _validationMessages; }
    set
    {
        if (_validationMessages == value) return;
        _validationMessages = value;
        NotifyPropertyChanged("ValidationMessages");
    }
}

We’ll also need to define what TLValidationMessages are.  They’re simply a Message string and a Severity Level, which could be used to change the styling at runtime based on the importance of the message.

public enum SeverityLevel
{
    Error,
    Warning,
    Info
}
/// <summary>
/// </summary>
public class TLValidationMessage
{

    /// <summary>
    /// Message to show the user
    /// </summary>
    public string Message { get; set; }

    /// <summary>
    /// This helps change the styling, based on the severity level.
    /// </summary>
    public SeverityLevel Level { get; set; }
}

 

Next we’ll create a little helper method on the ViewModel that will add new messages to our collection:

/// <summary>
/// Adds a validation message to the bottom of the UI, with the appropriate styling.
/// </summary>
/// <param name="level"></param>
/// <param name="message"></param>
public void AddValidationMessage(SeverityLevel level, string message)
{
    if (ValidationMessages == null) ValidationMessages = new ObservableCollection<TLValidationMessage>();

    ValidationMessages.Add(new TLValidationMessage
                               {
                                   Level = level,
                                   Message = message
                               });
    NotifyPropertyChanged("ValidationMessages");
}

Now we’ll need to call this helper method anywhere a validation error occurs (typically in other methods in the ViewModel itself.

if (someitem.SomeCollection == null)
{
    AddValidationMessage(SeverityLevel.Error, "There are no items.");
    return;
}

Turning our attention to the xaml, we’ll add an ItemsControl inside a Border, which will display the messages:

<Border x:Name="Validation" Grid.Column="0" BorderThickness="1" Grid.Row="3" Grid.ColumnSpan="2" HorizontalAlignment="Center">
    <ItemsControl ItemsSource="{Binding ValidationMessages, Mode=OneWay}" BorderBrush="{x:Null}" ItemTemplate="{StaticResource ValidationMessageTemplate}" Foreground="#FFFF0202"/>
</Border>

You may have noticed the template was set to ItemTemplate="{StaticResource ValidationMessageTemplate}"  Here is the DataTemplate to control the display.

<DataTemplate x:Key="ValidationMessageTemplate">
    <Grid>
        <StackPanel Orientation="Horizontal" d:LayoutOverrides="Height">
            <TextBlock Text="{Binding Message}"/>
        </StackPanel>
    </Grid>
</DataTemplate>

As long as you’ve set the DataContext of the parent control, and your binding lines up, this will display the Validation Messages as they occur.

Hope this helps!

// Dave