Dynamics CRM Add-ons and Extras

Following is my “short” list of Dynamics CRM Add-ons and Extras.

Category

Product/Add-on

Notes

Advanced/GUI Workflows

Business Process Management
by QGate

  

  

TK Process Builder
by TK

  

  

Intelligent Workflows for Microsoft Dynamics CRM
by PNM Soft

  

Custom Workflow Activities Libraries

eWorkflow 2011
by My CRM

  

  

  

  

  

  

  

Custom, COTS and Platform Development

Approaches to Line of Business Application Solution Development

Whether you are looking to write a brand new line of business (LOB) application, consolidate multiple existing LOB applications onto a standard platform, or modernize a 15 year-old legacy mainframe application, there are several approaches to consider in today’s marketplace.

 

Custom Development

Historically, and likely the way that your existing applications were created is via custom development to your exact specifications. However, custom development has shown to have some significant disadvantages:

  • Significant re-investment in the common “plumbing” services for each and every application
  • Lack of UI standardization and usability resulting in increased training costs and lower user adoption
  • Most organizations struggle to correctly and completely define the requirements resulting in inadequate and incomplete solution
  • You get ONLY what you ask for. EVERYTHING else becomes an extra cost and effort.
  • Stuck in the perpetual “technology refresh” cycle. (Technology already out-of-dated before even going to production.)
  • Lack of modern standards support (UI, integrations, services, etc.)
  • Lack of budget and resources to support today’s needs around Cloud, Mobility, Social Computing and Big Data.

 

COTS and SaaS

As a result of the challenges and cost of custom developed solutions, there has been a significant swing to ready-made, pre-built, applications usually referred to as Commercial of the Shelf (COTS) software.

In their Market Trends paper: “Application Services Shifting to Information- and Asset-Based Business Solutions” (1), Gartner documents very clearly the market shift from custom application services to COTS and Software-as-a-Service (SaaS) approaches. Some key drivers for this shift are:

  • Business managers are driving application decisions with preference toward packages and SaaS solutions
  • Demand for COTS and SaaS solutions now exceeds the demand for custom developed solutions.
  • The Nexus of Forces (3) (Cloud, Mobility, Social Computing and Big Data) is permeating virtually all application implementations
  • IT organization roles are shifting to managing technology, architecture and vendors
  • Shift in service portfolios to more architectural and information-centric and implemented through a series of small projects

While this trend towards COTS and SaaS solutions is seen across all domains, it is especially amplified within the Public Sector. In “Market Trends: Government Vertical-Specific Software” (2), Gartner discusses the ever increasing trend within the government at all levels towards more COTS and SaaS solutions targeted towards specific Public Sector missions like administration and finance; health and human services; public safety and criminal justice; and transportation and public works.

Unfortunately, COTS and SaaS have their own shortcomings.

A significant challenge encountered with COTS solutions is that they represent the vendor’s understanding and interpretation of the business needs in the particular vertical domain that the COTS application is targeting. Additionally, many COTS applications have minimal capacity for the individualization of their offering to your specific business needs. When we consider the Pareto Principle (Also known as the “80/20” rule), it can be applied to assert that the COTS application will only meet 80% of your needs out-of-the-box. But, what about the other “20%”?

clip_image002

Custom Development vs. COTS

Thus, when we compare custom development versus COTS software solutions, they can be summarized as:
Custom Development Exactly what you want, but costly with limited lifetime
COTS Pre-Built and vertical-ized, but exactly what they want

The common response to these two choices is that it seems like we are stuck between a choice of two extremes. On the one hand, you don’t have enough time and money to continue with custom development for all your LOB applications. Yet, on the other hand, you may need more flexibility and functionality than what a vertical specific COTS solution offers you.

Thankfully, there is third approach to line of business solution development: That of the Platform Development approach.

 

Platform Development

If the “80/20” rule for COTS applications implies that the COTS or SaaS solution will meet “80%” of your needs out-of-the-box, this is a great thing! But what about the other “20%”? Are you forced back into a partial custom development approach? Do you just “do without”?

Enter the realm of Platform Development.

With a LOB Platform development environment, like that of the Microsoft Dynamics xRM platform, you get the best of COTS and SaaS (the “80%”), the ability to leverage domain and vertical solutions, coupled with an extensibility framework that allows you to safely create the individualized “20%” that is specific to your particular business and mission requirements. Thus, we gain the efficiencies and economies of COTS + pre-built vertical solutions + individualization for specific line of business needs.

clip_image004

By adopting a Platform-based approach to LOB application development, modernization, and consolidation, we gain some very specific benefits:

  • Cost Reductions, and Avoidance
    • Common plumbing provided by the platform. No need to ‘recreate the wheel’
      • Database management
      • Security model
      • Web service enablement
      • Cloud enablement
      • Mobility enablement
      • Analytics enablement
    • Increased user adoption due to standardized user interfaces and user experiences
    • The ability to support multiple discrete LOB applications on a single deployed platform via multi-tenant architectures
  • Shorter time to value, Increased productivity
    • Common Platform features and functionality operational out-of-the-box
    • Domain accelerators providing the generalized domain and mission specific functionality out-of-the-box
    • Scalable to meet the most demanding business environments
  • Increased flexibility
    • Native extensibility to safely create both domain accelerators and specific business solutions
    • Point-and-Click dynamic configuration tailored to specific business and mission needs

 

Dynamics CRM Platform Examples

Following are just a few examples of Public Sector agencies that have successfully adopted an agency-wide application of Dynamics CRM as a platform development environment.

Commonwealth of Virginia

http://bit.ly/1zkH4z7

http://bit.ly/1wKLL0U

 

Built unique business solutions on a single Dynamics CRM platform to support multiple agencies across the state:

  • Department of Historic Resources
  • State Board of Elections
  • Department of Behavioral Health and Developmental Services
  • Virginia information Technology Agency
  • Secretary of the Commonwealth
  • Governor’s Office
Pennsylvania County Commissioners

http://bit.ly/107Rdjd

 

Using Microsoft Dynamics CRM as a platform, developed rich flexible applications for:

  • Functionality for Each Department
  • Reporting and Dashboards
  • Streamlined Flow of Information
  • Flexible Deployment Model
  • Improved Public Safety
  • More Efficient Processes
  • Better Insight across all agencies
United States Department of Homeland Security

http://bit.ly/1DCPnnE

 

In support of multiple Department of Homeland Security (DHS)-wide initiatives, a cloud-based software as a service (SaaS) solution is being deployed using the Microsoft Dynamics CRM platform. This SaaS offering deploys and scales business operations such as records management, scheduling, reporting, tracking campaigns, mission and workforce activities, and budgets. Within the DHS, Microsoft Dynamics CRM is used by the Transportation Security Administration, Federal Emergency Management Agency, Customs and Border Protection, Immigration and Customs Enforcement, and U.S. Coast Guard.
United States Veterans Administration

http://bit.ly/1DCPnnE

 

The U.S. Department of Veterans Affairs (VA) transformed the Veterans Benefits Administration National Call Centers and its Pension Call Center by using Microsoft Dynamics CRM. Through the VA’s Veterans Relationship Management (VRM) initiative, the VA used Microsoft Dynamics CRM to integrate access to 13 different databases, which previously had to be individually queried and are now viewed simultaneously. This not only makes the call agents’ jobs easier, enabling them to recall veteran information more quickly, it also gives veterans timely access to healthcare, claims status and business information. “Microsoft Dynamics has helped VRM provide a platform to help millions of veterans and their families each year,” said Maureen Ellenberger, director of VRM. “To date, over 1 million calls have been better supported using CRM. We are already planning expanded deployments to other VA call centers.” In addition, the Federal Case Management Tool (FCMT), also built on Microsoft Dynamics CRM, is greatly supporting wounded warriors as they transition into VA care. The modernization of the VRM and FCMT programs has enabled the VA to strengthen its services to veterans.

Summary (A Hybrid Approach)

As with most things in life, reality lies somewhere towards the middle. Even with rich platforms like Dynamics, it is still inevitable to come across niche situations where you must still write custom code. Fortunately, with the adoption of a platform development model and technology stack, both the quantity and complexity of the remaining custom development need will be greatly diminished.

By adopting a platform development solution like Dynamics and leveraging COTS-like domain specific accelerators and solutions you can effectively achieve the proverbial “80%” of your business needs out-of-the-box. Additionally, the platform enables advanced functionality around Cloud, Mobility, Social, and Big Data that you may not have been able to provide at all without the platform’s assistance.

For the remaining “20%”, the platform’s native extensibility framework provides you with an industry standard and safe mechanism to individualize and tailor both the platform and domain solutions to meet your very specific business and mission needs; ultimately reducing your costs, increasing your productivity, and serving your customers and constituency more efficiently.

 

References

1. http://my.gartner.com/portal/server.pt?open=512&objID=260&mode=2&PageID=3460702&resId=2075615&ref=QuickSearch&sthkw=g00231826
2. http://my.gartner.com/portal/server.pt?open=512&objID=260&mode=2&PageID=3460702&resId=2060115&ref=QuickSearch&sthkw=g00231251
3. http://www.gartner.com/technology/research/nexus-of-forces/

Dynamics CRM Version Matrix

 

Unfortunately, it can be quite difficult to figure out which Rollup version of CRM you are using as CRM only reports its actual build number and not its “name”.

The below matrix provides a mapping of the version numbers to the Rollup names. Note that this is only a listing of the major Rollups.  Hotfixes and special updates will have build numbers that are different than those shown here.
 

Version 2011 Family

Version

Build Number

Released on

RTM/RTW

05.00.9688.583

1/19/2011
Rollup 1 05.00.9688.1045 4/4/2011
Rollup 2 05.00.9688.1155 6/6/2011
Rollup 3 05.00.9688.1244 7/26/2011
Rollup 4 05.00.9688.1450 9/19/2011
Rollup 5 05.00.9688.1533 10/20/2011
Rollup 6 05.00.9690.1992 1/20/2012
Rollup 7 05.00.9690.2165 3/23/2012
Rollup 8 05.00.9690.2243 5/3/2012
Rollup 9 Update Rollup 9 will not be released because of a delay in the Q2 Service Update. Update Rollup 10 fixes all the issues that would have been included in Update Rollup 9. More information is here.  
Rollup 10 05.00.9690.2730 8/16/2012
Rollup 11 05.00.9690.2835 10/22/2012
Rollup 12 05.00.9690.3233 1/29/2013
Rollup 13 05.00.9690.3448 3/26/2013
Rollup 14 05.00.9690.3557 7/11/2013
CRM 2013 (Orion) Coming Soon!!! Fall 2013

 
Note that Microsoft will be expiring older versions of the Rollups from Microsoft Update. Note that they will all still remain available from the Microsoft Download site which all the links here point to.  More details are here.
 
 

Version 4.0 Family

Version

Build Number

Released on

RTM

4.0.7333.3

12/19/2007

Rollup 1

4.0.7333.1113

11/24/2008

Rollup 2

4.0.7333.1312, 4.0.7333.1316

1/15/2009, 2/8/2009

Rollup 3

4.0.7333.1408

3/12/2009

Rollup 4

4.0.7333.1551

5/7/2009

Rollup 5

4.0.7333.1644, 4.0.7333.1645

7/2/2009

Rollup 6

4.0.7333.1750

9/27/2009

Rollup 7

4.0.7333.2138

10/22/2009

Rollup 8

4.0.7333.2542

12/17/2009

Rollup 9

4.0.7333.2644

02/11/2010

Rollup 10

4.0.7333.2741

04/08/2010

Rollup 11

4.0.7333.2862

06/03/2010

Rollup 12

4.0.7333.2935

08/02/2010

Rollup 13 4.0.7333.3018 10/06/2010
Rollup 14 4.0.7333.3135 11/16/2010
Rollup 15

4.0.7333.3231

1/10/2011
Rollup 16

4.0.7333.3335

3/9/2011

Rollup 17 4.00.7333.3414 5/2/2011
Rollup 18 4.00.7333.3531 6/28/2011
Rollup 19 4.00.7333.3628 8/21/2011
Rollup 20 4.00.7333.3732 11/10/2011
Rollup 21 04.00.7333.3822 2/7/2012
 

 

 

If you know of something new or different, please leave a comment and let me know and I’ll update the matrix asap.

 

Robert
– One is pleased to be of service

 

Technorati Tags: ,

Windows 8 Enterprise–Day 1

 

For those of us lucky enough to have a MSDN or TechNet Subscription, Microsoft released Windows 8 RTM today!

So, like many, I’ve been multi-tasking to get it downloaded and installed.

I am actually writing this blog using the new Windows Essentials 2012 on Windows 8 on my Slate Tablet.

As I use my tablet as my primary computer, I’m not quite ready to just jump in and wipe it out, so I did another WindowsToGo USB installation.

See my blog for information on how to setup a WindowsToGo USB install.

I’m using an ASUS EEE EP121 Slate with 4GB RAM. My USB drive is actually the original 64GB SSD drive that came with my EP121. I recently upgraded my internal SSD to 128GB.

Being a Dynamics CRM guy, the first test I had to do was log into a couple CRM Organizations in both the Win8 UX browser and desktop browser.

LOOKS GREAT, RUNS FAST.

I will take some screen captures and write up some more specific information around Dynamics CRM and Windows 8 over the next days.

Here are my first impressions thus far on day 1:

Positives Negatives
The Win8 Mail app now supports IMAP! YEAH!!! The App Store is not supported from WindowsToGo. While I understand the logic that this would normally be used for a hardened corporate IT OS, that will not always be the case and it should really be a switch that can be set!
IE gives a nice “Private Network Access” warning and prompt when you attempt to connect to a network domain. I have not been able to get Windows Activation to work at all. Keeps throwing an error.
I use 2 monitors (the Slate’s, and an external).

You can have different wallpaper on each monitor now! very cool.

Can not do a Manual Activation because the slui 4 UI where you pick your country, is stuck on Afghanistan and you can not change it!

I do have a suspicion that this MAY also be related to WindowsToGo, but I can not confirm either way.

Windows 8 is SCREAMING FAST on my hardware I needed to download multiple files from SkyDrive to local drive. When you select multiple files in SkyDrive, the Download sprite is removed.  I had to download the files individually. Luckily there where only 8 files, but this was a shocker!
IE 10 is SCREAMING FAST on my hardware At one point, everything that required my live id stopped working (music, Xbox, SkyDrive, etc.) Not sure why.

I had to reboot after Windows Update finished with a round of updates, and it all started working again after the reboot. Weird for sure.

When picking a login picture, you can now select a picture directly from SkyDrive. I have been unable to get the legacy Zune software to install. Keeps wanting to install .NET 3.5, which fails because .NET 4.0 is already installed.  So apparently, Zune installer can’t see what version, if any, of .NET is installed.
Major ouch is that my companies VPN software will not install!!! Sad smile

It has a similar error. The installer can not see that .NET is installed, so it won’t install either.

Of course, our IT has no ETA for when they will have an update.

Unfortunately, this might be the biggest party pooper that prevents me from upgrading Sad smile

  I’m one of the 6 people in the world that liked the Aero transparency effect.  I will miss Aero. A moment of silence please…

 

Of course, we will need more and more Win8 UX style apps over time, but I understand there is a great selection already in the App Store (that I can not see while running WindowsToGo)

Regardless of all the above issues, I LOVE Windows 8 a lot, especially when I’m using my Slate in touch mode.

Using the Desktop and the new Start simultaneously and back-n-forth when I’m using it in a more traditional “desktop” configuration takes a little getting used to, but much of that is just the re-programming of my old brain to know where to go for what I want to do.

I am in the camp that touch will become ubiquitous and thus a huge fan of the “touch first” design principle. I’m sure my muscle memory will catch up with the rest of me once I can spend more daily time in Win8.

Now, if I could just get my new Win Phone 8 soon too…..

 

Robert
– It is an honor to be of service

 

Technorati Tags:

Windows 8 “to go” on ASUS EP121: Best of both worlds without having to buy a 2nd Tablet!

 

I’ve been playing with both of the Windows 8 previews as they have come out on an ancient HP Pavilion tx2000 flip-top tablet. The bad news is, the tx2000’s pressure touch-screen is just not sensitive enough for a nice finger-touch experience.  The, quite frankly, good and surprising news was that Windows 8 even ran on the tx2000, which it did very well actually. Kudos to Microsoft!

But, I really wanted to play with a more modern tablet, like my ASUS EP121. But, I use my EP121 as my primary computing device, so I could not really sacrifice it for “playing” with the preview releases yet.

I knew that Windows 8 supported booting from a USB device, but my first attempt was not successful, primarily because I “failed to read the manual” Smile

But, I was re-motivated again after watching the Windows-to-Go demo at WPC last week, so wanted to get this working and carved out some time. The good news is that it takes less than an hour to create a Windows 8 Windows-to-go USB boot device !

If you’re wanting to do similar, I would suggest following the instructions located here:

http://pureinfotech.com/2011/09/28/how-to-create-a-windows-to-go-usb-drive-in-windows-8-step-by-step/

They were the most succinct steps I found and worked perfectly (except for small change to step 12: See the comments on the same page)

I installed the Windows 8 image on my old 64GB SSD from my ASUS EP121 which was left over after upgrading my EP121 to a 128GB SSD last month.  I put the SSD into a USB drive housing which gave me a very nice, very fast USB drive. And like I said, It look less than an hour.

Additionally, I installed the Office 2013 Preview onto both my primary Windows 7 drive, and on my new cool Windows 8 USB drive! But that’s another blog all by itself. (I live it by-the-way)

If you want to, or even need to, have a handy Windows 8 environment around, but can’t afford to buy a dedicated tablet, the Windows-to-go approach may be a great alternative for you also! Just plug in the USB drive and re-boot.

 

Robert
– It is an honor to be of service

WordPress Tags: office 2013,usb drive,windows to go,windows-to-go,Windows 8,ASUS,tablet

