Wednesday, November 26, 2014

Dynamics GP JSON Integration Issue: null object property values for JSON parsed by MVC controller

By Steve Endow

I haven't yet seen code samples or API documentation for the new Dynamics GP 2015 Service Based Architecture (SBA), but I have a hunch that this might be relevant when we start working with GP 2015 SBA and use JSON to communicate with the GP SBA interface.

WARNING:  If the title wasn't warning enough, this post is a full-on geek fest, so if you aren't a developer that loves Riddles of the Code, flee now.

I'm currently working on a web service application that allows a Linux web server to integrate to Dynamics GP.  After considering various options, the client and I agreed that the simplest approach would be for me to develop a custom web application that could receive and send JSON.  The Linux developers were very comfortable with this, and after getting some help from an expert with experience developing JSON web apps in Visual Studio using MVC, I was able to create an integration that worked great.

After the release of the initial version of the web integration, I noticed a quirk about how blank JSON values were being received by my code.

If the client sent a JSON parameter value that was blank, that particular property on my object would be null.  So if he did not supply a Address2 value, I would get Customer.Address2 == null.

I thought that it was due to how I was defining my objects in Visual Studio using the simple property definition style, such as:

   public string Address2 { get; set; }

Since I wasn't defining a default value for the property, I thought it made sense that I was getting null, assuming that the .NET MVC JSON parser was skipping the empty JSON parameters.  Seemed to make perfect sense at the time.

I didn't think much about it, and just added some workaround code to check for null values and set them to empty strings.  In hindsight, I now know that was sloppy, but since I didn't realize the underlying problem, it was a simple fix and seemed to worked.

Now, I'm adding some additional functionality to the web application, as the customer wants to have new features, such as the ability to search for GP customers.  This time around, I'm more familiar with web app development and MVC, so I was a little more observant about the null property issue.

While testing my recent enhancements, I once again noticed that when I submitted a request to my web app, blank JSON values were being translated to null property values on my objects.  Still thinking that this was due to my object property definitions, I modified my object to use a "full" property definition, like so:

private string address = string.Empty;
public string Address
    get { return address; }
    set { address = value; }

When I walked through the code in debug mode, what I found surprised me.  Even though my property was initializing properly to an empty string, the MVC JSON parser was subsequently setting the property value to null.

So the null values weren't due to my property definitions!  So why was I getting a null, and how can I fix this?

I didn't even know how to phrase a search, but after a few random search attempts in Google, I found this Stack Overflow thread that appeared to exactly describe my scenario:

It appears that with MVC version 2.0, Microsoft changed the way that JSON is parsed.  Instead of assigning empty strings, the newer MVC versions assign null.  Here is a post that covers some of that history:

Okay, great, so how do I "fix" this "problem"?

The Stack Overflow post has several suggestions, none of which I really understand.  I understand the concept that it changes how the JSON is parsed, but the actual code is currently Greek to me.

I ended up trying the suggestion to create a new class called EmptyStringDataAnnotationsModelMetadataProvider.  I then modify my Global.asax file and add the single line to the Application_Start() method.

ModelMetadataProviders.Current = new EmptyStringDataAnnotationsModelMetadataProvider();

I am using MVC 4.0, and this solution worked for me.

Now, when I pass in JSON with blank parameter values, my string properties are empty strings and not nulls.  You know you are a geek when you get excited about an empty string.

It was a bit of a journey, but this obscure change should make my life easier.

And I suspect that once we start developing against the GP 2015 Service Based Architecture, this may come in handy if GP returns empty JSON parameters.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Monday, November 17, 2014

Unable to read unsaved Cash Receipt Document Number using VS Tools

By Steve Endow

I have a customer that issues thousands of invoices to a handful of customers.  So when they receive a payment from a customer, they have to apply the payment to hundreds or thousands of invoices.

To accommodate this high volume / bulk payment apply process, I developed a custom AR apply window.  The window works well on its own, but the customer wanted the ability to launch the custom apply window from the Cash Receipts Entry window, immediately after they enter the payment.

When the user launches my custom apply window, they wanted the customer, payment doc number, check number, and payment amount from GP all pre-populated so that they could immediately start applying the payment, which makes complete sense.

No problem, I thought.  Easy peazy lemon squeezee, right?

Unfortunately, no.

In my VS Tools AddIn project, I added the Menu Handler to the Cash Receipt window so the user could open my custom window.  Very straightforward and worked fine.

I then added some code to read the field values from the Cash Receipt window so that I could populate the fields on my custom apply window.  That was simple as well and everything looked good.

But when I tested the code, it didn't work.  My window would launch, but the fields on my form weren't populating.

