Dynamic Code Blocks

Microsoft Dynamics GP & .NET technical Blog by Tim Wappat

Convergence 2015–Atlanta USA

image

I just noticed tonight that there is a competition to win Convergence tickets, one has to sell one’s social media soul to enter though, but I’ve tried anyway. If I won, I’d have to find a sponsor pay for the airfare! – Perhaps someone would sponsor me presenting a session like, “.NET Microframework, GP & The Internet Of Things in a Service Orientated Architecture”, for example!

“Enter to win a FREE Up! Pass to Convergence 2015

Don’t miss your opportunity to win your way to Convergence 2015 in Atlanta! We are giving one lucky winner the ultimate Convergence experience with a FREE Up! Pass (valued at $2,145). We are also giving away five $100 gift cards to some of Atlanta's top restaurants. All you have to do is enter our giveaway on Facebook. But hurry, the giveaway ends December 22, 2014 at 11:59pm ET!”

For those of you who don’t know convergence – it is a massive conference in the USA and is packed full of more sessions than you can shake a stick at, on all kinds of subjects Dynamics related.

Service Orientated Architecture & Dynamics GP–the future is bright

Andrew Haywood of m-hance #DYNBC14

Andrew Hayward keynote the m-hance conference earlier in the year


It being late December I’m reflecting on the year, one of the highlights for me was when I got the pleasure of a long chat, one to one, with Chad Sogge & Daryl Anderson and then a quick chat to Errol Schoenfish. I came away having learnt many things that have really changed my whole opinion of the Dynamics GP product future.

The move to service orientated architecture in GP 2015 version is perfect for developers, as is the tighter integration with .NET from Dexterity. This really does open up the product to do virtually anything we can dream up. This is a really significant moment in the evolution of GP in my view. Today it can now leverage the investment Microsoft has made with the .NET framework and the full Microsoft product stack, including cloud computing.

I also observe Microsoft handing back third party products to the original developers and simultaneously unzipping the core product for more developers to build awesome things upon it. To me this feels like a message that – hey, we can’t be everything to everyone and also keep it all maintained and yet still drive the product forward, it’s time to let you do that for us.  Microsoft have a growing ISV community around that can build great things for specific market verticals,  thus allowing  Microsoft to maintain the framework, core product, adding new features and performance… boy so many features have been delivered recently! The agile development burndown cadence MS have at the moment is really swelling the bullet points in the sales datasheets and giving us plenty of “new toys” to implement! Smile

I do think there are some amazing years ahead of us in the Dynamics world, presenting many opportunities for the ISV community to grow and build some great products on top of our Fargo friends hard work! I can’t wait to see what the next year brings on.

Buttons not persisting size in Dynamics GP add-in

Steve Endow, posted yesterday on Buttons mysteriously resize on VS Tools Dynamics GP Forms -- VST template bug?This could have a big impact as I’m now working against GP2013R2 and so I set about investigating the issue. Thanks to Steve for sending me a ZIP of his example, from that I confirmed the same buggy behaviour on my environment, what is more, I also confirmed it on my own projects in my environment.

A big thanks Steve for pointing this issue out, here are my findings.

Reproduce the issue


Start new Dynamics GP Add-in Project

image

Add a form into the project

image

Drag two buttons onto the form

image

Resize the buttons so one is significantly larger than standard and one is much smaller than standard.

image

Save the form Form

close the form down, then open it again in the designer view….

image

Yes the buttons have defaulted to “default” size.

I have tested this with Visual Studio 2012 & 2013 as I remembered running Dynamics GP Tools is not technically supported for VS2013.

This is an interesting behaviour!

Testing

None of the following testing helped:

  • Using Visual Studio 2012
  • Applications.Dynamics / Microsoft.Dexterity.Bridge / Microsoft.Dexterity.Shell dlls from other copies
  • Downloading and installing latest Visual Studio Tools for GP including GP2013R2
  • Trying class library projects

To track down what was going wrong I jumped into the designer file, thinking that the design time values were not being persisted in the DynamicsGPForm1.Designer.cs

image

From the above screen shot, the sizes are as expected, one button longer horizontally than the other. Clearly the designer is ok, so why this behaviour? Forms that inherit from the type DexUIForm (i.e. “Microsoft Dynamics GP Forms” from project >> Add New Item), have some extra goodness in the designer “tray area”, as shown below. One of those is the dexButtonProvider. This component grabs the buttons in the form and adds some extra properties to them, it allow the developer to give the users the same experience from the buttons in an add-in, as they would have from the native GP Dexterity buttons.

-so this component is overriding the drawing of the button, there we have a lead to the answer.