CRM 2011 Developer Toolkit Solution “Forgets” it’s a CRM Solution

 

A funny thing happened to me yesterday on my way to trying to actually get some work done…

I frequently will open a Dynamics CRM Developer Toolkit solution in Visual Studio when I’m disconnected from the actual Dynamics CRM server.  Visual Studio will kindly let me know that it can’t find CRM, I tell it, “yep, I know”, and it continues to load the solution without any problems. Once I’m ready to actually connect to CRM, a quick selection of the Tools | ”Connect to Dynamics CRM Server…” menu item and I’m on my way.

Except yesterday when Mr. Murphy was visiting for the day…

This time, all went as normal, except that when I went to connect to CRM, the Tools | ”Connect to Dynamics CRM Server…” menu item was missing!

And of course, I was in a hurry!

Well, after doing some digging, and comparing to other CRM 2011 Developer Toolkit solutions, I found the problem:  The .sln file was missing a section!

If you ever encounter this problem, the fix is VERY easy.

Open your .sln file for the CRM 2011 Developer Toolkit solution, locate the “Global” section, and make sure that the first entry is as follows:

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

   1: Global

   2:     GlobalSection(CRMSolutionProperties) = preSolution

   3:         SolutionIsBoundToCRM = True

   4:     EndGlobalSection

   5:     ...

   6: EndGlobal

 

A complete empty CRM .sln file follows with the key GlobalSection highlighted that MUST be present for Visual Studio to know that it is a CRM solution.

   1: Microsoft Visual Studio Solution File, Format Version 11.00   

   2: # Visual Studio 2010   

   3: Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmPackage", "CrmVSSolution1\CrmPackage\CrmPackage.csproj", "{9AA6A940-7773-4376-B972-383C7EB001C8}"   

   4:     ProjectSection(ProjectDependencies) = postProject   

   5:         {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760} = {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}   

   6:         {388B3993-ECAB-4A3A-B925-D6039DEC872F} = {388B3993-ECAB-4A3A-B925-D6039DEC872F}   

   7:     EndProjectSection   

   8: EndProject   

   9: Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plugins", "CrmVSSolution1\Plugins\Plugins.csproj", "{D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}"  

  10: EndProject  

  11: Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workflow", "CrmVSSolution1\Workflow\Workflow.csproj", "{388B3993-ECAB-4A3A-B925-D6039DEC872F}"  

  12: EndProject  

  13: Global  

  14:     GlobalSection(CRMSolutionProperties) = preSolution  

  15:         SolutionIsBoundToCRM = True  

  16:     EndGlobalSection  

  17:     GlobalSection(SolutionConfigurationPlatforms) = preSolution  

  18:         Debug|Any CPU = Debug|Any CPU  

  19:         Release|Any CPU = Release|Any CPU  

  20:     EndGlobalSection  

  21:     GlobalSection(ProjectConfigurationPlatforms) = postSolution  

  22:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU  

  23:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.Build.0 = Debug|Any CPU  

  24:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU  

  25:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.ActiveCfg = Release|Any CPU  

  26:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.Build.0 = Release|Any CPU  

  27:         {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.Deploy.0 = Release|Any CPU  

  28:         {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Debug|Any CPU.ActiveCfg = Debug|Any CPU  

  29:         {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Debug|Any CPU.Build.0 = Debug|Any CPU  

  30:         {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Release|Any CPU.ActiveCfg = Release|Any CPU  

  31:         {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Release|Any CPU.Build.0 = Release|Any CPU  

  32:         {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU  

  33:         {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Debug|Any CPU.Build.0 = Debug|Any CPU  

  34:         {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Release|Any CPU.ActiveCfg = Release|Any CPU  

  35:         {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Release|Any CPU.Build.0 = Release|Any CPU  

  36:     EndGlobalSection  

  37:     GlobalSection(SolutionProperties) = preSolution  

  38:         HideSolutionNode = FALSE  

  39:     EndGlobalSection  

  40: EndGlobal

 

Robert
– It is an honor to be of service

Technorati Tags: ,,,,,,,,CRM

Blogger Labels: Developer,Toolkit,Solution,Dynamics,Visual Studio,Tools,CRM Solution Properties,Project,CRM Package

Anonymous, Type-less, 100% Generic and Abstracted Logging and Tracing

 

The Challenge

Over the years I have used various mechanisms to de-couple logging and tracing specifics from the code that needs to send a message up.

Certainly, at the macro level, there are whole frameworks for this: Such as Enterprise Library, Log4N, etc.  But, these don’t really solve the problem when you get down to the micro-level, especially if you are developing libraries like Domain Specific Languages (DSL), Helper Libraries, and any other code that should be totally generic and not know anything about the higher level context that it is running within. Does my DSL Extension method really have know if it’s being used with EntLib or Log4N or whatever? The goal is certainly that it would know NOTHING and be completely transportable between such macro frameworks.

Note: For a discussion of the use of DSLs versus Helper Libraries, see my forthcoming blog: Death to Helper Libraries!!!

There are some patterns that attempt to deal with this level of abstraction. One of the most popular is the Inversion of Control (IOC) pattern, which I have certainly used extensively in the past, but this can still be way too heavy for there situation where all we need is for an Extension or Helper Method to be able to provide trace level messages to the higher level context.

Another common approach, and frankly the one I’ve used the most at this level in the past, is an event-ing mechanism where the Helper class, or other utility class advertises an Event (e.g. myClass.OnTraceMessage) that the higher level code can bind to, receive the events, and write to the then known tracing and logging mechanism.

Unfortunately, there is a fair amount of overhead code required by the class that will be firing the Events: local variable to track all the event listeners, methods to track listeners, methods to fire the Event.  YUK! Certainly, you can start to hide the complexity with another layer of abstraction, but now we’re just moving the problem around and sweeping it under the rug.

Over the last few years, .NET has released new interfaces that standardized concepts like IObservable and IObserver. And if you want the whole thing to be Asynchronous, you have the new .NET Reactive Extensions (Rx) library.  But, again, these are all fairly heavy weight, especially at the lowest level of code like we are discussing.

There just HAS to be a way, at the lowest micro-level of code to be able to provide tracing and logging information to the higher-level caller, but without having to write more abstraction layers, more controllers, and more marshal-ing agents!

So, recently, while writing a some DSL libraries to connect Dynamics CRM to a customer’s enterprise Line of Business systems or Service Bus, I took the opportunity to ponder on this problem with a fresh perspective.

Pondering….

Being a big fan of Linq, which includes becoming familiar with Lambda expressions, and recalling .NET’s support for Delegates and Anonymous declarations and expressions, including functions…A VERY simple and VERY Elegant approach to this problem occurred to me, and turned out to be trivial to refactor into the DSL libraries.

Solution Approach

How to define a “Function Variable” [Delegate]

First, let’s think about what it means to have a 100% abstracted, generic approach to writing a log message. Basically, it’s like saying, “I just want to be able to call ANY function that takes a single string parameter (The trace/log message) and returns ‘void’. I don’t want to have to know what Assembly that function lives in. I don’t want to have to reference that assembly. I don’t want to have to “using” its namespace. I especially do NOT want to have to include any additional assemblies with my distribution!!!!  I want to live in complete and total ignorance and isolation.  Just point me to a similar to the following:


public void logger( string msg ){...}

 

Seems like a tall order to fill, but it’s actually very simple when we think about it this way.

.NET provides several mechanisms for defining an expected function like this. They’re called Delegates, and there are various forms to choose from:

On the simplistic explanation side, Func delegates require a return type while Action delegates return ‘void’.

In our case, we want the equivalent of ‘void’ functions, so let’s use the Action delegate.

This now lets us define exactly what we described:

“Give me ANY function that takes a single string parameter and returns ‘void’”

And in c#, that looks just like this:

public void MyDoItFunction( Action<string> logger ) {...}

This says, when you call MyDoItFunction, you have to pass it a Function or Delegate that takes a single string parameter. MyDoItFunction will call it with logging and tracing messages, and you do whatever you want with them. MyDoItFunction does not want to know where or how those messages ultimate end up going.

Inside of MyDoItFunction, It just sends out tracing messages as it see fits by calling the passed in Action Delegate like this:


public void MyDoItFunction( Action<string> logger )
{
logger("Setting up the string builders...");
...
}

As we now see, it becomes very easy to require a caller to pass in a 100% abstracted, generic function that we can write our trace messages to. This could be done in function signatures like our examples, or also constructors, properties, etc. Basically, anywhere that you could/would define and pass a variable, you can define and pass a function delegate.  This is VERY COOL!

If you’ve used Events, IObservable, IObserver, Inversion of Control, or any other approach, you will quickly see the immense simplicity of this approach.

How to pass in the Delegate

So far, so good.  Now that I can define a function delegate property that I can log my trace messages to, how does the caller of MyDoItFunction pass in a delegate?

As you can read in the MSDN Documentation for Action, There are several approaches for how to create and pass in a Delegate:

  • Explicit define a delegate over pre-defined function declaration
  • Explicit Action declaration
  • delegate using Anonymous methods
  • Lambda expressions

To me, the most interesting approaches are the last two: Anonymous methods and Lambda expressions. And of those two, my favorite is Lambda expressions.  I will leave you to read about the first two on your own.

Now, let’s look at a couple examples of calling our MyDoItFunction function and passing in widely varying actual output writing targets:

   1: //all examples use Lambda expressions

   2:  

   3: //Write all messages to the built in .NET Tracing

   4: MyDoItFunction( msg => System.Diagnostics.Trace.Writeline( msg ) );

   5:  

   6: //Write to Console

   7: MyDoItFunction( msg => Console.Writeline( msg ) );

   8:  

   9: //Writes to method in the consuming class

  10: MyDoItFunction( msg => this.MyTracer( msg ) );

Yet again, we have an immensely simplistic solution. Note that there are no registrations for Events, IObservers, etc. Once again, THAT’s COOL!

What’ does that have to do with Dynamics CRM again?

Recall that we are writing a DSL (Domain Specific Language) that exposes the customer’s legacy enterprise LOB applications and services to Dynamics CRM plugins and Workflows. One of the most flexible and efficient mechanisms for implementing DSLs is the use of .NET extensions methods.  If you’ve used Linq, then you’ve used Extension Methods. Simply put, Extensions Methods allow you to extend other objects with additional behavior (functions) without having to modify the original source code. That’s what allows Linq to add all those functions to all those objects.

Bringing it all together, we can take the concept of defining and passing in function delegates plus the use of Extension Methods, and we can not very trivially provide a mechanism for consumers of our DSL to provide delegates to their own logging mechanism.

Specifically, when we’re talking about custom .NET Plugin and Workflow code in the Dynamics world, Dynamics CRM introduces it’s own tracing mechanism (ITracingService) that is provided within the Plugin and Workflow IServiceProvider.

Let’s look at a DSL’s extension method that can write Dynamics CRM Entity data to an Enterprise’s LOB application’s web service:

   1: /// 

   2: /// Sends updated contact person information to the ESB.

   3: /// 

   4: /// The contact as a late-bound CRM Entity.

   5: /// A function that takes a string parameter that will receive tracing/logging messages.

   6: public static void ESBUpdatePerson(this Entity contactEntity, Action<string> logger)

   7: {

   8:     logger("ESBUpdatePerson(Entity contactEntity) called...");

   9:     logger("Ensuring that Entity.LogicalName == contact...");

  10:  

  11:     //ensure that contactEntity is a contact

  12:     if ( contactEntity.LogicalName.ToLower() != "contact" )

  13:     {

  14:         throw new InvalidPluginExecutionException(OperationStatus.Failed, string.Format("ESBUpdatePerson(this Entity contactEntity) was passed invalid Entity of '{0}' expected a 'contact'", contactEntity.LogicalName));

  15:     }

  16:     

  17:     ...

  18: }

And, a sample Plugin Execute() method that consumes ESBUpdatePerson():

   1: public void Execute(IServiceProvider serviceProvider)

   2: {

   3:    //get the tracing log out of the context

   4:    var tracer = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

   5:  

   6:    //get the plugin execution context

   7:    var pluginExecutionContext = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

   8:  

   9:    //get the actual entity out of the context

  10:    var pluginEntity = (Microsoft.Xrm.Sdk.Entity)pluginExecutionContext.InputParameters["Target"];

  11:  

  12:    //send the Entity to the ESB, 

  13:    //providing the CRM tracer for capturing trace messages

  14:    pluginEntity.ESBUpdatePerson(msg => tracer.Trace(msg));

  15:  

  16: }

 

Summary

We have talked about the historic approaches taken (Events, IObservable, IObserver, RX library, Inversion of Control, etc.) to accomplish 100% abstracted access to logging and tracing mechanisms and frameworks from lower level code, and our desire to be able to support ANY logging and tracing implementation without having to know anything about them, and especially without having to be couples to them and have to include their distributable with our own!

We then looked at function delegates and explicit examples of using the Action delegate that demonstrated the immense simplicity and flexibility of the approach of using Delegates.

And finally, we brought it back to Dynamics CRM and demonstrated how we could write a DSL using Extension Methods that could take in a Action delegate for providing detailed tracing messages and information, and how we could use the DSL from a plugin and provide CRM’s own internal tracing mechanism to the DSL methods.

I hope you’ve seen the immense simplicity and flexibility of using delegates as a function abstraction for being able to support most any logging and tracing mechanism without having to know anything about them!

Robert
– It is an honor to be of service

 

WordPress Tags: Enterprise Library,Domain Specific Language,EntLib,DSL,Inversion of Control,IOC,IObservable,IObserver,Reactive Extensions,Linq,Lambda,Delegate,Action,Func,Workflows,Plugin,ITracingService,IServiceProvider,IPluginExecutionContext

Blogger Labels: Enterprise Library,Domain Specific Language,EntLib,DSL,Inversion of Control,IOC,IObservable,IObserver,Reactive Extensions,Linq,Lambda,Delegate,Action,Func,Workflows,Plugin,ITracingService,IServiceProvider,IPluginExecutionContext

CRM 2011 Developer Toolkit Solution “Forgets” it’s a CRM Solution

 

A funny thing happened to me yesterday on my way to trying to actually get some work done…

I frequently will open a Dynamics CRM Developer Toolkit solution in Visual Studio when I’m disconnected from the actual Dynamics CRM server.  Visual Studio will kindly let me know that it can’t find CRM, I tell it, “yep, I know”, and it continues to load the solution without any problems. Once I’m ready to actually connect to CRM, a quick selection of the Tools | ”Connect to Dynamics CRM Server…” menu item and I’m on my way.

Except yesterday when Mr. Murphy was visiting for the day…

This time, all went as normal, except that when I went to connect to CRM, the Tools | ”Connect to Dynamics CRM Server…” menu item was missing!

And of course, I was in a hurry!

Well, after doing some digging, and comparing to other CRM 2011 Developer Toolkit solutions, I found the problem:  The .sln file was missing a section!

If you ever encounter this problem, the fix is VERY easy.

Open your .sln file for the CRM 2011 Developer Toolkit solution, locate the “Global” section, and make sure that the first entry is as follows:

Global
GlobalSection(CRMSolutionProperties) = preSolution
SolutionIsBoundToCRM = True
EndGlobalSection

...
EndGlobal

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

A complete empty CRM .sln file follows with the key GlobalSection highlighted that MUST be present for Visual Studio to know that it is a CRM solution.

   1:  Microsoft Visual Studio Solution File, Format Version 11.00
   2:  # Visual Studio 2010
   3:  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CrmPackage", "CrmVSSolution1\CrmPackage\CrmPackage.csproj", "{9AA6A940-7773-4376-B972-383C7EB001C8}"
   4:      ProjectSection(ProjectDependencies) = postProject
   5:          {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760} = {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}
   6:          {388B3993-ECAB-4A3A-B925-D6039DEC872F} = {388B3993-ECAB-4A3A-B925-D6039DEC872F}
   7:      EndProjectSection
   8:  EndProject
   9:  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plugins", "CrmVSSolution1\Plugins\Plugins.csproj", "{D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}"
  10:  EndProject
  11:  Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Workflow", "CrmVSSolution1\Workflow\Workflow.csproj", "{388B3993-ECAB-4A3A-B925-D6039DEC872F}"
  12:  EndProject
  13:  Global
  14:      GlobalSection(CRMSolutionProperties) = preSolution
  15:          SolutionIsBoundToCRM = True
  16:      EndGlobalSection
  17:      GlobalSection(SolutionConfigurationPlatforms) = preSolution
  18:          Debug|Any CPU = Debug|Any CPU
  19:          Release|Any CPU = Release|Any CPU
  20:      EndGlobalSection
  21:      GlobalSection(ProjectConfigurationPlatforms) = postSolution
  22:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  23:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
  24:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
  25:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
  26:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.Build.0 = Release|Any CPU
  27:          {9AA6A940-7773-4376-B972-383C7EB001C8}.Release|Any CPU.Deploy.0 = Release|Any CPU
  28:          {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  29:          {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Debug|Any CPU.Build.0 = Debug|Any CPU
  30:          {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Release|Any CPU.ActiveCfg = Release|Any CPU
  31:          {D6B86A2F-B4E4-44B8-8C7C-81B4C07BB760}.Release|Any CPU.Build.0 = Release|Any CPU
  32:          {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
  33:          {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Debug|Any CPU.Build.0 = Debug|Any CPU
  34:          {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Release|Any CPU.ActiveCfg = Release|Any CPU
  35:          {388B3993-ECAB-4A3A-B925-D6039DEC872F}.Release|Any CPU.Build.0 = Release|Any CPU
  36:      EndGlobalSection
  37:      GlobalSection(SolutionProperties) = preSolution
  38:          HideSolutionNode = FALSE
  39:      EndGlobalSection
  40:  EndGlobal

 

Robert
– It is an honor to be of service

 

Technorati Tags: ,,,,,,,,CRM

Blogger Labels: Developer,Toolkit,Solution,Dynamics,Visual Studio,Tools,CRM Solution Properties,Project,CRM Package