In Visual Studio, I attached to the Dynamics.exe process and started debugging.  I found that an If statement was being skipped:

if (rmCashReceiptWindow.CustomerNumber.Value != string.Empty && rmCashReceiptWindow.DocumentNumber.Value != string.Empty && rmCashReceiptWindow.CheckNumber.Value != string.Empty)

That was odd, since I had populated all of the fields on the Cash Receipt window.

The customer number, document number, and check number were all populated.

I checked the field values in Visual Studio, and to my surprise, the DocumentNumber field value was empty.

I could read the Check Number and Customer Number just fine, but the Document Number field had no value, even though it was displayed in GP.

Um, what gives?

Just to make sure I wasn't making a silly mistake, I fired up Andrew Dean's very cool VSTools Object Explorer that we demonstrated at our reIMAGINE session last week.

Sure enough, the Object Explorer confirmed that the Document Number field had no value, and that the value wasn't stored in any of the other fields accessible through VS Tools.

This confirmed that with an UNSAVED cash receipt, the Document Number field value was not accessible in VS Tools.

But after I saved the cash receipt, then pulled the receipt back up in the Cash Receipt window, I could read the Document Number value in VS Tools.

Not sure what is going on.  My two wild guesses are that during data entry, the field value is being stored in some temporary field--which seems really strange.  Or, the VS Tools field value is somehow wired up to the underlying Dex table buffer, and that table buffer value is not populated until the transaction is saved.  Which seems like a stretch as well.

I'm going to dig into it further and see if other windows have this issue, but this definitely complicates things if you are trying to trigger events in VS Tools that depend on the GP document number during data entry.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Saturday, November 15, 2014

Change the name of a Dynamics GP Web Client server

By Steve Endow

Several months ago I setup the GP Web Client on a spare GP 2013 R2 server that I had used to test Scribe.  The server was named Scribe, but I wasn't using Scribe any more, and will be using this server to work with the Web Client, so I wanted to change the name of the server.

I had a feeling that changing the server name would be a bit of an off-roading adventure, and sure enough it was.  But with some fiddling, I think I eventually figured out the process to change the server name and reconfigure all of the GP Web Client components to get everything working again.  At a minimum, it was a fun exploration that helped me learn a little more about the innards of the GP Web Client server configuration.

I assume this will be a very rare situation, but since I went through the process, I figured I would document it in case any other poor soul decides to change the name of their GP Web Client server.

The one caveat about this process is that I have a single server deployment.  If you have a multiple-server deployment, you may need to complete a few additional steps on the additional servers.

