Tampilkan postingan dengan label C#. Tampilkan semua postingan
Tampilkan postingan dengan label C#. Tampilkan semua postingan

Rabu, 15 Februari 2017

VST: An error occurred while loading or initializing an addin

As I mentioned before, I am now the Lead Software Engineer at Mekorma. I love it here as I get to work with some really talented software engineers and developers, all of which challenge me everyday. One of the cool new products we are working on, Mekorma Multi-Batch Management, allows you to build payment batches, print and post payments, and generate electronic funds transfer (EFT) and positive pay (Safe Pay) files, across companies, and across multiple checkbooks, with some minor configuration and just the click of a button. You can see an in-depth video on the product here.


Part of the challenges of building Multi-Batch Management were its extensive interfacing with both our own Mekorma MICR product and Microsoft Dynamics GP, and in particular, the Safe Pay module - Multi-Batch Management is designed to drive the Microsoft Dynamics GP user interface, thus eliminating the need for invasive code.

If you have worked on integrating code for Microsoft Dynamics GP, you are certainly familiar with the challenges surrounding the response to Dexterity modal dialogs. This is true for Microsoft Dexterity service enabled procedures as much as it is true for standard applications like ours, that simply try to drive the user interface.

NOTE: Dexterity does not have a programmatic mechanism to respond to modal dialogs. As it stands, only Visual Basic for Applications (VBA) and Visual Studio Tools for Microsoft Dynamics GP (VST) provide event handlers for modal dialogs.

VST aids in responding to Dexterity modal dialogs by allowing a developer to define form or window level modal event handlers. Because our code needed to respond to dialogs in Safe Pay only when our process was running, it was necessary to create an application assembly for our dictionary, that we could then reference in a Visual Studio Tools project. In addition, we needed to reference the Safe Pay application assembly as well. The project reference looks something like this:


Project References

Once references are added to the project, the tendency is to immediately add all event handlers to the Initialize() method within the GPAddIn class, as shown below:


public void Initialize()
{
Dynamics.Forms.SyErrorMessage.SyErrorMessage.OpenBeforeOriginal +=
Dynamics_SyErrorMessage_OpenBeforeOriginal;
Dynamics.Forms.CmTransactionEntry.CmTransactionEntry.BeforeModalDialog +=
Dynamics_BeforeModalDialog;
Dynamics.Forms.CmEftGenerateFiles.CmEftGenerateFiles.BeforeModalDialog +=
Dynamics_BeforeModalDialog;
SafePay.Forms.MePpTransactions.MePpTransactions.BeforeModalDialog +=
new EventHandler(SafePay_Transactions_BeforeModalDialog);
}


Unfortunately, this approach has a problem: let's assume Safe Pay is not installed, therefore, the Safe Pay application dictionary and application assembly are missing from the Dynamics GP installation folder. Since the Initialize() method is the entry point to your VST application, when the runtime engine attempts to load your assembly, your application would contain a reference to a non-existing assembly. This in turn will cause the runtime engine to produce the following error:

"An error occurred while loading or initializing an addin. As your administrator to check the Windows event log for more details. Dynamics will now close."


This is always been accepted as "the way things work". Unfortunately, we couldn't live with the status quo as it meant that customers who did not require the Safe Pay module would have to install it just for the sake of our assembly not failing.

We then attempted to move our event handler registration into it's own method, enveloping the call in a try..catch block:


