This technical blog will be about my adventures with Microsoft Dynamics 365 for Operations (AX7/D3fo), AX 2012, and AX 2009.
Wednesday, February 25, 2015
Are you sure that you want to cancel this operation? Keeps popping up fix
If "Are you sure that you want to cancel this operation?" keeps popping up over and over when you open AX, the fix is, when the prompt is up, press Ctrl+Pause, then click "No".
This happens to me all the time because Ctrl+Alt+Pause is a shortcut to make a remote desktop window full screen...and if AX is open and catches some of the keystrokes, it puts it in some sort of weird loop.
Monday, February 2, 2015
How to refresh AX WSDL configuration from a command prompt
My build/release process is almost entirely automated, except for one step, where we refresh the WSDL/WCF configuration. So far, I've only been able to do it conventionally with the mouse.
After getting pointed in the right direction by Martin Dráb, I wrote a little command line tool in C# that you can incorporate into your build scripts that should refresh your WCF configuration in your AXC file automatically.
It has one dependency on the AX client configuration tool obviously, which is located at:
C:\Program Files\Microsoft Dynamics AX\60\BusinessConnector\Bin\AxCliCfg.exe
Usage: RefreshAXCConfig.exe <axc file> <aos name> <WSDL Port>
Example: RefreshAXCConfig.exe C:\CUS.axc DevAOS 8101
The only caveat that I'm now realizing as of typing this up, is it uses RegEx to find/replace in the AXC file, so it requires you to have refreshed your WCF at least once, otherwise the RegEx won't find what to replace.
The C# code is simple below, and make sure to add the reference to AxCliCfg.exe. Happy DAX'ing and hopefully this helps someone. I've also saved the ZIP'd executable to my OneDrive. You will need to copy the AxCliCfg to the same local directory in order for it to work.
Link to compiled zipped executable for those who don't feel like typing up themselves.
After getting pointed in the right direction by Martin Dráb, I wrote a little command line tool in C# that you can incorporate into your build scripts that should refresh your WCF configuration in your AXC file automatically.
It has one dependency on the AX client configuration tool obviously, which is located at:
C:\Program Files\Microsoft Dynamics AX\60\BusinessConnector\Bin\AxCliCfg.exe
Usage: RefreshAXCConfig.exe <axc file> <aos name> <WSDL Port>
Example: RefreshAXCConfig.exe C:\CUS.axc DevAOS 8101
The only caveat that I'm now realizing as of typing this up, is it uses RegEx to find/replace in the AXC file, so it requires you to have refreshed your WCF at least once, otherwise the RegEx won't find what to replace.
The C# code is simple below, and make sure to add the reference to AxCliCfg.exe. Happy DAX'ing and hopefully this helps someone. I've also saved the ZIP'd executable to my OneDrive. You will need to copy the AxCliCfg to the same local directory in order for it to work.
Link to compiled zipped executable for those who don't feel like typing up themselves.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.IO; using System.Xml; using Microsoft.Dynamics.Configuration; namespace RefreshAXCConfig { class Program { static void Main(string[] args) { Tuple<Guid, string> result; string axcFile; string strAOS; int intWSDLPort; if (args.Length == 0) { Console.WriteLine("Usage: RefreshAXCConfig.exe <axc file> <aos name> <WSDL Port>"); Console.WriteLine("Example: RefreshAXCConfig.exe CUS.axc Dev-vwaos05 8101"); return; } try { axcFile = args[0]; strAOS = args[1]; if (int.TryParse(args[2], out intWSDLPort) == true) { result = FormRegenerateWcfDialog.GetConfigurationAsString(strAOS, intWSDLPort); XmlDocument xmlDoc = new XmlDocument(); xmlDoc.LoadXml(result.Item2); File.WriteAllText(axcFile, Regex.Replace(File.ReadAllText(axcFile), @"<\?xml.*\</configuration\>", xmlDoc.InnerXml)); } } catch (Exception e) { Console.WriteLine("Error encountered: {0}", e.Message); } return; } } }
Thursday, January 15, 2015
How to extend TFS and create a bug/workitem from AX 2012 X++!
This is a sample job that shows how to create a bug in TFS from AX by extending Team Foundation Server using the available TFS assemblies.
You need to add two references to the TFS assemblies.
First copy these files to your client bin direcotry (C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin):
Please also note the couple comments as they will explain a little more.
You need to add two references to the TFS assemblies.
First copy these files to your client bin direcotry (C:\Program Files (x86)\Microsoft Dynamics AX\60\Client\Bin):
- C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.WorkItemTracking.Client.dll
- C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Client.dll
Then in the AOT, on the References node, right click and click "Add Reference". Then choose "Browse" and navigate to these two files.
Then if you have Team Foundation Server setup as your Version Control System in AX, you can just run this job and it'll create a test bug! If you have TFS somewhere else, you can just adjust the job some.
I also showed how to enumerate allowed fields, validate before saving the bug, etc. I have a more complicated class that I wrote that does more error handling, but I tried to keep this as simple as possible for demo purposes.
I currently haven't quite figured out how I want to use this yet. I was thinking of creating a new MenuItemButton on the infolog form that a select set of users would have security to. And if an error was present in the infolog, the user could click "Submit Bug". Still thinking of ideas.
Please also note the couple comments as they will explain a little more.
Good luck, happy New Year, and happy DAXing!
static void JobCreateTFSBug(Args _args) { Microsoft.TeamFoundation.Client.TfsTeamProjectCollection tfs; Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore store; Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemTypeCollection witc; Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemType wit; Microsoft.TeamFoundation.WorkItemTracking.Client.Project project; Microsoft.TeamFoundation.WorkItemTracking.Client.ProjectCollection projectCollection; Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItem workItem; SysVersionControlParameters parameters = SysVersionControlParameters::find(); System.Boolean netBool; System.Collections.ArrayList invalidFields; System.Int32 netInt; Microsoft.TeamFoundation.WorkItemTracking.Client.Field field; Microsoft.TeamFoundation.WorkItemTracking.Client.AllowedValuesCollection allowedValues; System.String netStr; str s, s2; int retVal; int i, n; int arrayCount, arrayCount2; try { tfs = Microsoft.TeamFoundation.Client.TfsTeamProjectCollectionFactory::GetTeamProjectCollection(Microsoft.TeamFoundation.Client.TfsTeamProjectCollection::GetFullyQualifiedUriForName(parameters.TfsServer)); store = new Microsoft.TeamFoundation.WorkItemTracking.Client.WorkItemStore(tfs); projectCollection = store.get_Projects(); project = projectCollection.get_Item(parameters.TfsProject); witc = project.get_WorkItemTypes(); wit = witc.get_Item('Bug'); workItem = wit.NewWorkItem(); workItem.set_Title("Bug Title"); workItem.set_Description("Bug description"); // This is how you set a custom field //workItem.set_Item('CustomField', 'CustomData'); // These two lines are equivalent // workItem.set_Item('Assigned To', 'AlexOnDAX'); // This is the same as the line below workItem.set_Item(Microsoft.TeamFoundation.WorkItemTracking.Client.CoreField::AssignedTo, 'AlexOnDAX'); netBool = workItem.IsValid(); if (netBool.Equals(false)) { setPrefix("Error creating work item"); invalidFields = workItem.Validate(); netInt = invalidFields.get_Count(); arrayCount = netInt; for (i=0; i<arrayCount; i++) { field = invalidFields.get_Item(i); s = field.get_Name(); s2 = field.get_Value(); error(strFmt("Error creating work item\tField '%1' with value '%2' is invalid", s, s2)); allowedValues = field.get_AllowedValues(); netInt = allowedValues.get_Count(); arrayCount2 = netInt; for (n=0; n<arrayCount2; n++) { netStr = allowedValues.get_Item(n); s = netStr; warning(strFmt("Error creating work item\tAllowed values\t %1", s)); } } throw Exception::Error; } else { workItem.Save(); netInt = workItem.get_Id(); retVal = netInt; } } catch { error(strFmt("@SYS343139", parameters.TfsServer)); } info(strFmt("Created bug %1", retVal)); }
Monday, September 8, 2014
Removing diacritics (accents on letters) from strings in X++
If you want to remove diacritics (accents on letters) from strings like this "ÁÂÃÄÅÇÈÉàáâãäåèéêëìíîïòóôõ£ALEX" to use the more friendly string "AAAAAACEEaaaaaaeeeeiiiioooo£ALEX", you can use this block of code:
I did not come up with this code, I merely adapted it from http://www.codeproject.com/Tips/410074/Removing-Diacritics-from-Strings who adapted it from somewhere another person who deleted their blog. It is still very useful.
static void AlexRemoveDiacritics(Args _args) { str strInput = 'ÁÂÃÄÅÇÈÉàáâãäåèéêëìíîïòóôõ£ALEX'; System.String input = strInput; str retVal; int i; System.Char c; System.Text.NormalizationForm FormD = System.Text.NormalizationForm::FormD; str normalizedString = input.Normalize(FormD); System.Text.StringBuilder stringBuilder = new System.Text.StringBuilder(); for (i = 1; i <= strLen(normalizedString); i++) { c = System.Char::Parse(subStr(normalizedString, i, 1)); if (System.Globalization.CharUnicodeInfo::GetUnicodeCategory(c) != System.Globalization.UnicodeCategory::NonSpacingMark) { stringBuilder.Append(c); } } input = stringBuilder.ToString(); input = input.Normalize(); retVal = input; info(strFmt("Before: '%1'", strInput)); info(strFmt("After: '%1'", retVal)); }
I did not come up with this code, I merely adapted it from http://www.codeproject.com/Tips/410074/Removing-Diacritics-from-Strings who adapted it from somewhere another person who deleted their blog. It is still very useful.
Thursday, August 28, 2014
HowTo: Find out how long your AOS Service has been running through PowerShell
If you want to check when you last restarted your AOS service, you can just run the powershell command:
Get-Process Ax32Serv | % {new-TimeSpan -Start $_.StartTime} | select Days,Hours,Minutes,Seconds
Tuesday, August 12, 2014
How to get/set printer settings in AX 2012 for SRS reports
This is a simple job that shows you how to get/set printer settings in AX 2012. In AX 2009, I used things like PrintJobSettings and SysPrintForm where in AX 2012 you use SRSPrintDestinationSettings which uses SysOperationsTemplateForm.
This is just a "Hello World" if you will for modifying the print settings in AX 2012 and I'll be posting a follow up with a slightly more advanced example.
This is just a "Hello World" if you will for modifying the print settings in AX 2012 and I'll be posting a follow up with a slightly more advanced example.
static void GetPrinterSettingsAX2012Simple(Args _args) { SRSPrintDestinationSettings printSettings = new SRSPrintDestinationSettings(); SRSPrintDestinationSettingsContainer printerNameDestination; // This sets what the user will see defaulted printSettings.printMediumType(SRSPrintMediumType::Printer); if (SrsReportRunUtil::showSettingsDialog(printSettings)) { printerNameDestination = SrsReportRunUtil::getPrinterNameDestination(printSettings); if (printerNameDestination != conNull()) { info(strFmt("Printer Name: %1", conPeek(printerNameDestination, 1))); info(strFmt("Printer Destination: %1", conPeek(printerNameDestination, 2))); } } else info("User clicked cancel"); }
Friday, August 8, 2014
AX 2012 TFS: Solving update conflicted FK_ModelElementData_HasModelId_LayerId and XU_Update error with SQL profiler
When using AX 2012 with TFS, sometimes you'll get a cryptic error during a TFS synchronization like this:
SQL error description: [Microsoft][SQL Server Native Client 10.0][SQL Server]The UPDATE statement conflicted with the FOREIGN KEY constraint "FK_ModelElementData_HasModelId_LayerId". The conflict occurred in database "Dev5_AX2012_model", table "dbo.Model".
SQL statement: { CALL [Dev5_AX2012_model].[dbo].[XU_Update](?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) }
Cannot execute a stored procedure.
And that's hardly enough information to solve it.
Most likely cause of error for those who don't want to read the entire article:
You probably have a USR layer (or some other layer) that was mistakenly created by any number of things that you should delete.
How to identify/solve:
First, I have to give credit to this post by Fred Shen that got me started down the right path. He received the same FK_ModelElementData_HasModelId_LayerId error, but with a different root cause. I couldn't use his steps verbatim though because my TFS sync would take 30+ minutes and that would generate tons of SQL profiler data that I couldn't easily sift though.
- Find the error code (547 for me). SystemAdministration>Inquiries>Database>SQL statement trace log
- Launch SQL Profiler and connect to the SQL server
- Create new trace, name it whatever you'd like, set a stop time just in case you leave it running, then click on "Events Selection" tab
- Uncheck everything
- Check "Show all events" and "Show all columns"
- Under "Errors and Warnings" check "Exception"
- Under "Stored Procedures" check "SP:Starting"
- Verify for both of these rows that the columns "TextData", "DatabaseName", and "Error" (where applicable) are checked
- Click column filters and on DatabaseName, put your database name or %DBName% for wildcards
- Click on the Error filter and put the error code from step 1 (547 in my case)
- Lastly, click on TextData and put in "%XU_Update%" and "%FOREIGN KEY%"
- Run it, then execute a TFS sync or whatever it is you do to cause the exception to be thrown in AX.
- Stop it after you receive the exception and you should see a bright red "Exception" in the profiler.
- Press Ctrl+F, and type "exception" and choose the column "EventClass" to search and it'll help you get right to the bad call
Hopefully this helps somebody identify exactly what is throwing their error!
Subscribe to:
Posts (Atom)















