Tuesday, November 25, 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/

No comments: