The Coding Hero You Deserve, Not The One You Need

Posted by Sonoma Partners on June 26, 2012 in   |  Microsoft Dynamics CRM,   |  Microsoft Dynamics CRM 2011  |  commentsComments (1)

Today's guest blogger is Rob Swafford, a Senior Developer at Sonoma Partners

Hero
We recently ran into an unusual situation on a client project for which it took a fair bit of research to ultimately track down the correct fix.  This particular client utilizes a number of internal web services with which different business units interact.  Most of these web services are standard SOAP-compatible services with exposed WSDLs that .NET is able to consume without a problem.  One in particular - that happened to be central to this project - was queue-based, and expected a packet of plain old XML (POX) to be dumped in its queue bucket as the request payload.  My first thought on tackling this service was to build up a series of C# objects that mirror the XML structure the service expects, decorate them appropriately with XmlAttribute and XmlElement attributes as needed, and then simply serialize the object to XML, passing the resulting string off to the service.

My team built up a console test client for the service at hand, worked through a few minor connection details, and soon we had XML packets being sent off to the queue for processing and were receiving the expected “yup, queue submission looks good” confirmation messages from the queue manager.  All should be good to go, let’s build this thing out into our CRM plugin and get ‘er done right?  Not so fast…

Where’s my Serializer?
When we deployed the plugin to fire off this web service call in CRM, we suddenly started getting a most unhelpful error message:

                “There was an error generating the XML Document.”

Doing a little debugging on the server turned up a stack trace that ended with a null reference exception:

