Saturday, March 19, 2016

Blog Series: Introduction to Dynamics CRM 2016 Web API

The release of the Microsoft Dynamics CRM Web API provides non-.Net developer types with true freedom to integrate CRM rich data sets into other platforms. This also provides CRM developers with the ability to create some great visuals within CRM as well when out-of-the-box grids and charts just won't do.  Since I also moonlight as an Angularjs and IonicFramework developer, I'm uber-excited about the possibilities that this provides.  Prior to the release of the Web API, developers had the SOAP based endpoint which was an authentication nightmare for those connecting from non .Net applications or the REST endpoint which was good but provided a very limited set of methods.

The Web API is ODATA 4.0 compliant which means that it adheres to and supports all and provides some awesome new features:
  • OAuth Support - OAuth is the authentication method supported for the Dynamics CRM Web API.  Because users in CRM Online and on-premise Internet Facing Deployments(IFD) are authenticated using Azure Active Directory Services, developers can leverage Azure Active Directory Authentication Library to authenticate to CRM from external applications. Before developers can use OAuth authentication to connect to CRM, the application must first be registered with Azure Active Directory.  Azure Active Directory is used to verify that your application is permitted to access the business data in CRM.  We'll go through a tutorial on how to build a SPA consuming the CRM Web API later in the series.
  • CORS Support - with the increase in popularity of Single-Page Applications(SPA) and javascript frameworks available to support building them, the need for Cross-Origin Resource Support(CORS) support is vital since most browsers restrict requests from other domains.
  • Predefined queries - support for executing saved system views and personal views.
  • Custom FetchXml  - since system and personal views really are just executing saved FetchXml, you can leverage that same principal and use custom FetchXml with your HTTP Get request.
  • Custom Actions and Functions - Those familiar with ASP.Net Web APIs will know the concept of Actions and Functions, if not you can read up on it here.  Essentially actions and functions are a way to encapsulate additional behaviors that are not captured in normal CRUD operations.  The difference between Actions and Functions is that Actions can have server-side effects, meaning data that other HTTP Requests can be performed besides HTTP Get. 
    • Query Functions - query functions are intended to further filter your HTTP GET requests.  Functions available are similar to those found in an Advanced Find filter criteria such as  Last X Months or Equals User or His Reporting Hierarchy.  For a complete list of functions available, check it out here.
    • Functions - The Dynamics CRM Web API has both bound and unbound functions.  In Web API terms, bound functions are those tied to a specific entity while unbound functions are not.  For a complete list of functions supported, click here.
    • Actions - Like Functions, actions For a complete list of actions supported, click here.  The true game changer here is that your custom actions that you create can also be called from Web APIs as well. 
  • Batch Operations - With batch operations, one can execute multiple requests in one transaction.  Use a POST request to submit a batch operation.  The POST request containing the batch must have a Content-Type header with a value set to multipart/mixed with a boundary set to include the identifier of the batch using this pattern. 
  • Optimistic Concurrency - check whether an entity has been modified since it was last retrieved before making changes.

Web API Limitations aka The Fine Print

Of there will be a few gotchas here.  
  • There are a few functions that are not supported found here 
  • Querying date values is a bit quirky - To query date values you can't use "eq" keyword, instead use one of the other supported CRM Web API Functions such as between, greater than, etc.
       Doesn' Work
    /contacts?$select=fullname,birthdate&$filter=birthdate eq 1990-01-01
        
       Works
     /contacts?$select=fullname,birthdate&$filter=Microsoft.Dynamics.CRM.Between(PropertyName='birthdate',PropertyValues=["1990-01-01","1990-01-01"])
    

  • One thing with the Web API is that there are several navigation properties that may not be supported.  One in particular that  I stumbled upon while developing is that retrieving navigation properties for collections is not supported.  For example if you wanted to retrieve the primary contact for a particular account, you can write it like this and works like a charm.
"GET [organization URI]/api/data/v8.0/accounts/primarycontactid?$select=fullname HTTP/1.1
Accept: application/json
OData-MaxVersion: 4.0
OData-Version: 4.0"
This will render the following error:
  {
  "error":{
    "code":"","message":"The request URI is not valid. Since the segment 'accounts' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.","innererror":{
      "message":"The request URI is not valid. Since the segment 'accounts' refers to a collection, this must be the last segment in the request URI or it must be followed by an function or action that can be bound to it otherwise all intermediate segments must refer to a single resource.","type":"Microsoft.OData.Core.ODataException","stacktrace":"   at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CheckSingleResult(Boolean isSingleResult, String identifier)\r\n   at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateNextSegment(String text)\r\n   at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection`1 segments)\r\n   at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection`1 segments, ODataUriParserConfiguration configuration)\r\n   at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize()\r\n   at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePath()\r\n   at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath, ODataUriResolverSetttings resolverSettings, Boolean enableUriTemplateParsing)\r\n   at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath)\r\n   at Microsoft.Crm.Extensibility.OData.CrmODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath)"
    }
  }
}

In this 5-part blog series, we will take a deep-dive into the Dynamics CRM Web API.

  • Part 1 - CRM Web API Fundamentals - Exploring the Dynamics CRM Web API
  • Part 2 - Building better visualizations with Dynamics CRM Web API with jQuery DataTables and Chart.js
  • Part 3 - Doing Stuff with the Dynamics CRM Web API using functions and custom actions
  • Part 4 - Authenticating CRM Users with Azure Active Directory Active Library 
  • Part 5 - Putting it all together - Building a SPA with Angular.js and Dynamics CRM Web API 
Get ready!


Tuesday, March 1, 2016

In the Bloginning aka Hello World

So here it is, my first blog.  I can't believe how long it took me to get here.  I think it's mostly out of self-doubt and fear.  I can go into a conference room full of strangers and talk about Office 365 or Dynamics CRM or SharePoint, Angularjs, but somehow writing that same knowledge down to share with millions of people(or worse nobody) is a really frightening thought.  Kinda feels a bit too permanent.  But on Feb. 29th, I decided to take the cliche "leap" and challenge myself to blog for 30 days.

I've always kinda hated this idea of "building your brand" through social media.  I've never been that good at bragging on myself or my expertise.  But after years of having people make assumptions about my knowledge and skillset based on nothing but my race, gender, and size, I figured maybe it's time to give people a few more data points.

So who am I?  Whenever someone asks me that question the first thing that I always say is I'm a Software Consultant,  I love to code and solve problems.  It's amazing that after 15+ years that answer hasn't changed, though lately I think maybe it should(but that's for another blog post).  Lately I've been thinking about those moments that really shaped me as a developer and consultant.  So how better to introduce myself to the world than to describe my top 5 developer moments.

5.  (2014) Teaching myself Angularjs and Ionic Framework

So when I first started my career, I built custom web apps using .Net and it was great.  I loved the challenge and freedom that coding provided. But after years of working in the custom dev world, I was thrust into 80/20 world of SharePoint and Dynamics CRM.  This meant I became less of a pure developer and more of a component builder.  During that time, maybe I got rusty, but learning Angularjs was THE hardest thing ever.  What normally took days to grasp, took months.  But I got it!!!

4.  (2007) Learning SharePoint

One of the greatest things that SharePoint provides is a huge community of people that share ideas and knowledge.  SharePoint put me in touch with some amazing people that I respect both professionally and personally. Not only has SharePoint help me become stronger technically, but I also became a lot more social.

3.  (2005) Meeting People that Code for "fun?"

So prior to joining Avanade in 2005, I liked coding and knew I wanted to make it my long-time career.  But I thought career, as in 9-5(maybe 9-7).  But I never had met people that lived, breathed, and ate code.  People that in their spare time used code to solve everyday problems at home.  This was huge, it pushed me to work harder, to craft and hone my skills.

2.  (2015) Not remembering the term Declarative Function

I was at a happy hour event with some fellow tech folks and as I do too often, I was amazing people with the fact that I was a female coder.  Someone who perhaps had too much to drink challenged me and said "Well if you can code, what's a Declarative Function?".  I froze, how could I not know that?  In that moment, I let down an entire race and gender.  I've worked hard my entire life to prove my skills and in one night it was completely ruined.  It took months to forgive myself for that miss.

1.  (2001) Getting my first Tech Lead Job

At the age of 24, I was asked to be the Operations Tech Lead for a major web application.  I had a team of 8 people reporting to me and we monitored the website 24/7.  I had people almost twice my age reporting to me.  I was responsible for 13 million dollars of revenue for my consulting company.  At the time, I didn't even know how huge that was and how much I was respected.  Still today, I have former colleagues that say how great I did.  I am always grateful for the man that trusted me enough to give me that chance. He saw how hard I worked and just rewarded me.  Sounds pretty simple, but in 15 years, I can say it's rare.

What's your top 5 dev moments?