And I would only recommend this process for a test server.  I haven't yet vetted the process, so I would not recommend this for a production server.

  1. Change the computer name and reboot server
  2. Update the Dynamics GP ODBC DSN with new server name
  3. If using a self-signed or server-specific SSL cert, remove the SSL cert from the IIS site Bindings window, then create and install a new SSL cert
  4. Modify the server name in Microsoft.Dynamics.GP.Web.ConfigurationWizard.config file (C:\Program Files\Microsoft Dynamics\GP Web Client)
  5. Launch SQL Server Management Studio and login using the new server name  (I don't know why, but this seemed to resolve a subsequent SQL connection issue during the repair process)
  6. Open Control Panel -> Programs
  7. Select Microsoft Dynamics GP Web Client and click on the Change button
  8. Click the Repair button
  9. Complete the GP Web Client repair / configuration windows
  10. Open a command prompt and run iisreset to restart IIS
  11. Restart the GP Session Central Service and GP Session Service
  12. Open a web browser and try logging in to the GP Web Client to confirm the web client works
  13. Connect to the Web Management Console (https://ServerName:PortNumber/WebManagementConsole) and update the server name for the Session Central Service 
  14. In SQL Management Studio, navigate to the GPWEBCLIENTSESSIONCENTRAL database
  15. Remove any records from the SessionStatus table
  16. Remove the old server record from the SessionHostStatus table
  17. Remove the old account records from the ServiceSecurity table
  18. After these changes, my old Dynamics GP logins would no longer work.  I had to re-enter my GP registration keys and then reset the passwords of my additional GP users.  I don't know if this was due to changing the DSN, or due to other aspects of the changes.

If anyone else is lucky enough to have to complete this procedure, please let me know if I missed any steps or if you have to do things differently than me.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Consultant Toolkit: How to make friends at a tech conference (USB Battery Chargers)

By Steve Endow

Once a year, Fargo, North Dakota becomes the epicenter of the technology world as the smartest (and best looking) people on the planet all converge at the most scenic and bucolic city in America for a Dynamics GP partner conference.  This year, it was for the reIMAGINE 2014 conference.

When I have flown from Los Angeles to Fargo the last 3 years, I've had a stop in Minneapolis St. Paul--an airport that must have been going for a world record in walking distance between terminals.  Since many of the Fargo flights are routed through the MSP airport, it's become a spot for me to meet up with colleagues on the way to Fargo.  Last year, my blog buddy Christina Phillips and I coordinated our Fargo flights, so we were able to grab lunch and catch up at MSP and then take the same plane into Fargo.

This year, while I was waiting at the gate, my friend Tanya from S2 Technology just happened to walk by.  Sure enough, we were on the same flight to Fargo.  As soon as she sat down, she had to find an outlet and start the famous airport charging routine.  Yup, she was a wall hugger.  She had to charge her laptop, and then she had to plug her phone into her laptop to charge that too.

I admit I've been there before.  But earlier this year I was introduced to a nifty gadget:  the USB battery charger.

It's very simple and somewhat obvious, but brilliant.  Just a battery that you can charge via USB, and then use to charge your phone or tablet or other devices that charge via USB port.

They come in all sorts of shapes and sizes depending on what you need to charge and how much capacity you need or want to carry around.

A friend gave me a small version like the one pictured above, and after seeing how handy it was, I bought a slightly larger version made by Jackery.

I dug out my Jackery charger and gave it to Tanya to test.  During our wait for the flight, it did a pretty good job of charging up her phone and had plenty of capacity left.  I think she was sold on the idea.

During our mind-blowingly awesome Pushing the Boundaries of .NET Development presentation, Andrew Dean and I gave them away as prizes to the attendees of our session--who I'm told were the smartest people at the conference.

And throughout the conference, I was able to charge my phone and tablet without having to ever look for a wall socket.

And on the last night of the conference, Andrew's USB phone charger stopped working, leaving him with a dead cell phone.  I gave him my USB charger and his phone got fully charged overnight--a tech rescue.

So if you want to stop being a wall hugger, check out USB battery chargers.  They are inexpensive and can help you make friends at tech conferences.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Troubleshooting GP Web Client Error: An unexpected error has occurred. Press the Sign-in button to reconnect to the application.

By Steve Endow

Others have posted articles about troubleshooting issues with the GP Web Client (such as Mariano's comprehensive series here), but since this is the first time I've done the troubleshooting, and since my problem was pretty simple, I thought I would document my experience.

I have a server with the Dynamics GP Web Client installed and configured.  It worked fine back when I performed the initial install, but it has been a few months since I've used the Web Client.

While trying to setup the new GP 2013 R2 workflow features today, I tested the Web Client and received this error in Internet Explorer:

Unexpected Error
An unexpected error has occurred. Press the Sign-in button to reconnect to the application.
Correlation ID: a238ed59-ea0e-46f7-b4ef-482f2e370372 

This is a generic error, so the error message itself doesn't offer any clues.

One thing I recently learned at the reIMAGINE 2014 conference is what a "Correlation ID" is.  That unique ID is assigned to a web client process and allows you to trace a process in Event Viewer and other logs when testing or troubleshooting.  If you have 20 people using the Web Client and need to troubleshoot an error for one user, the ID lets you identify errors or messages for that particular user.  So while that ID can be helpful in troubleshooting, it doesn't have any meaning or explain what caused the error.

To learn more about the error, I opened Event Viewer and navigated to the Dynamics application log.  There I found a pile of shiny red errors.

Starting at the top, I reviewed this error.  Notice the GUID at the beginning of the error--this matches the Correlation ID I saw in Internet Explorer, telling me that this error is related to my browser session.
a238ed59-ea0e-46f7-b4ef-482f2e370372:An unexpected error has occurred.  Press the Sign-in button to reconnect to the application.::System.Web.HttpUnhandledException (0x80004005): Exception of type 'System.Web.HttpUnhandledException' was thrown. ---> System.ServiceModel.EndpointNotFoundException: There was no endpoint listening at https://webclient:48650/SessionCentralService that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details. ---> System.Net.WebException: Unable to connect to the remote server ---> System.Net.Sockets.SocketException: No connection could be made because the target machine actively refused it [2001:0:5ef5:79fb:8fb:201f:3f57:e65b]:48650
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.ServicePoint.ConnectSocketInternal(Boolean connectFailure, Socket s4, Socket s6, Socket& socket, IPAddress& address, ConnectSocketState state, IAsyncResult asyncResult, Exception& exception)

Next, I saw the message "There was no endpoint listening".  If you've worked with eConnect, you may have seen this error, which can be caused when the eConnect service is not running.  The message helpfully indicated that the SessionCentralService was not available, so that led me to check Windows Services.

Sure enough, when I found the GP Session Central Service, it was not running.  Great, just start it up, right?  Not so fast--apparently there was a reason why it wasn't running.

And there it is.  The service can't start due to a password issue.  I hadn't set the "Password never expires" option for the service account, so the password had expired.  I fixed the account and the service started up properly.

With the service started, the web client started working again.

Fortunately, this particular web client error was very simple and easy to track down, but I think it's a nice simple example of web client troubleshooting.

Off to configure Workflow!

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Who actually uses the Dynamics GP Multi-Tenant feature?

By Steve Endow

When Microsoft announced that Dynamics GP 2013 would include Multi-Tenant support, there was some buzz.  The ability to have multiple separate Dynamics GP installs on the same SQL Server instance seemed like an obviously beneficial feature, and during presentations at Tech Airlift, it was explained that the functionality was largely designed for partners looking to host Dynamics GP.

But even for GP partners who needed multiple demo environments, or consultants who needed different GP configurations on a laptop, multi-instance would seem to have some benefits, right?

Since then, I've spoken with some customers, partners, and a few GP hosting providers, and I haven't found any that use the multi-tenant feature.

Quite a while ago, I had a call with a large Dynamics hosting provider, and when I asked if they used the GP multi-tenant feature, I thought I heard a scoff as a "No" response came back immediately.  When I asked why, I was told that having a separate SQL Server instance per customer was easier for them to manage, and that the multi-tenant feature would add more complexity than benefit.  Admittedly, I'm not an expert on GP hosting, but I was surprised that the feature that was supposedly designed for GP hosting partners was completely dismissed by an actual hosting partner.

During the reIMAGINE 2014 conference last week, I attended several sessions on the new GP 2015 Service Based Architecture (SBA) functionality.  In a few of the sessions, the speaker, from Microsoft, discussed several design elements and features of SBA that existed to accommodate multi-tenancy.  One statement was along the lines of, "We did this at the request of some of our large hosting providers."  So apparently someone is using multi-tenancy?

After one of the presentations, I visited a vendor table for one of the GP hosting providers.  I asked them if they used the GP multi-tenant feature.  After double checking with an engineer at their office, the salesperson confirmed that they did not use multi-tenancy--they use a separate SQL instance for each customer.  Hmmm.

After the conference was over, I was in the palatial lobby of the Holiday Inn Fargo, and I happened to chat with someone who worked with a different Dynamics hosting provider.  You can guess what my first question was.  Once again, I was told that they also do not use the GP multi-tenant feature.  When I asked why, the explanation I received was that they regularly have partners request 'sa' access to the SQL Server (because GP often requires SQL access to fix issues, they explained), so it is easier to have a separate SQL instance to accommodate the SQL access request.

However, the person told me that they did offer GP hosting in Azure, where they do utilize the GP multi-tenant feature, but that hosting package is more limited than their internally hosted GP solution, and presumably they do not offer 'sa' or direct SQL access to the Azure customers.  Not sure how they fix GP SQL issues on Azure.

Last, during a lunch discussion at the conference, I asked a few partners if they have ever used or implemented GP multi-tenant.  One person said that they had used the feature for a customer that had two instances of GP, for two different legal entities.  The person said that it turned out to be a mistake, as they have had numerous technical issues with the multi-tenant install and will never use it again.

So I guess I'm surprised and puzzled.  GP multi-tenancy was a pretty big deal when it was announced, but if 3 large Dynamics hosting partners don't want to use it, who are these "large hosting providers" that Microsoft is working with as they invest in architecting new features to support the functionality?

Do you know of any Dynamics hosting providers who use the feature?  If so, who are they?  I'd love to chat with them.

If you are a hosting provider or partner that has chosen not to use the multi-tenant feature, why not?  What limitations or issues are causing you to avoid it?

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter

Wednesday, November 12, 2014

reIMAGINE 2014: Pushing the Boundaries of .NET Development

By Steve Endow

I'd like to thank everyone who attended the fantastic reIMAGINE conference in Fargo this week, and the brilliant Dynamics GP consultants and developers who attended the .NET Development presentation with me and Andrew Dean of Envisage Software.

As promised, here are the presentation slides and .NET sample projects that were discussed in the presentation.


Sample code:

Please note that you will need to edit some of the projects to supply your own GPConnNet license key in the DataAccess.cs class for those projects that perform data access.  And in the Bitcoin integration sample, you will need to supply your own Coinbase account information and keys.

Steve Endow is a Microsoft MVP for Dynamics GP and a Dynamics GP Certified IT Professional in Los Angeles.  He is the owner of Precipio Services, which provides Dynamics GP integrations, customizations, and automation solutions.

You can also find him on Google+ and Twitter