public void Initialize()
{
Dynamics.Forms.SyErrorMessage.SyErrorMessage.OpenBeforeOriginal +=
Dynamics_SyErrorMessage_OpenBeforeOriginal;
Dynamics.Forms.CmTransactionEntry.CmTransactionEntry.BeforeModalDialog +=
Dynamics_BeforeModalDialog;
Dynamics.Forms.CmEftGenerateFiles.CmEftGenerateFiles.BeforeModalDialog +=
Dynamics_BeforeModalDialog;

try
{
InitializeSafePay();
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}

public void InitializeSafePay()
{
SafePay.Forms.MePpTransactions.MePpTransactions.BeforeModalDialog +=
new EventHandler(SafePay_Transactions_BeforeModalDialog);
}


The above produced virtually the same results. That is, the exception was still being displayed. Now, quite clearly, if we commented out the throw statement, the exception would no longer present itself and the message would not appear, precisely what we needed since we did not want to alert of the missing assembly and prevent the user from login into Dynamics GP.

NOTE: Alternatively, we implemented tracing capabilities for our assembly, so now all exceptions are recorded in a log file.

Special thanks to my Sr. Software Engineer, Lee Butenhoff for researching and providing a solution to this long standing issue.

Until next post!

MG.-
Mariano Gomez, MVP

Minggu, 28 Desember 2014

The Dynamics GP Blogster Best Articles of 2014

The Dynamics GP Blogster Best Articles of 2014

How about this 2014 year, ah? Two major releases in Microsoft Dynamics GP 2013 R2 only to top off the year with the recent release of Microsoft Dynamics GP 2015. More than 30 new features in 2013 R2 (over 150 if you include those released in GP 2013 RTM) and now over 120 new features in Microsoft Dynamics GP 2015, including the cornerstone .NET interoperability and Service Based Architecture components, it's no wonder why the Microsoft Dynamics GP Product Management and Product Development teams deserve a massive showing of the hands on this one! Congratulations team on a job well done.

Let's not forget about the events either: the wildly successful Microsoft Convergence 2014 Atlanta, the hugely concurred GPUG Summit 2014 St. Louis, and what's got to be the most anticipated partner event since the days of Stampede, reIMAGINE 2014 in Fargo. All these events drove the vision of t

Travel was also off the chain for me: Johannesburg, South Africa; St. Louis, Missouri; Fargo, North Dakota; Boston, Massachusetts; Las Vegas, Nevada; Green Bay, Michigan; Kansas City, Missouri; Shreveport, Louisiana; and the list goes on! Over 70,000 miles of airline travel, 100+ nights of hotel lodging, and tons of driving miles, ah!... and the ALS ice bucket challenge in between.

Nonetheless, every year I try to bring interesting topics to the blog, an insight into the events I attend, and definitely, those troubleshooting and development articles that are life savers when you need them most. So without further due, here's a sample of some of the best articles you liked throughout the year (in no particular order)


No.
Article
1Word Templates: We can't open template because we found a problem with its contents. Just recently I was working on a Sales Invoice Word Template customization for a customer and ran into a strange issue when attempting to print a batch of invoices for customers assigned to this template... Read more.
2Web Client Wednesday - You receive ArgumentNull_Generic exception when clicking an option on the Navigation Bar. In good measure, here at Intelligent Partnerships we eat our own dog food. As of January 1, 2014 we completed our internal rollout of Microsoft Dynamics GP 2013 and web... Read more.
3Microsoft Dynamics GP 2013 Virtual Machine image from the Windows Azure Gallery.
In my previous article, Part 1 of the series, I talked about provisioning a Microsoft Dynamics GP 2013 development environment from the Windows Azure gallery.  If you are already an MSDN subscriber and... Read more.
4Preventing Visual Studio Tools customization processes from being terminated by Microsoft Dynamics GP. Just recently I ran into a case on the Microsoft Dynamics GP Partner Forum where the ISV developer was dealing with a potentially long standing process to be executed from... Read more.
5Working with the Dex.ini Settings in Microsoft Dynamics GP 2013. Dex.ini settings have always existed to provide developers and end-users with ways to set a number of preferences for their Microsoft Dynamics GP application without the need of additional development or customizations... Read more.
6Using Microsoft Dynamics GP Business Intelligence deployment utility to deploy custom SSRS reports. In the previous installment, I outlined a technique to deploy your custom SQL Reporting Services reports using the standard Business Intelligence deployment utility provided by Microsoft... Read more.
7Deploying Business Analyzer Companion App Services on Windows Azure Service Bus. If you are not using Business Analyzer today, shame on you. Last year sometimes I wrote a small article on how to deploy the Business Analyzer Windows 8 application on a personal laptop, which is typically... Read more.
8Microsoft Dynamics GP 2015 Developer's Preview: .NET Framework Interoperability - Part 3. In part 2 of the series, I delivered a brief primer on the service architecture in Microsoft Dynamics GP 2015 and how you are able to consume services natively created with Dexterity. There are two types... Read more.
9Working with Dex.ini Settings to customize the Microsoft Dynamics GP Connect gadget. Have you ever wanted to wake up with The Dynamics GP Blogster page as the centerpiece of your Microsoft Dynamics GP application homepage? Or how about your favorite online news outlet? What if you...Read more.
10Microsoft Dynamics GP backups with Windows Azure Blob Storage Service - Follow up. As a follow up to my post yesterday (see Microsoft Dynamics GP backups with Windows Azure Blob Storage Service), an issue has been identified with Microsoft Dynamics GP 2015 running on SQL Server 2014...Read more.


2015 is sure to be a very exciting year for the Dynamics GP community. Right off the bat I can think of Convergence 2015 in Atlanta, GPUG Summit in Tahoe-Reno, NV, reIMAGINE in Fargo, ND, the upcoming release of Microsoft Dynamics GP 2015 R2 with another iteration, Dynamics GP 2015 R3, close to the end of 2015. So lots and lots to talk about.

Personally, I start the year with a business trip to Ireland, I already have commitments with Dynamic Partner Connections, and tons of webinars in conjunction with GPUG. So please stay tune to hear from those.

Until next post!

MG.-
Mariano Gomez, MVP
Intelligent Partnerships, LLC
http://www.intelligentpartnerships.com/

Kamis, 11 Desember 2014

Microsoft Dynamics GP 2015 Developer's Preview: Wrap Up

Microsoft Dynamics GP 2015 Developer's Preview: Wrap Up

It has been an exciting ride combing through the features and capabilities of the Microsoft Dynamics GP 2015 Service Based Architecture components, starting at the core with the new and enhanced .NET interoperability capabilities within Microsoft Dexterity, all the way to the new service base architecture foundation built into Microsoft Dynamics GP to expand the realm of integrations that can be accomplished in today's fast paced, application (Apps) dominated world, whether those applications are native to the Windows platform or cross-platform, whether they reside in the cloud or on premise, and regardless of the form factor.

I wanted to provide this single point of reference to reach all entries in the series, which saw 5 articles over the past 5 months.

Microsoft Dynamics GP 2015 Developer's Preview: Loading the VHD image - Part 1 (Aug 29, 2014)
Microsoft Dynamics GP 2015 Developer's Preview: Working with Sample URIs - Part 2 (Sep 24, 2014)
Microsoft Dynamics GP 2015 Developer's Preview: .NET Framework Interoperability - Part 3 (Oct 29, 2014)
Microsoft Dynamics GP 2015 Developer's Preview: Dexterity Service Patterns - Part 4 (Nov 25, 2014)
Microsoft Dynamics GP 2015 Developer's Preview: Dexterity Service Patterns - Part 5 (Dec 1, 2014)

Since Microsoft Dynamics GP 2015 is now available to the general public, my focus will turn to keeping you abreast of those application nuggets, point out any glaring issues or problems, and continue to work with the development community at large to maximize the technological foundations of the product.

In the future, you may see new series on this blog seeking to enhanced the product learning experience, so stay tuned.

Until next post!

MG.-
Mariano Gomez, MVP
Intelligent Partnerships, LLC
http://www.intelligentpartnerships.com/

Senin, 01 Desember 2014

Microsoft Dynamics GP 2015 Developer's Preview: Dexterity Service Patterns - Part 5


In my previous article (see Microsoft Dynamics GP 2015 Developer's Preview: Dexterity Service Patterns - Part 4), we discussed the merits of the Wrapped Window pattern and how it can save time by avoiding refactoring of complex business logic embedded on Dexterity forms. I also provided an intro on the Decoupled Logic pattern and why this is the preferred method for exposing Dexterity services as it provides the best performance. However, we also came to the conclusion that refactoring is only feasible in cases where decoupling the business logic from the UI will yield a reasonably increase in performance, without negatively impacting development and product release timelines.

We also looked into the Decoupled Logic pattern considerations and today we will accompany these with sample code to clarify the meaning of each.

Decoupled Logic Considerations
  • In decoupled logic mode, there is no implicit data types validation or conversion. Unlike the Window Wrapped pattern where the map statement manages casing, signed versus unsigned precision, and nulls during the binding of window fields to our instantiated class properties; in the Decoupled Logic pattern we must perform all the conversion and validations.
     
  • Check for valid value for decimals
(Click to enlarge)
     

  • Check for a valid value for a drop-down or radio group
(Click to enlarge)
     
  • Force strings to upper case as needed, for example, items, customers, vendors, etc. (see first example).
  • Set default values as needed as user may pass a null value as a parameter to a service procedure
    

There you have it! Working with services and .NET interop is quite frankly not that complicated so long you understand the patterns and some of the rules governing them. So finally, we will put this all together in a final installment that will complete this series.

Until next post!

MG.-
Mariano Gomez, MVP
Intelligent Partnerships, LLC
http://www.intelligentpartnerships.com/

Senin, 24 November 2014

Microsoft Dynamics GP 2015 Developer's Preview: Dexterity Service Patterns - Part 4

What a week of learning that reIMAGINE 2014 conference was! If you stayed for the post conference training classes, even more power to you.

In my previous article (see Microsoft Dynamics GP 2015 Developer's Preview: .NET Framework Interoperability - Part 3), I talked about the .NET interop capabilities introduced in this iteration of Dexterity and how these new capabilities have become the foundation for unlimited extensibility options for Dexterity-based applications. Today, I wanted to talk about another aspect brought by .NET interop: Dexterity services. However, to understand Dexterity services, we must first take a look at the service implementation patterns.

Wrapped Window Pattern

Under the wrapped window pattern,  a complete Dexterity form or window logic is wrapped into a service. The goal is to instrument the user interface and leverage all the existing validation logic within a RESTful service as to avoid recreating that same logic separately -- similar to the behavior displayed by the Web Client.

Wrapped Window Pattern (click on image to enlarge)

A closer to home example is how Integration Manager's standard adapter leverages the UI to get data into Microsoft Dynamics GP.

Wrapped Window Pattern Considerations

Create .NET object
The basic idea here is to leverage .NET to create a class library with all the properties reflected by the associated Dexterity table, i.e., RM_Customer_MSTR, then expose that class to your Dexterity application (via .NET interop). You can then instantiate that class in Dexterity to map the UI fields to the instantiated class properties. Here are some basic steps to follow:
  • Include all fields from table as part of the .NET class 
  • Remove white spaces from names, i.e., 'Customer Number' should be defined as CustomerNumber within the .NET class 
  • Create enumerations for radio groups and drop down lists

Preparation for window being wrapped
What we are trying to do in this instance is, identify all modal dialog elements in our code that may require branching logic for when our application is running in service mode, finding an effective way to handle these.
  • Handle calls to Warning_Dialogs by evaluating service mode state with IsServiceMode() function.
    Warning_Dialogs handling
  • Ask messages for actions need a predetermined action 
    Ask() function
  • On-the-fly record events cannot be performed . When in service mode, if the record is not found, a trace event is created.
Ask() on-the-fly record add
  • TraceAdd and Trace are used to report service events to calling applications or services.

Decoupled Logic Pattern

The Decoupled Logic pattern exposes Dexterity procedures and functions as a service, this is, the business logic does not reside in a form. Under this approach, the objective is to separate the business logic from the user interface. Since we are dealing with procedures and not the user interface, the decoupled logic pattern can be considerably faster from a service performance perspective.

Decoupled Logic Pattern (click on image to enlarge)

Using our closer to home example, think of Integration Manager's eConnect adapter, which leverages the eConnect assembly and stored procedures to bypass the user interface. At the same time, this is a prime example as to why you want to find a Dexterity pattern approach that's suitable for creating a service -- you may not want to have to refactor the entire UI, depending on the complexity of the UI validations. Key points in determining whether to refactor the UI or not are the frequency of use of the UI in question and performance of the UI code.

Decoupled Logic Considerations

  • In decoupled logic mode, there is no implicit data types validation or conversion. Unlike the Window Wrapped pattern where the map statement manages casing, signed versus unsigned precision, and nulls during the binding of window fields to our instantiated class properties; in the Decoupled Logic pattern we must perform all the conversion and validations.
  • Check for valid value for decimals
  • Check for a valid value for a drop-down or radio group
  • Force strings to upper case as needed, for example, items, customers, vendors, etc.
  • Set default values as needed as user may pass a null value as a parameter to a service procedure

In the interest of clarity (and space), I will tackle some decoupled logic sample code in a follow up article.

Until next post!

MG.-
Mariano Gomez, MVP
Intelligent Partnerships, LLC
http://www.intelligentpartnerships.com/