XmlDocument error
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
at FooBarCo. Crm.Logic.Request.getXML() in C:\Users\jdoe\Desktop\FooBarCo\FooBarCo.Crm.Logic\Request.cs:line 31
at FooBarCo.Crm.Plugins.CreateRequestWebServicePlugin.Process(IServiceProvider serviceProvider, Dictionary`2 data, String rawData) in c:\Users\jdoe\Desktop\FooBarCo\FooBarCo.Crm.Plugins\CreateRequestWebServicePlugin.cs:line 100
at SonomaPartners.Xrm.Toolkit.Server.Plugins.Preconstructed.WebservicePlugin.Process(IServiceProvider serviceProvider, Entity entity, String entityNamespace, String data) in :line 0 

{"There was an error generating the XML document."} 

{"The type initializer for 'Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterRequest' threw an exception."}

at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriterRequest..ctor()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializerContract.get_Writer()
at System.Xml.Serialization.TempAssembly.InvokeWriter(XmlMapping mapping, XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id) 
{"Object reference not set to an instance of an object."}

Ok…so the type initializer for our XmlSerializer object threw a null reference exception.  Seems a little strange, especially since I just tested this exact code in a console application and it works fine.  What gives?

A few internet searches later, I came across a post on StackOverflow talking about a similar error that occurs when you are doing dynamic code compilation and assembly loading, and the fix is to set a compiler flag to compile the assembly to disk instead of compiling to memory.  But we’re not doing dynamic compilation…or are we?  See that first line of the inner exception stack trace?  The one that starts “at Microsoft.Xml.Serialization.GeneratedAssembly…”  Yeah…that’s right, we’re generating an assembly at run-time, which means dynamic code compilation.  Under the covers it turns out that the XmlSerializer class does some pretty fancy reflection magic on whatever object(s) you’re serializing.  So how do we tell the compiler inside XmlSerializer to generate to disk?  We can’t.  But we can pre-generate a custom XmlSerializer for our class!

SGen to the Rescue!
I finally stumbled across this blog post by none other than Microsoft’s own CRM team that demonstrates how to improve your application’s performance with pre-generated XmlSerializers.  In a nutshell, you can use the sgen.exe tool provided with Visual Studio to pre-generate your XmlSerializer class and then ILMerge it into your plugin assembly.  The steps I followed were as follows:

  • Compile plugin assembly using generic XmlSerializer class
  • Run sgen.exe /t:FooBarCo.Crm.Logic.Request /a:FooBarCo.Crm.Plugins.dll from the Visual Studio Command Prompt
  • Copy the resulting FooBarCo.Crm.Logic.XmlSerializers.dll assembly into my shared Libraries folder and reference it in my Plugins project
  • Replace the reference to XmlSerializer with a reference to the new RequestSerializer object from the new assembly

Lastly, we added the new DLL assembly to our post-build ILMerge step, recompiled and merged everything together and deployed the newly updated Plugins assembly.  With the pre-compiled XmlSerializer assembly in place, CRM was finally able to send the XML request payloads required of our target web service.

Legend...wait for it...nope, that's all - legend.

Posted by Sonoma Partners on June 22, 2012 in   |  Microsoft Dynamics CRM 2011  |  commentsComments (1)

Today's guest blogger is Jacob Cynamon-Murphy, a Technical Specialist at Sonoma Partners

Barney Stinson is not the only person who cares about things being legendary.  I was building out a demo of Microsoft Dynamics CRM 2011 (CRM) and I created what I considered a pretty cool chart.  Much to my chagrin, the legend was showing in the reverse order (see Before image, below).

Before

I scoured the internet for guidance, but found that there was no documentation going this deep into customizing the legend of a chart in CRM.  Ultimately, my past developer experience helped me dig up the way to do this (see After image, below).  By adding one attribute to the Legend element, I was able to reverse the order.

Code
After

Technical explanation: Behind the scenes, CRM is mapping a declarative model (XML) to an imperative model (.NET).  The XML appears to reflect the structure of the Chart class in the System.Web.UI.DataVisualization namespace.  As a result, we can discover additional elements and attributes that we can use in the chart XML to control the presentation of the chart elements.  Empowered with this knowledge, I now know exactly where to go for more control over my CRM charts.  For example, with the Legend change I made, I found the Legend class had a property called LegendItemOrder, with three options: Auto, SameAsSeriesOrder and ReversedSeriesOrder.  Knowing that I wanted to reverse the order that CRM was using, I defined LegendItemOrder as an attribute with a value of "ReversedSeriesOrder".  Legend… wait for it… dary!

 

CRM 2011 Plugin Registration Error on Connect: 407 Proxy Authentication Required

Posted by Sonoma Partners on June 18, 2012  |  commentsComments (2)

Today's guest blogger is BJ Dibbern, a Developer at Sonoma Partners.

I stumbled across a weird error the other day when trying to use the CRM 2011 Plugin Registration Tool to register a plugin assembly in a new On-Premise environment. I fired up the Plugin Registration Tool and setup all my connection information, however when I hit Connect I received this error almost immediately: “The remote server returned an error: (407) Proxy Authentication Required."

image

First things first, I checked that I didn’t still have Fiddler running. Fiddler can cause these kind of errors, but sadly Fiddler was not running at the time so I knew it was a different problem. Checking on Fiddler actually gave me an idea though to start up Fiddler and see if any requests were being made from the Plugin Registration Tool.

What I found was that when I would click Connect, the tool would try to open a tunnel to login.live.com:443.

image

This was quite surprising to me as I was not expecting any interaction with any external services, even Live.com, considering it was an On-Premise deployment I was attempting to connect with. After seeing this behavior, I opened up Internet Explorer and found I also could not connect to that site from the browser. Rather than mess with the firewall settings, I decided to see if I could work around it.

Apparently the first time you run the Plugin Registration Tool on a new machine or under a new user account, the tool tries to hit Microsoft’s Live services for a new Device Id. Since I had another machine that’d already worked, I figured I might be able to copy the Xml file the tool was looking for over to the target machine. Thankfully, this worked! All I had to do was copy LiveDevice.xml from the source machine’s %userprofile%\LiveDeviceId\ folder to the target machine’s same folder.

Note that at the time I was connecting to an On Premise environment and not a CRM Online environment. However, I would doubt that this would help in that scenario as if you cannot access login.live.com, chance are you’ve got some bigger changes to make to your firewall or proxy server so that you can access login.live.com.


Contact Us for a Quote, or Personalized Demonstrationof Microsoft Dynamics CRM for Your Business.

Contact Us