Thursday, August 30, 2018

System can't cast 'LedgerJournalEngine)' to 'LedgerJournalEngine_VendInvoice' in Batch

I came across an issue recently where my Timesheets wouldn't post in 'Batch'.

It turns out that it wouldn't perform the following code in 'Batch', but would be fine doing it in the Client.

LedgerJournalEngine_VendInvoice         ledgerJournalEngine;
ledgerJournalEngine = LedgerJournalEngine::construct(LedgerJournalType::VendInvoiceRegister);

If we go to the 'construct' method, we will see it returns the 'default' in the switch case:

default :
            ledgerJournalEngine = new LedgerJournalEngine(_formRun);

When running this in the client, it works fine.  When running it in 'Batch' on the server, it fails:

Unable to cast object of type 'Dynamics.Ax.Application.LedgerJournalEngine' to type 'Dynamics.Ax.Application.LedgerJournalEngine_VendInvoice'.

This does make sense that you can't cast a 'Child' class to it's 'Parent', however, why would this work on the Client but not in Batch?

UPDATE:

The answer here is that in X++, this is allowed.  Thus, the client works.
In CIL, it is a bit more strict and it is not allowed, therefore it fails in 'Batch'

Simple solution is to just make this 'LedgerJournalEngine'.  That is the type that is being returned anyway so it works just fine.

Monday, August 20, 2018

AX 2012 Enterprise Portal - Server error in '/' Application

After performing a code deployment (modelstore import), we attempted to update our 2 EP Websites with:
axupdateportal -updateall -websiteurl https://mySite.mydomain.com/Sites/DynamicsAX
With each one having it's own 'mysite' address.
1 of our sites worked perfectly, however, the 2nd site wouldn't allow axupdateportal to run due to this error:
The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:10:00'. ---> The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:10:00'. ---> The read operation failed, see inner exception. ---> The socket connection was aborted. This could be caused by an error processing your message or a receive timeout being exceeded by the remote host, or an underlying network resource issue. Local socket timeout was '00:10:00'. ---> An existing connection was forcibly closed by the remote host

When navigating to the site this is what we see:

If you could scroll all the way to the bottom, it would seem that ALL 'Proxies' are showing the same error of:
CS0234: The type or namespace name 'AX' does not exist in the namespace 'Microsoft.Dynamics' (are you missing an assembly reference?)
After doing some reasearch, I found this post and video. This video turned me on to my web.config file which had the same problem as in the video.  My web.config file had NO reference to Dynamics.  
Thankfully, I had a backup of this file from a few days prior.  Once I put the correct web.config file in worked perfectly.
However, I am still unsure about the 'socket' error I was getting when trying to use AxUpdatePortal... To be continued...


Thursday, August 16, 2018

AxUpdatePortal 'Document Moved' error

When trying to run AxUpdatePortal -UpdateUrl -websiteurl https://myWebsite.domain.com/Sites/DynamicsAx I was receiving the following error:


System.Net.WebException: The request failed with the error message:
--
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found <a HREF="https://uat-ep01.vipernet.net/_layouts/EPDeploymentService/EPDeploymentService.asmx">here</a></body>
--.
   at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
   at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
   at Microsoft.Dynamics.Framework.Deployment.Services.EPDeploymentService.DeployEnterprisePortal(String virtualServer)
   at AxUpdatePortal.Program.Deploy(String[] args, String webSiteUrl)
   at AxUpdatePortal.Program.Main(String[] args)

This simply ended up being the wrong 'domain.com'.  Once I put in the correct domain, all was well.

Wednesday, August 8, 2018

First record in 'RecordInsertList' had incorrect company

We recently had a situation where (Long story short...) the first record from a 'RecordInsertList' was showing the data area id of the batch job it was run under and the other 3 were correctly showing the company from 'changeCompany()'.

Here is the original code (From a 3rd party):

 MyTable myTable;
 RecordInsertList myRecordInsertList;
 myRecordInsertList= new RecordInsertList(myTable.TableId);
 while (myEnumerator.moveNext())
 {
    [Get the company you need]
    changeCompany([company])
    {
      myTable.Field1 = field1
      ....
      myTable.Insert();
    }
 }
 
The first record, in some instances, will have the data area id that doesn't match what you changed it to in 'changeCompany'.  Very interesting.  This was causing some other functionality to fail as it was doing a 'select' on myTable but not cross company.

Here is the solution:

changeCompany([comapny])
{
   myTable = null;
   myTable.Field1 = field1
   ....
   myTable.Insert();
 }

This fixes the problem.  I suspect that the 'mytable.TableId' might be instantiating the myTable buffer 'DataAreaId' and it doesn't ever get corrected.
On top of the above fix, I would also do:

myRecordInsertList = new RecordInsertList(tableNum(MyTable));

I don't know if this would fix the problem (I suspect it would), however, it seems to be a better to handle this.

UPDATE:
After running some tests, I have confirmed that 'tableNum(Mytable)' fixes the issue.  When you do 'myTable.TableID', it instantiates the table buffer with the curExt() in 'dataArea'.  As above, when you continue on to filling the fields in the table, the 'dataArea' is wrong.

I think one could use either myTable = null or myTable.Clear() so long as the 'clear()' method is called after the 'changeCompany()'

Special thanks to Ben for helping me out with this one.

WCF 'The server has rejected the client credentials'

We are working through a request where our homegrown app is going to be on a different domain than AX.  Up until now, they have been on the same domain.

When testing our WCF connection into our inbound port into AX, we kept getting 'The server has rejected the client credentials'. 

I decided to write a small .NET console app to test and see if I could duplicate this error:

MyServiceReference.MyAXWCFService service = new MyServiceReference.MyAXWCFService();
service.ClientCredentials.UserName.UserName = "myUser@domain.com"
service.ClientCredentials.UserName.Password = "IncorrectPassword"
...
[Call methods from AX]
...

Wierdly, this worked, even though I have an incorrect password. 
After researching I found that it was using the windows credentials of my user that I used to log on to the machine to use VS 2015.

To do this correctly you need do the following:

service.ClientCredentials.Windows.ClientCredential.UserName = "myUser@domain.com"
service.ClientCredentials.Windows.ClientCredential.Password = "IncorrectPassword"

The 'Windows.ClientCredential' is what we need to use to set the Windows Credentials.  When you do this, you will then get the 'The server has rejected the client credentials' error. 

We could then specify the correct credentials in our homegrown app code, on a different domain and it will successfully connect into AX.

Hard coding a username and password like this isnt' the best idea, however, for testing purposes it does show that we can get our WCF across different domains.