image

The DynamicsGPForm1.resx file holds the form resources. If you are “in the know”, then you will know that these providers are persisting design time state through the form resources file, as seen from a snippet below:

<metadata name="dexButtonProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
</metadata>
<metadata name="dexDefaultColorsProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>260, 17</value>
</metadata>
<metadata name="dexLabelProvider.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>450, 17</value>
</metadata>

We would expect to be seeing a XML fragment for each button in here, but it is missing. The expected missing fragment would like this, for button1;

<metadata name="button1.DexDefaultsSet" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>


If you paste this code in before the final </root> element in the resource file, save and open the form again, amazingly the label size is displayed correctly.
 
The problem seems to be that at design time, when the button is added to the form, the button provider is not writing the information into the resource file that it needs to bind itself to the button correctly.
 

Workaround

It turns out there is a work around that forces the form to emit this meta data into the resource file. Simply flip the “Button Type on DexButtonProvider” property of each button on the form. Do this by after creating the button, set the value other than “Standard” and back again to “Standard”.
Now save the form and check the form resource file. The XML that was missing has been generated for the buttons, and it is confirmed by re-opening the form, the buttons will now retain their designed sizes.

image

 

Conclusion

There is an issue with both Steve and My environments, or there is a bug in the button provider when used in GP2013R2 and .NET 4.5. I have a work around for now, but may come back to this out of curiosity, perhaps reflecting into the button provider to find the root cause.

Find Custom Triggers before Dynamics GP upgrade

imageBe aware that any custom created SQL triggers in the Dynamics GP database that have been created outside of Dynamics GP will be dropped at time of upgrade from one version of GP to another. Custom triggers are a technique SQL Server Admins might use to, for example default a field in GP, without using a GP application modification. Introducing triggers in GP can cause application malfunctions, so please read up on the subject before attempting such an action.

Custom eConnect stored procedures also suffer this fate so also grab back ups for those before any upgrade

Pre-Upgrade

  • Identify the custom triggers for each database
  • Script out the custom triggers using SQL Server Management Studio

Post-Upgrade

  • Run the create script from the pre-upgrade step to recreate SQL triggers in the database.

In an ideal world, your documentation will have details of these triggers, and the trigger create scripts are in your server build scripts, locked away safely in source control –right?

For those of us in the real world, the script below can be used to group the create dates of triggers in a database together, look for where the rank changes on the far right column. As the majority of triggers are created together when products are installed, the ad-hoc created triggers stand out as being in their own ranking groups.

-- Script will list all triggers in the current database
-- Custom SQL triggers are removed at upgrade by the upgrade
-- Script triggers out to recreate them post upgrade
-- The rank column can be used to find where triggers have been manually addded
-- those triggers will usually be groups together by that ranking
-- Remember to run for each company and the DYANMICS database too
SELECT
sysobjects.name AS trigger_name
,USER_NAME(sysobjects.uid) AS trigger_owner
,s.name AS table_schema
,OBJECT_NAME(parent_obj) AS table_name
,OBJECTPROPERTY( id, 'ExecIsUpdateTrigger') AS isupdate
,OBJECTPROPERTY( id, 'ExecIsDeleteTrigger') AS isdelete
,OBJECTPROPERTY( id, 'ExecIsInsertTrigger') AS isinsert
,OBJECTPROPERTY( id, 'ExecIsAfterTrigger') AS isafter
,OBJECTPROPERTY( id, 'ExecIsInsteadOfTrigger') AS isinsteadof
,OBJECTPROPERTY(id, 'ExecIsTriggerDisabled') AS [disabled],
sysobjects.crdate as [Trigger Created],
RANK() OVER ( order by DATEADD(dd, 0, DATEDIFF(dd, 0, sysobjects.crdate)) desc) [Rank of Trigger Created Date]
FROM sysobjects

INNER JOIN sysusers
ON sysobjects.uid = sysusers.uid

INNER JOIN sys.tables t
ON sysobjects.parent_obj = t.object_id

INNER JOIN sys.schemas s
ON t.schema_id = s.schema_id

WHERE sysobjects.type = 'TR'
order by sysobjects.crdate desc

Result

image

How to script the triggers out

Once they have been identified them, use the “generate scripts” by a right click of the database node in SQL Server Management Studio object explorer, to script all triggers out. It is then possible to search through the generated script for the term “CREATE TRIGGER” and extract the triggers of interest into another TSQL file to run after the upgrade.

image

To do this, script out all the tables

image

On the options before you finish the script wizard, in the tables section, select to allow scripting of the triggers.

image