středa 2. prosince 2009

Powershell remoting

V posledních týdnech pracuji spíše okolo Axapty než přímo v ní a v podobném duchu je i tento příspěvek. Jednou z věcí, kterými se zabývám, je totiž automatizace správy Dynamics AX prostředí, zejména instalace programových úprav. PowerShell je pro to ideální nástroj a funkce pro práci po síti - "remoting" - jsou velice potřebné, protože i jednoduchá migrace mezi dvěma Dynamics AX prostředími typicky vyžaduje práci na několika serverech. Nasazování úprav se skládá z mnoha kroků - například zastavování a spouštení AOS, kopírování souborů (vrstev, labelů), importy, kompilace a podobně. Automatizace nejen že sníží čas, který je třeba věnovat celému nasazování, ale sníží i chybovost při práci se soubory a minimalizuje dobu odstávek prostředí. PowerShell remoting v tom může pomoci tak, že celý proces lze řídit z jednoho místa - spravovat služby na vzdálených počítačích, spouštět aplikace, pracovat se soubory, přistupovat k registrům a tak dále. To vše velmi pohodlně a s plnou podporou .NET typů. Na Microsoft Festu 2009 jsem se dozvěděl, že mnoho lidí naráží při pokusech o konfiguraci PowerShell remotingu na problémy, zkusím tedy popsat mé zkušenosti. Musím rovnou říct, že já jsem na žádné příliš závažné problémy nenarazil, tak snad budete stejně úspěšní. První věc, kterou budete potřebovat, je PowerShell verze 2.0. Oproti verzi 1.0 obsahuje řadu nových funkcí, hlavně ale ten zmiňovaný remoting. PowerShell 2.0 je již obsažen v systémech Windows Server 2008 R2 a Windows 7, může ale být samozřejmě nainstalován i do starších systémů a to jako součást Windows Management Frameworku (odkaz obsahuje podrobnější informace včetně podporovaných systémů). Osobně používám PowerShell na WS2008 SP1 a WinXP SP3. Windows Management Framework tedy stáhněte a nainstalujte na všechny počítače, kde chcete PowerShell (i jen vzdáleně) využívat (a pokud nejde o systém, kde již je obsažen). Dále je třeba povolit remoting a to nejlépe pomocí příkazu:
Enable-PSRemoting
Tento příkaz spustí (a nakonfiguruje) službu WinRM, připraví listener očekávající vzdálené příkazy a vytvoří odpovídající pravidlo na firewallu. Toto musí být provedeno jak na serveru, tak i na klientském počítači. Na klientech jsem dále musel změnit konfiguraci sdílení:
Set-ItemProperty –Path HKLM:\System\CurrentControlSet\Control\Lsa –Name ForceGuest –Value 0
a přidat server mezi důvěryhodné. K tomu lze využít následující příkaz:
Set-Item WSMan:\localhost\Client\TrustedHosts –Value MujServer -Force -Concatenate
A to bylo v mém případě vše. :-) Pokud takové štěstí mít nebudete, zkuste se podívat nejprve na about_Remote_Troubleshooting a příbuzná témata, kde je mnoho možných problému popsáno. Off-line můžete zobrazit lokální podobu nápovědy takto:
Get-Help about_Remote_TroubleShooting
Konkrétnímu využití pro nasazování Dynamics AX se budu věnovat někdy v blízké budoucnosti. Dnes uvedu jen jeden jednoduchý příklad - spuštění AOS číslo 2 na vzdáleném stroji MujServer:
$aosService = (Get-Service -Name 'AOS50$02' -ComputerName MujServer)
$aosService.Start()
$aosService.WaitForStatus("Running")
Triviální, nemyslíte?

středa 28. října 2009

Nová kniha o Dynamics AX

Další kniha o programování v Dynamics AX je na cestě, konkrétně jde o Microsoft Dynamics AX 2009 Programming: Getting Started. Předpokládané vydání v prosinci, ale již nyní je možné objednávat. Bohužel nevím o obsahu nic víc, než co najdete na uvedeném odkazu.

sobota 24. října 2009

Generování přístupových metod

Vytváření přístupových metod (tzn. metod zpřístupňujících neveřejné členy tříd) je velmi častá činnost. Členské proměnné tříd totiž nejsou přímo přístupné pro čtění či zápis a je proto nezbytné vytvořit metody, která vrátí či nastaví hodnotu dané proměnné. Díky tomuto řešení lze například zcela odstranit proměnnou a nahradit ji nějakým výpočtem, aniž by bylo třeba provádět změny mimo danou třídu. Přístupové metody mají obvykle prefix get (metoda pro čtení) nebo set (pro zápis), v AX se typicky kombinují do jediné metody s prefixem parm, která slučuje obě funkce. (V AX se používá několik přístupů - get metody jsou většinou zcela bez prefixu, někdo naopak propaguje používání prefixu parm i pro metody jen pro čtení či jen pro zápis atd.) Šablona parm metody V Dynamics AX si lze psaní přístupových metod zjednodušit pomocí šablon metod. V editoru otevřte Scripts > template > method > parm, případně použijte sekvenci zkratek "Alt+R" (Alt+M ve starších verzích) "S" "T" "M" "P". Do dialogu zadáte typ a název proměnné a po potvrzení bude vygenerovaný kód vložen na pozici kurzoru. Stále to ale není "ono". Je třeba vytvořit metodu, vymazat její obsah, ale zejména vědět typ a název proměnné. S jednou metodou se člověk vypořádá snadno, ale má-li jich vytvářet několik desítek, rázem vidí tento problém v jiném světle. Musí hledat deklarace požadovaných proměnných, vytvářet metody, kopírovat typy a názvy a tak dále. To je neproduktvní a stereotypní činnost, která volá po automatizaci. Generátor Proto jsem vytvořil generátor přístupových metod, který umí o něco víc. Konkrétně:
  • zobrazí členské proměnné dané třídy (formuláře, datasetu apod.) včetně zděděných a umožní vybrat, pro které budou vytvořeny přístupové metody
  • tento seznam je možné filtrovat
  • umožňuje nastavit, zda vygenerovaná metoda bude určena pro čtení, zápis nebo obojí
  • umožňuje změnit vygenerovaný název proměnné a parametru
V praxi to vypadá takto: Po potvrzení zadání se zobrazí infolog s výsledky generování. Z něj lze dvojklikem otevřít metodu v editoru. Existující metody nejsou přepsány. Pár poznámek k implementaci
  • Vývoj i testování generátoru proběhly v AX2009.
  • Potřebujete-li změnit vytváření výchozích názvů metod a parametrů, změňte metody initMethodName() a initParameterName() na tabulce TmpDevAccessorMethod.
  • Pokud v dialogu měníte hodnoty checkboxů Read a Write, mění se i prefix v názvu metody. Jakmile však zadáte svůj název, změny Read/Write na něj nemají vliv.
  • Vygenerované metody nepoužívají prmIsDefault(), což může být v některých případech problém. Bohužel, v tuto chvíli vám nezbývá než modifikovat vygenerovanou metodu ručně. Mám tuto vlastnost v "Nice to have". :-)
Integrace do kontextové nabídky Intergrace do kontextového menu je velmi prostá, stačí:
  1. Přidat do menu
  2. Určit, u kterých elementů bude tato volba dostupná (
První krok znamená jen přetáhnout menu item (DevAccessorMethodsGenerator) do menu SysContextMenu. Druhý vyžaduje změnu ve třídě SysContextMenu, metodě verifyItem(). Do větve MenuItemType::Action přidejte následující kód, který zajistí zobrazení jen u podporovaných typů:
case menuitemActionStr(DevAccessorMethodsGenerator):
    if (this.selectionCount() == 1
        && !firstNode.AOTIsOld()
        && DevAccessorMethodsGenerator::isSupportedTreeNode(firstNode))
  {
      return 1;
  }
  return 0;
Zpětná vazba Připomínky jsou vítané, hlášení chyb vyžadované. :-) Download Generátor přístupových metod (AX2009)

neděle 11. října 2009

Otevírání formulářů v hlavním okně

Na AxForu jsem narazil na nápad změnit chování AX2009 tak, aby se formuláře otevíraly vždy v hlavním okně (originální post) a ne v oknech samostatných (tedy aby se chovaly stejně jako v dřívějších verzích). Já jsem si to ještě rozšířil o ListPages a dostal jsem tak všechny formuláře pod kontrolu Tabaxu. Toto uspořádání mi vyhovuje daleko více než to standardní. Potřebuji-li pracovat s příliš mnoha okny, otevřu si další workspace a v každém workspace pak udržuji související okna. Nemusím tak řešit chaos na taskbaru pokud například pracuji ve více prostředích a společnostech. Programová úprava je jednoduchá - do SysSetupForm.init() před super() jsem přidal:
if (this.form().design().windowType() == FormWindowType::Standard
    || this.form().design().windowType() == FormWindowType::ListPage)
{
   this.form().design().windowType(FormWindowType::Workspace);
}
Prosté a efektivní. Tak to má být. :-)

sobota 10. října 2009

Překlad X++ do MSIL

Před pár dny jsem konečně našel čas a podíval se na video Peter Villadsen and Gustavo Plancarte: X++ to MSIL z Channel9. A musím říct, že opravdu stojí za zhlédnutí. V krátkosti tam lidé z X++ teamu popisují, proč a jak vytvořili překlad z mezijazyka AX do MSIL (Microsoft Intermediate Language - do něj jsou překládány všechny .NET jazyky). Dále také ukazují debugging X++ v prostředí Visual Studia a na závěr připouští možnost rychlého opuštění X++. A upřímně, ty možnosti jsou natolik lákavé, že to podle mého názoru sotva může v budoucnu dopadnout jinak. Špičkové vývojové prostředí, mj. také jednotné prostředí (když se ve VS už vyvíjí EP, reporty, workflow…), pohodlná integrace, testovací nástroje, plné využití TFS… Vůbec jsem netušil, že se do tohoto překladače Microsoft už pustil, natož že ho má hotový. Udělali mi velkou radost. :-)

pátek 9. října 2009

Zobrazení názvu reportu

Na úvod malé vysvětlení, proč jsem se v poslední době poněkud odmlčel. Absolvoval jsem totiž stěhování a až dnes mě připojili k internetu, no a na novém projektu se také nenudím :-). Nicméně na pár zajímavých věcí jsem narazil, snad z toho dám něco v nejbližších dnech do zveřejnitelné podoby. Začnu tou nejčerstvější věcí. Dnes jsme řešili, jak nesnáze získat AOT jméno reportu (tiskové sestavy) vytištěné na obrazovku. Zkrátka máte na obrazovce report, chcete jej editovat/prozkoumat implementaci a nevíte, jak ho vlastně najít v AOT. Možnosti samozřejmě existují, ale nejsou příliš pohodlné. (Tedy pokud o nějaké víte, dejte vedět!) Já jsem zvolil řešení, které sice vyžaduje programovou úpravu, ale jeden řádek není zas tolik. ;-) Do titulku okna reportu jsem přidal jméno reportu - stačí k tomu drobná úprava metody createReportViewer() ve třídě ClassFactory:
public ReportViewer createReportViewer(
    PrintJobHeader  _jobsCursor,
    PrintJobPages   _pagesCursor,
    ReportRun       _reportRun = null)
{
    ReportViewer ret;

    ret = super(_jobsCursor, _pagesCursor, _reportRun);
    ret.description(strFmt("%1 (%2)", ret.description(), _reportRun.name()));
    return ret;
}
A nezbytná ukázka výsledku:

čtvrtek 3. září 2009

Nasazování úprav pomocí PowerShellu

Nejdřív bleskově pár slov o PowerShellu. PowerShell je (relativně) nový shell, tedy příkazová řádka pro Windows. Je objektový, je postaven na .NET a dobře si rozumí s mnoha komponentami Windows. Je součástí nových Windows (7, 2K8R2) a do starších lze doinstalovat. Vyskytuje se ve dvou hlavních verzích (1 a 2), které se pochopitelně liší funkcionalitou. Detailnější popis není předmětem tohoto postu, zájemcům doporučuji několik odkazů níže. Při nasazování úprav je potřeba udělat spoustu kroků - zastavit AOS, překopírovat vrstvy, labely, spustit AOS… Přímo si to říká o nějakou automatizaci. A PowerShell je pro tento úkol velmi vhodný nástroj. Připravil jsem jeden skript, který ukazuje některé možnosti PowerShellu využitelné pro nasazování úprav v AX. Jde o PowerShell 1.0 a AX2009. Pro AX4 by neměly být třeba žádné změny, u AX3 je situace složitější - například v tom, že AOS v AX3 nemá podobu Windows služby. Nápad volat business connector přímo z PowerShell skriptu jsem si vypůjčil odtud. Věřím, že komentáře v kódu jsou dostačující pro pochopení záměru:
#deklarace proměnných
$aosServiceName = "AOS50`$01"
$axPath = "C:\Program Files\Microsoft Dynamics AX\50"
$axApplPath = "$axPath\Application\Appl\DAX5"

#logování výstupu skriptu do souboru v aktuálním adresáři
$scriptLogName = Get-Date -f "dd-MM-yyyy"
Start-Transcript "$scriptLogName.log" -append -force

#start AOS (pokud neběží)
Start-Service $aosServiceName

#zalogování do AX pomocí business connectoru
[reflection.Assembly]::Loadfile("$axPath\Client\Bin\Microsoft.Dynamics.BusinessConnectorNet.dll")
$ax = New-Object Microsoft.Dynamics.BusinessConnectorNet.Axapta
$ax.logon("","","","")

#výpis počtu sessions (jen pro ukázku)
Write-Host "Sessions:" $ax.CallStaticClassMethod("xSession", "numSession")

#nalezení logovacího souboru kompilace (bude třeba později)
$logFile = Join-Path $ax.CallStaticClassMethod("xInfo", "AOTLogDirectory") "AxCompileAll.html"

#odhlášení z AX
$ax.logoff()

#zastavení AOS, zkopírování souborů, smazání indexů a opětovné spuštění AOS
Stop-Service $aosServiceName
copy "somewhere\*.aod" $axApplPath  #kopírování vrstev
copy "somewhere\*.ald" $axApplPath  #kopírování popisků
rm "$axApplPath\*.ali"              #smazání indexů popisků
rm "$axApplPath\axapd.aoi"          #smazání aplikačního indexu
Start-Service $aosServiceName

#kompilace aplikace
$proc = New-Object System.Diagnostics.Process
$proc.StartInfo.FileName = "$axPath\Client\Bin\Ax32.exe"
$proc.StartInfo.Arguments = "-startupCmd=compileall"
$proc.Start()
$proc.WaitForExit()

#otevření logu kompilace v prohlížeči
Invoke-Item $logFile
Po smazání aplikačního indexu (.aoi) se AOS spouští velmi dlouho, protože vytváří nový index. Kompilaci jsem chtěl původně řešit jako volání:
$ax.CallStaticClassMethod("SysCompileAll","compile")
ale ukázalo se to jako dost nešťastný nápad. Kompilace proběhla, ale ne příliš úspěšně. AX například hlásila chybějící inicializace globálních proměnných (např. infolog), což mě sice pobavilo, nicméně jsem chtěl prostředí ještě někdy používat a musel jsem ho znovu zkompilovat, tentokrát klasicky přes klienta. Ačkoli PowerShell není můj denní chleba a mé příležitostné psaní skriptů zahrnuje jistou dávku objevování, obětovaný čas se rychle vrátí. Navíc člověk dříve nebo později udělá chybu (a třeba smaže jiný soubor než zamýšlel), odladěný skript chyby nedělá. Nicméně skript je program jako každý jiný, je ho tedy třeba otestovat atd. Odkazy: PowerShell homepage PowerShell downloads (na PowerShell blogu) Windows PowerShell 1.0 Documentation Pack Scripting with Windows PowerShell (TechNet) Pokud PowerShell neznáte a chystáte se ho používat, rozhodně se podívejte po vhodném IDE, třeba: PowerGUI PowerShell Analyzer

neděle 23. srpna 2009

EP: X++ Web UI Framework končí

Ve starších verzích AX se webové uživatelské rozhraní vytváří v AOT pomocí WebForms apod. V AX2009 se objevil nový přístup a to vytváření komponent v ASP.NET (a mapování na DataSets v AOT). Tento nový přístup má být v nové verzi AX jediný možný - a bude tedy třeba zmigrovat existující implementace postavené na původním frameworku. Převzato z: Dilip's blog

The records buffer is NULL

Tento příspěvek dokumentuje jedno ne zrovna intuitivní chování Axapty. Vezměme následující jednoduchou třídu:
class Test
{
    public server static void main(Args args)
    {
        Test::recordOnClient();
    }

    public client static InventTable recordOnClient()
    {
        InventTable inventTable;
        select firstOnly forUpdate inventTable;
        return inventTable;
    }
}
Tento kód (respektive pokus o vrácení hodnoty z metody recordOnClient()) vyhodí run-time výjimku Error executing code: The record buffer is NULL. Testováno v AX2009, AX3 jednoduše spadne (AX4 nemám po ruce). Právě vytvořením kódu sestřelujícího Axaptu 3 toto chování jeden můj kolega objevil. Zajímavé je, že se tak děje pouze při volání client metody ze serveru a pokud metoda vrací buffer vybraný pro update. Všechny ostatní scénáře skončily bez chyby. Doufal jsem, že se mi na základě chybové hlášky podaří najít více informací, ale nebyl jsem úspěšný. Zřejmě se to moc často vytvořit nepovede. Doplnění: Pokud je na bufferu volán insert(), dostane buffer příznak forUpdate. Výše popsané chování tedy platí i v takovém případě.

Convergence 2009 Europe

Convergence je oficiální akce Microsoftu na téma Dynamics. Původně plánovaná celoevropská konference byla rozdělena do čtyř měst takto: 27.10.2009 Londýn 29.10.2009 Vídeň 03.11.2009 Frankfurt 05.11.2009 Rotterdam Registrace začíná 1.9.2009, cena pro zákazníky je 150€, pro partnery dvojnásobek. Záznamy z akce pak budou přístupné nejen účastníkům, ale i všem partnerům a zákazníkům s BREP (Business Ready Enhancement Plan). Oficiální stránky: Convergence 2009 Europe Další info, vč. Breakout Sessions (PPT): Partner Update 20.8.2009

sobota 22. srpna 2009

Iterator vs. Enumerator

Pro procházení kolekcí lze v Axaptě využít dvě třídy - Iterator a Enumerator. Respektive, pro každou kolekci existuje specializovaný iterátor a enumerátor, např. SetIterator a SetEnumerator. Použití iterátoru vypadá takto:
SetIterator iterator = new SetIterator(set);
while (iterator.more())
{
    info(iterator.value());
    iterator.next();
}
…a enumerátoru takto:
SetEnumerator enumerator = set.getEnumerator();

while (enumerator.moveNext())
{
    info(enumerator.current());
}
Je best practice používat enumerátor namísto iterátoru. O tomto doporučení vím již dlouho, ale až tento týden jsem se dozvěděl jeden zásadní rozdíl: volání iterátoru totiž selže, pokud jsou iterátor a iterovaná kolekce na jiné vrstvě (ve smyslu klient/server). V takovém případě je vyhozena run-time výjimka s tím, že objekt iterátoru není inicializován. Enumerator s touto situací počítá a vznikne na stejné vrstvě jako kolekce. Procházení všech prvků kolekce umístěné na jiné vrstvě zas může být výkonnostní problém, ale to už je jiná kapitola… MSDN: ListEnumerator MSDN: ListIterator MSDN: MapEnumerator MSDN: MapIterator MSDN: SetEnumerator MSDN: SetIterator

čtvrtek 20. srpna 2009

AxDecisions 2009

Virtuální konference jsou čím dál oblíbenější - je to zejména daleko lacinější varianta než "fyzická" konference. AX Decision 2009 je další taková virtuální konference a jak název naznačuje, půjde o Dynamics AX. Bude se konat 14.10.2009 - více informací je k dispozici na webu AxDecisions. Z čistě vývojářského hlediska není zveřejněný program nijak lákavý, ale pro přehled o trendech a možných přístupech by mohl posloužit dobře. Za tu cenu… (je zdarma) PS: Koho zajímá, jaktože je konference zdarma, doporučuji standardní postup: podívejte se, jak je prezentována potenciálním sponzorům. :-)

AxAssist

AxAssist je bezpochyby jeden z nejužitečnějších nástrojů, které jsou pro vývoj v Dynamics AX k dispozici. Není sice zdarma, ale přináší mnoho skvělých funkcí za rozumné peníze. Navíc je k dispozici třicetidenní zkušební verze, takže každý má možnost si AxAssist důkladně osahat. Hned na úvod odkáži na oficiální stránky (AxAssist.com), protože je tam většina funkcí popsána a nechybí flashová videa, která přiblíží chování AxAssistu asi lépe než cokoli jiného. Mým cílem tedy není popsat všechna nastavení atd., spíše rychle prolétnout všechny funkce a podívat se na pár praktických zkušeností. Jen jeden obrázek (z AX3) pro představu, o čem je řeč: Doplňování kódu Nejviditelnější a nejdůležitější shopností je doplňování kódu při psaní. MorphX sice dokáže nabídnout seznam metod objektu nebo polí tabulky a dokonce i seznam tříd či datových typů (pod různými záhadnými klávesovými zkratkami), ale AxAssist to dělá řádově lépe. Nabízí datové typy při deklaraci, proměnné vhodného datového typu v přiřazení nebo volání parametrické metody, nabízí i makra atd. atd. Navíc je toto chování konfigurovatelné, např. lze definovat, po kolika zapsaných znacích se má nabídka zobrazit. Další příbuzná funkce je Acronyms, tedy zkratky. Slouží k nabízení datových typů a principem je „skákání po hrbech velblouda“, abych tak odkázal na velbloudí notaci. :-) Zkrátka nabídnou se ty typy, v nichž jsou v daném pořadí obsažena zadaná velká písmena. Například pro LJTI se (v AX3) nabídne LedgerJournalTrans_InventTrans (je-li povolena volba Extended Acronyms), LedgerJournalTransImport a LedgerJournalTypeId. Rozdíl v počtu znaků, které je nutné napsat, je evidentní. Užitečná funkce je také možnost zadání ignorovaných prefixů. Pokud vaše firma například prefixuje objekty trojicí znaků XYZ, můžete nechat prefix XYZ ignorovat a typ XYZOrderId se nabídne po prostém zadání OI. Lze zadat i více prefixů, oddělených čárkou. Po nastavení prefixu budete pravděpodobně muset restartovat AX klienta. Do nabídek lze přidat vlastní kusy kódu, tedy různé často zapisované konstrukce, komentáře dle firemních pravidel atd. Text nemusí být úplně statický, výsledná podoba je zkonstruována při spuštění AxAssist. Lze tedy např. předpřipravit komentář s vyplněným jménem přihlášeného uživatele apod. A ještě jedna drobnost: rozbalovací nabídka také zobrazuje ToolTip pro aktuálně vybraný prvek (a v něm např. typ proměnné, předka typu, label apod.). Způsob vytváření těchto ToolTipů lze také libovolně modifikovat a přidávat tak další informace, měnit formátování atd. Tlačítka Ve výchozím nastavení AxAssist také přibyde šest tlačítek na hlavní lištu a do AOT a tři do lišty editoru kódu. Z první skupiny zaujme třeba možnost otevření datového typu pole v AOT (což lze volat i z definice datového zdroje formuláře apod.), v editoru je zásadní skvěle fungující Open in AOT (lze použít z definice i použití libovolné proměnné a její typ je otevřen v samostatném AOT okně). Některá tlačítka mě příliš nezaujala z prostého důvodu, že všude používám Tabax a mám je tam (a třeba TableBrowser je v Tabaxu lepší ;)). Funkce tlačítek může být měněna, mohou být přidávana další atd. Vyžaduje to drobné zásahy do kódu, ale je to popsáno na webu AxAssist a není na tom nic složitého. Další změny v IDE Do IDE dále přibylo:
  • dolní lišta v AOT – zobrazuje definici (třídy, metody) nebo label (tabulky, formuláře, pole, EDT...)
  • rozbalovací seznam metod v editoru
  • panel v editoru (vlevo dole) – zobrazuje informaci o vybrané proměnné, včetně např. všech hodnot výčtového typu. I toto lze velmi snadno rozšiřovat a často se to hodí. Zobrazené hodnoty lze i kopírovat, typicky odtud kopíruji název datového typu.
Klávesové zkratky AxAssist umožňuje definovat vlastní klávesové zkratky a to zvlášť pro editor a zvlášť pro zbytek IDE. Funkce, pro kterou chcete definovat klávesovou zkratku, musí být definována v třídách AxAssist. Defaultně tam jsou funkce pro jednotlivá tlačítka a Code reformatter (viz dále). Opět odkáži na dokumentaci na webu, kde je postup přidávání dalších funkcí dobře popsán. Code reformatter Cílem Code reformatteru je zpřehlednit existující kód pomocí jeho rozdělení na více řádek a odsazení. Zřejmě se tak děje jen pro parametry metody a deklarace proměnných, což je pro mě trochu zklamání, ale budiž. Způsob odsazování lze nakonfigurovat v nastavení (čtvrtá záložka, „ReFormatter“). Spouštění reformatteru je poněkud zvláštní. Spouštěcí funkce je implementována a lze k ní přiřadit klávesovou zkratku nebo tlačítko, ale defaultně to provedeno není – tudíž ve výchozím nastavení není možné reformatter spustit. Nicméně stačí přidat čtvrté tlačítko do editoru a bude automaticky volat Code reformatter. Instalace, spuštění, synchronizace AxAssist se distribuuje jako jeden .exe soubor obsahující instalátor. Ten mj. uloží do instalačního adresáře soubor AxAssist.xpo, který musíte naimportovat do AX. Dále je třeba udělat ještě drobný zásah do třídy EditorScripts (viz web), jinak vám AxAssist vynadá, že instalace není dokončena. Po instalaci se ale AxAssist ještě nijak nespouští - je třeba spustit formulář DEV_AxAssistForm. Může být spouštěn buď automaticky po startu (zásah do Info.startupPost(), resp. workspaceWindowCreated()), nebo ručně (k tomu je ideální Tabax - stačí přidat ikonku Display_DEV_AxAssistForm.bmp do AX adresáře \Share\Include\Tabax\Plugs). Při startu provádí AxAssist synchronizaci, kdy si ukládá informace o typech a tyto informace pak využívá při konstrukci nabídek. Synchronizace trvá cca půl minuty, což může pochopitelně zdržovat, chcete-li se např. jen rychle na něco podívat. V závislosti na osobních preferencích pak můžete spuštět AxAssist ručně, automaticky s případným přeskočením startu AxAssist (typicky stiskem Shift nebo Ctrl; toto musí výslovně implementováno ve spouštěcí logice), používat různé konfigurace (např. konfiguraci bez AxAssist pro AxPath) atd. Cena Aktuální ceník naleznete zde. Rád bych upozornil na dvě věci:
  1. Jste-li firma, nemůžete zakoupit Single Developer License, vždy musíte koupit zakoupit Company License
  2. AxAssist se pořizuje pro každou verzi AX zvlášť, ale zároveň je hned zmíněna možnost slev (s čímž ovšem zkušenost nemám)
Support Při nasazování na projekt v AX3 jsem narazil na určité nejasnosti a výkonnostní problémy (v předchozí verzi AxAssist, nyní je již problém vyřešen) a vyzkoušel jsem tedy i support. Reakce byla rychlá a přínosná a pomohla i v přípravě tohoto příspěvku. Takže díky, Alexi! Závěr AxAssist umožňuje pracovat významně rychleji a lépe se soustředit na smysl implementace, protože není třeba přerušovat psaní kódu hledáním typu v AOT a podobně. Je až s podivem, kolik Dynamics AX vývojářů o AxAssist nikdy ani neslyšelo. Snad se to teď v české kotlině trochu změní… :-)

neděle 2. srpna 2009

Vyhledávání

Vyhledávání v kódu nebo v AOT je velice častá činnost. Hledáme použití proměnné, modelový kus kódu, objekty určitých vlastností atd. Přesto řada lidí neovládá některé užitečné funkce, které pro to Axapta nabízí. A právě na ty se nyní podíváme. Spustit formulář pro vyhledávání v AOT jistě dokáže každý, ale tento formulář umí podstatně více než jen vyhledat zadaný řetězec. Přímo na formuláři jsou další pole pro upřesnění kritérií (ačkoli pro některé jsem dosud nenašel smysluplné využití) a dokonce možnost zapsat vlastní funkci, která se spustí pro každý TreeNode (jaké má mít metoda parametry se dočtete v nápovědě k formuláři). Co už není tak očividné je možnost zadat regulární výraz do vyhledávacích polí. Syntaxe odpovídá metodě match() a je u ní zdokumentovaná. Takže např. následující příklad hledá přiřazení do proměnné i - jinak řečeno, proměnnou i následovanou libovolným počtem mezer a znakem =. Dohromady i: *=. Obdobně lze hledat třeba metody, jejichž název odpovídá určitému regulárnímu výrazu (např. <check.*sales pro metody začínající check a pak kdekoli obsahující sales). V tomto případě pochopitelně umístíme regulární výraz do pole (Nazváno) Named. Regulární výrazy lze využít i při vyhledávání labelů (což je mimochodem funkce k nezaplacení) a také v editoru kódu. V editoru hlavně pozor na to, že se vyhledává od pozice kurzoru do konce, to je dost matoucí. A kupodivu hledání v AOT a hledání v editoru pracuje jinak např. s koncem řádku… Při hledání v AOT lze využít ještě jednu zajímavou funkci a to vyhledávání ve vlastnostech. Nejprv je nutné přepnout volbu Hledat (Search) na Vše (All nodes) - tím se zobrazí další záložka: Vlastnosti (Properties). Na ní si pak najdeme patřičné vlastnosti, označíme jako Selected a zadáme hodnotu. Ta má opět hodnotu regulárního výrazu. Může to vypadat třeba takto:

Reflexe - AOT

Třída TreeNode představuje uzel AOT, tedy objekty, metody, pole ale i "adresáře" jako třeba Forms. S její pomocí pak můžeme provádět akce, na jaké jsme zvyklí při ruční práci s AOT. Například tento kód vytvoří novou třídu a spustí ji:
#AOT
TreeNode nodeClasses = TreeNode::findNode(#ClassesPath);
TreeNode nodeClass;
TreeNode nodeMethod;
;

nodeClass = nodeClasses.AOTadd('NovaTrida');
nodeMethod = nodeClass.AOTadd('main');
nodeMethod.AOTsetSource(
   'public static void main(Args _args){;info("Bezi");}', true);
nodeClass.AOTsave();
nodeClass.AOTcompile();
nodeClass.AOTrun();
Příklad asi nepotřebuje mnoho komentáře. Makro #AOT obsahuje cesty k různým prvkům (nebo části cest, jako třeba '\%1\\Fields\\\%2'). Skupinu všech tříd, novou třídu i její metodu reprezentuje třída TreeNode. Díky této funkcionalitě lze například snadno vytvářet generátory kódu apod. Další užitečná věc je práce s vlastnostmi (Properties). Vlastnost vyhledáme podle jejího názvu a v tom nám pomůže další makro - #Properties.
#AOT
#Properties
TreeNode nodeBOM = TreeNode::findNode(#TablesPath + #AOTDelimiter + tableStr(BOM));
;
info(nodeBOM.AOTgetProperty(#PropertyCachelookup));
Obdobně lze vlastnosti i nastavovat:
tableNode.AOTsetProperty(
   #PropertyFormRef,
   menuitemDisplayStr(Form1));
tableNode.AOTsave();
Často je také potřeba procházet iterovat přes větší množství AOT uzlů. K tomu se hodí tyto třídy:
  • TreeNode - metody AOTfindChild(), AOTfirstChild(), AOTnextSibling() atd.
  • TreeNodeIterator - prochází přímé potomky. Lze získat voláním AOTiterator() na TreeNode.
  • TreeNodeTraverser - prochází potomky včetně nepřímých.
  • TreeNodeTraverserSource - potomek TreeNodeTraverser; prochází jen uzly obsahující zdrojový kód.
Některé zajímavé metody pro práci s uzly AOT naleznete ve tříde SysTreeNode. Je jasné, že TreeNode obsahuje funkcí daleko více, ale pro základní představu to stad stačí.

úterý 28. července 2009

SysCompareCreateProject

Dnes jsem potřeboval vypsat objekty existující v jedné vrstvě a změněné v jiné vrstvě. Nejdřív mě napadl upgrade projekt, ale pak jsem objevil třídu SysCompareCreateProject. Zadám vrstvy, jméno privátního projektu a jedem… Jenže do projektu se mi dostaly i ty objekty, které ve vyšší vrstvě prostě chyběly, a to jsem nechtěl. Pokusně jsem upravil podmínku v compareNodes() a vše bylo OK. Před zásahem do dialogu (aby bylo možné chování měnit) jsem se ještě podíval do AX2009 (tohle bylo na 3.0) a co myslíte? Jasně, přesně tohle tam už je implementováno. :-)

neděle 19. července 2009

Reflexe - vytvoření objektu, volání metod

Původně jsem se chtěl vrátit k Team Foundation Serveru, ale času se nějak nedostává a plány se odsouvají... Takže raději zpátky k tématu reflexe. V poslední době jsem níže uvedené informace vyvsvětloval postupně několika lidem, tak bude asi vhodné to sepsat. Podívejme se na případ, kdy máme jméno (nebo ID) třídy a chceme vytvořit instanci.
ClassName className = 'SalesFormLetter_Invoice';
SysDictClass dictClass = new SysDictClass(className2Id(className));
FormLetter formLetter;
;
formLetter = dictClass.makeObject(true);
Jméno jsem převedl na ID, vytvořil instanci SysDictClass a zavolal metodu makeObject(). Té lze předat parametry, které očekává konstruktor. Je zajímavé, že nedojde k run-time chybě ani když vynechám povinný parametr (AX přiřadí parametru default hodnotu). Vtipně provádí validaci SysDictClass.allowMakeObject(). :-) Teď můžeme zavolat metodu objektu FormLetter. Na tom nic není. Ale co když neznám typ objektu? Mohu například zjistit, zda třída implementuje nějaké rozhraní a přetypovat na něj.
if (dictClass.isImplementing(classNum(SysRunable)))
{
   sysRunable = dictClass.makeObject();
   sysRunable.run();
}
Obdobně zjistím, zda je potomkem nějaké třídy.
if (dictClass.isExtending(classNum(RunBaseBatch)))
Nebo prostě zkusím, zda má objekt nějakou konkrétní metodu:
IdentifierName methodName = 'xml';
SysDictClass dictClass = new SysDictClass(classNum(Query));
Object object;
;

object = dictClass.makeObject();

if (dictClass.hasObjectMethod(methodName))
{
   info(dictClass.callObject(methodName, object, 10));
}
Metoda callObject() tedy očekává název metody, instanci objektu, jehož metoda se má volat, a případné parametry metody. Obdobně lze volat i statické metody. Jedno z možných použití je samozřejmě i vytvoření instance:
SysDictClass dictClass = new SysDictClass(classNum(InventItemType));
Object object;
;
object = dictClass.callStatic('construct', ItemType::Service);
U tabulek je to pak velmi podobné, jen místo makeObject() se použije makeRecord():
SysDictTable dictTable = new SysDictTable(tableNum(LedgerJournalTrans));
Common common;
;
common = dictTable.makeRecord();
dictTable.callObject('initFromCustTable', common, CustTable::find('1'));
U tabulek nás ale většinou zajímá jestě jedna věc a tou věcí jsou datová pole. Tam přijde ke slovu trochu neobvyklá syntaxe tabulka.(číslo pole). Například:
InventTable inventTable = InventTable::find('1');
SalesLine   salesLine = SalesLine::findInventTransId('12345', true);
Common      table1 = inventTable;
Common      table2 = salesLine;
FieldId     fieldId1 = fieldNum(InventTable, ItemId);
FieldId     fieldId2 = fieldNum(SalesLine, ItemId);
;
table1.(fieldId1) = table2.(fieldId2);
Poslední příklad ukazuje, jak získat hodnotu na základě jména pole:
SysDictTable dictTable;
Common common;
FieldId fieldId;
;
dictTable = new SysDictTable(common.TableId);
fieldId = dictTable.fieldName2Id('Name');
if (fieldId)
{
   info(common.(fieldId));
}
Užitečný odkaz: MSDN: Intrinsic Functions

sobota 18. července 2009

SysMultiTableLookup

Tento týden jsem potřeboval vytvořit lookup s poli z různých tabulek. Věděl jsem o existenci třídy SysMultiTableLookup, ale nějak jsem ji dříve nepotřeboval. A teď tedy přišel čas, abych se na ni podíval. Tuto třídu vytvořil Vanya Kashperuk (blog) s cíle rozšířit funkcionalitu široce používané třídy SysTableLookup. SysMultiTableLookup přináší možnost zobrazovat pole z více tabulek, používat display metody, agregační funkce nebo zadat jiný než standardní popisek pole. Vše, co jsem vyzkoušel, funguje velmi dobře. Skvělá práce! Třídu a formulář s příklady lze stáhnout zde.

neděle 12. července 2009

Reflexe - úvod

Reflexe (reflection) umožňuje pracovat se strukturou programu samotného. Když například Unit Testing Framework spouští všechny metody začínající "test", využívá k tomu reflexi. Hrátky s reflexí jsou zábavné a zároveň umožní tvořit velmi zobecněná řešení některých problémů, takže ji určitě neignorujte. :-) Obecně bych rozdělil využití reflexe v Axaptě do dvou hlavních oblastí: 1. Analýza aplikace - například:
  • vyhledání tříd implementujících dané rozhraní (Které RunBaseBatch třídy se mění aktuálním releasem?)
  • výpis polí tabulky pro uživatelský výběr (AIF, DEV_SysTableBrowser)
  • generátory kódu (metoda find() na základě primárního indexu)
  • atd.
2. Ovlivnění business logiky - tím míním např.:
  • volání metod na základě dat (Např. volám konkrétní metodu všech tříd, jejichž názvy jsem uložil do tabulky. To mi umožní měnit aplikační logiku dle aktuálních požadavků bez potřeby zásahu do kódu.)
  • provedení určité akce se všemi poli v tabulce, nebo třeba s poli určitého datové typu (validace)
  • atd.
Z funkčního hlediska existují dva přístupy:
  • TreeNode - představuje práci s AOT. Umožňuje procházet AOT, spouštět objekty, vytvářet, exportovat, pracovat s vrstvami atd. Základem je třída TreeNode, resp. její rozšíření SysTreeNode.
  • Dictionary - pracuje jen s datovým slovníkem (EDT, tabulky, třídy; ne třeba formuláře), ale objektům "rozumí" lépe než TreeNode. Pracuje s dědičností, přístupovými modifikátory (např. private), databází atd. Využívá systémové třídy Dict* a aplikační třídy SysDict*, v kterých jsou mnohá užitečná rozšíření.
Ještě se sluší poznamenat, že některé úkoly lze realizovat i jinak a mnohdy i efektivněji. Napadají mě třeba:
  • křížové reference (pokud jsou aktuální, samozřejmě)
  • UtilElements a další systémové tabulky
  • polymorfismus (jinak řečeno - řešení vhodným objektovým návrhem)
Na závěr dva jednoduché příklady, složitější aplikace si schovám na jindy. Ukázka 1 - Dictionary
Dictionary dictionary = new Dictionary();
DictClass dictClass;
ClassId classId;
;

classId = dictionary.classNext(0);

while (classId)
{
    dictClass = dictionary.classObject(classId);
    info(strFmt(
        "Třída %1 - instančních metod: %2",
        dictClass.name(),
        dictClass.objectMethodCnt()));
    classId = dictionary.classNext(classId);
}
Ukázka 2 - TreeNode
TreeNode formsNode = TreeNode::findNode(@'\Forms\'); //cesta v AOT
TreeNodeIterator iterator;
TreeNode formNode;
;

iterator = formsNode.AOTiterator();
formNode = iterator.next();

while (formNode)
{
     info(strFmt(
         "Formulář %1 - datových zdrojů: %2",
         formNode.AOTname(),
         formNode.AOTfindChild('Data Sources').AOTchildNodeCount()));
    formNode = iterator.next();
}

Videa

Dnes uvedu pár tipů na videa týkající se Axapty. Některé věci je prostě dobré vidět v chodu. Hlavním zdrojem je Channel 9 na MSDN. Dají se tam najít i např. rozhorvory s tvůrci, ale já jsem vybral linky na několik screencastů: Dynamics AX 2009 AIF Web Services Dynamics AX 4.0 - Unit Testing Exception handling in X++ Dynamics AX 4.0 - 3-tier Development Samozřejmě se dá něco najít i na známém YouTube (BTW není nad český překlad TyTrubko ;)), například: Dynamics AX Item Approval Workflow Setting Up Outlook Sychronization in Dynamics AX 2009 TabaxLite & Microsoft Dynamics Ax (TabaxLite je verze Tabaxu určená pro koncové uživatele) A nakonec zmíním tutoriály na MSDN: “How Do I” Videos — Dynamics AX PS: Celkem nedávno rozjel český Microsoft portál MSTV - přímo k Dynamics tam sice nic není, ale zato spousta zajímavostí ohledně .NETu...

středa 24. června 2009

Vyšla kniha Inside Microsoft Dynamics AX 2009

Knížka Inside Microsoft Dynamics AX 2009 je v prodeji, samozřejmě v angličtině. (link)

úterý 9. června 2009

Tabax

Prostředí Dynamics AX má k dokonalosti v mnoha ohledech daleko a některé úkoly jsou tak zbytečně komplikované. V tu chvíli přichází ke slovu programátor, jehož základní vlastností je lenost :), a pro zjednodušení práce si napíše utilitku. Vývojáři Dynamics AX nejsou výjimkou a mnozí si své nápady nenechávají pro sebe - díky tomu lze na internetu nalézt řadu zajímavých nástrojů. Třeba Tabax. Největším přínosem Tabaxu je umisťování oken na panel záložek, takže nemusíte složitě hledat schovaná okna. V AX2009 se sice některé formuláře otevírají mimo hlavní okno, ale přesto záložky Tabaxu rozhodně využijete. Dále Tabax nabízí nástrojovou lištu, kde sice nenajdete mnoho nového, ale např. možnost jednou kliknout pro otevření aktivního formuláře v AOT ušetří spoustu neproduktivního času. Pro názornost screenshoty z AX3 a AX2009: Stručný popis funkce tlačítek (AX2009):
  • Slouží k rozmisťování oken.
Edit current form
  • Otevře aktivní formulář v AOT (jinak řečeno, přejdu z uživatelského pohledu na formulář do jeho editace).
Edit current field
  • Otevře aktivní formulářový prvek v AOT. Funkce je sice určeno pro pole, ale s úspěchem lze aplikovat i třeba na MenuItemButton.
  • Ctrl+Click - Vypíše do infologu podrobné informace o aktivním poli - např. jméno prvku, jméno pole (popř. metody), použitý datový typ, jeho rozsah atd.
  • Ctrl+Shift+Click - Otevře v AOT použitý datový typ a zobrazí jeho vlastnosti (Properties).
Table browser
  • Otevře tabulku v prohlížeči tabulek (form SysTableBrowser). Funkci můžete použít přímo z formuláře (otevře se tabulka, do níž patří aktivní pole), ale také v podstatě kdekoli v AOT, kde narazíte na tabulku (např. v definici query na tiskové sestavě).
  • Shift+Click - Zobrazí seznam tabulek, které jsou na formuláři použity. Zvolenou tabulku pak zobrazí v prohlížeči tabulek. Pokud je k dispozici pouze jediná tabulka, je zobrazena rovnou.
  • Ctrl+Click - Funguje obdobně jako Shift, ale zvolenou tabulku otevře v AOT.
  • Ctrl+Shift+Click - Zobrazí SQL dotaz použitý k vygenerování aktivního datového zdroje formuláře. Úžasně užitečná funkce pro ladění složitých filtrů, dynamicky připopojovaných datových zdrojů apod.
Refresh AOD
  • Vymaže nacachované informace o aplikačních objektech (na klientu).
xReferences - usedBy
  • Zobrazí křížové reference, tedy informaci, kde všude je zvolený objekt používán. Samozřejmě to vyžaduje aktuální křížové reference…
Application Hierarchy Tree
  • Zobrazí Strom aplikační hierarchie pro aktivní datový typ nebo třídu. Funguje to i pro systémové objekty, takže se můžete třeba podívat, jaké potomky má třída TreeNode.
Copy
  • Zkopíruje do schránky název vybraného objektu (objektů), nebo, v případě formuláře, AxPath odkaz na aktivní záznam.
  • Ctrl+Click - Zkopíruje AOT cestu (např. \Classes\RunBase\run).
  • Ctrl+Shift+Click - Zkopíruje AxPath odkaz. AxPath vydá na samostatný příspěvěk, ale v zásadě jde o protokol pro odkazování do AX (např. na konkrétní záznam v konkrétním formuláři), takže je pak možné jednoduše kliknout na odkaz třeba z e-mailu a v AX se otevře cíl odkazu. Více v angličtině zde.
Open Application Object
  • Otevře aplikační objekt v novém okně. Je to užitečné, jsem-li na nějaké části aplikačního objektu (např. na metodě v editoru) a chci otevřít celý objekt v AOT.
  • V případě otevřeného formuláře otevře v novém okně objekt, který daný formulář vyvolal (caller). To je většinou jiný formulář nebo třída.
Add-ins
  • Otevře menu Add-ins. Víc od toho nečekejte. :-)
Compare
  • Porovná dvě verze objektu (verze z různých vrstev nebo ve smyslu verzí v repository), případně dva objekty mezi sebou. Bohužel na mé instalaci na AX2009 to nefunguje a zatím nevím proč. :-(
Import
  • Zobrazí dialog pro import .xpo.
Následuje prostor pro plug-iny, ve verzi pro AX2009 tam již dva standardně jsou: Search
  • Zobrazí dialog pro vyhledávání v AOT pro vybrané objekty.
Label Search
  • Zobrazí Editor popisků.
V pravé části se nachází: Search (input box) - lze do něj zadat řadu věcí:
  • AOT cestu (třeba \Classes\Info) - otevře objekt v AOT; metodu přímo v editoru.
  • Výraz začínající otazníkem (např. ?74 MOD 17 nebo ?tableId2Name(177)) - vyhodnotí výraz a výsledek vypíše do infologu.
  • Příkaz začínající vykřičníkem (např. !beep();) - provede příkaz.
  • Ostatní - vyhledá text na Googlu. Je tam nastavené hledání AxSearch, které mi ale nepřijde příliš užitečné.
About
  • Verze, odkaz na domovskou stránku, text licence.
Pause
  • Pozastaví úlohy Tabaxu běžící na pozadí. Nevím, co přesně dělají, ale ve výpisu profileru opravdu nehezky překáží. Toto tlačítko problém řeší.
Preferences
  • Obsahuje několik nastavení, např. maximální velikost záložky.
Close
  • Ukončí Tabax.
Automatické spouštění Tabaxu Chcete-li automaticky spouštět Tabax při startu AX, můžete použít postup popsaný na stránce Tabaxu, tzn. umístit následující kód do metody startupPost() (AX3) nebo workspaceWindowCreated() (AX4 a 5) ve třídě Info:

// if shift is pressed skip running tabax
if(!WinAPI::isShiftButtonDown())
{
// check for user ID 
if(curUserId()=='bmi') // <- change to your loginname
{
 // actually run tabax
 TreeNode::findNode(@'\Forms\'+formStr(Tabax)).AOTrun();
    }
} 
Nebo, pokud chcete nastavovat spouštění pro různé uživatele či skupiny uživatelů, můžete zkusit <reklama>můj StartupTool</reklama>. Odkazy: Axaptapedia: Tabax Axaptapedia: Tabax Plugin API Axaptapedia: AxPath Max Belugin: New AxPath plugin

čtvrtek 4. června 2009

Query s dočasnou tabulkou

Nedávno jsme s kolegy řešili join dočasné a trvalé tabulky v třídě Query. V zásadě na tom není nic složitého (dočasná tabulka se zadá do datového zdroje stejně trvalá tabulka, jen je na QueryRun potřeba pomocí setCursor() přiřadit buffer dočasné tabulky), zajímavé ale je, že připojení dočasné tabulky na trvalou není možné provést na klientu. V takovém případě dostanete chybu: Cannot select a record in table. Temporary tables must be the outer tables when joined to permanent tables. Neboli Nelze vybrat záznam v tabulce tabulka. Dočasné tabulky musí být vnitřní při spojování na trvalé tabulky. Na aplikačním serveru proběhne vše OK. Důvodem omezení jen na AOS asi bude výkonnost tohoto joinu (full table scan na trvalé tabulce). Chování je ověřeno na AX3SP3 a AX5SP1. Vyzkoušet si to můžete na přiloženém příkladu (.xpo z DAX2009), dostat byste měli takovýhle výstup: .xpo s ukázkovým kódem

pondělí 25. května 2009

Třída Debug

Třída Debug obsahuje několik metod pro debugování, tedy ladění kódu. Konkrétně to jsou: Debug::printDebug(str s) Debug::printTab(DebugPrintTab tab, str s) Debug::assert(boolean b) První dvě jsou velmi podobné, jejich účelem je vypsání dodatečných informací v okně debuggeru. printDebug() na záložku Debug a printTab() na záložku určenou prvním parametrem. Metoda assert() je také velmi jednoduchá. Tato metoda ověřuje platnost nějakého předpokladu, který by měl vždy být splněn. To se nazývá assertion, česky aserce. Pokud splněn není, běh programu se zastaví a řízení se předá debuggeru. Je to vlastně takový podmíněný breakpoint. Typicky se takto ověřují vstupní nebo výstupní podmínky metody. Jako příklad ve standardní aplikaci (AX2009) může posloužit metoda calculateSumOfAmount třídy LedgerBudget, kde najdeme aserci Debug::assert(_startDateStart <= _startDateEnd); Aserce jsou určeny pro ladění, nikoli běh v uvolněné aplikaci. Obvykle se zachovávají ve zdrojovém kódu, ale kompilátor je ignoruje, pokud nejde o kompilaci debugovací verze. AX to sice neumožňuje řešit na úrovni kompilátoru, ale umožňuje nastavit Režim ladění (Nástroje > Možnosti > Vývoj) - je-li nastaveno na Ne, jsou debugovací příkazy ignorovány.

neděle 24. května 2009

Vydání Inside Dynamics AX 2009 se blíží

Vydání dlouho slibované knihy Inside Microsoft Dynamics AX 2009 se přiblížilo, na Amazonu si ji už se slevou můžete předobjednat (link) a vydání na sebe snad už nenechá dlouho čekat. Pro ty, kteří neradi objednávají ze zahraničí, mám jeden tip v podobě e-shopu bookfayre.cz.

čtvrtek 21. května 2009

SQL Server 2008 a AX

V poslední době se dost lidí zajímá o možnosti využití nového SQL Serveru 2008 a pátrají, jak že je to s jeho podporou v Dynamics AX. Vězte, že odpověď je velmi prostá: V tuto chvíli existuje jediná verze podporující SQL Server 2008 a to Dynamics AX 2009 SP1. Navíc musíte počítat s některými dalšími komplikacemi, například můj pokus o instalaci Reporting Extension skončil s tím, že je vyžadován SQL Server 2005 SP2 (bylo třeba překopírovat jednu knihovnu ze SP, viz např. tento příspěvěk). Také použití SQL Serveru 2008 pro databázovou vrstvu Team Foundation Serveru je komplikovanější než v případě SQL Serveru 2005, je totiž nutné zaintegrovat SP1 přímo do instalace TFS, nicméně je to dobře zdokumentováno a není to nijak náročné. Až budou vydány plné verze přímo počítající s SQL Serverem 2008, tyto problémy zmizí. A když už jsem u těch systémů řady 2008, na Windows Serveru 2008 to jede všechno bez problémů. :-)

středa 20. května 2009

TFS a AX 1 - Úvod

Dnes bych chtěl začít malý seriál předem neurčeného rozsahu a to o Team Foundation Serveru (TFS) v Dynamics AX 2009. Asi bych měl předem varovat, že s TFS nepracuji (a v dohledné době asi ani nebudu) a tak se budu věnovat jen vybraným a základním věcem - ovšem s důrazem na použití s AX. Team Foundation Server je produkt společnosti Microsoft pro komplexní správu a řízení projektu - to zahrnuje mj. správu "work items" (např. úkol nebo kvalitativní požadavek), úložiště zdrojových kódů, reporting a podobně. TFS je zaměřen hlavně na Visual Studio, ale jeho architektura (o které se snad zmíním podrobněji jindy) počítá s implementací různých klientů a díky tomu máme možnost využít TFS i v Dynamics AX ve verzi 2009. V Dynamics AX je TFS integrován čistě jako systém pro správu kódu. Jinak řečeno, je možné ukládat do repozitáře, porovnávat verze objektů apod., ale už ne např. přiřadit ukládanému kódu číslo požadavku. To neznamená, že na ostatní funkce TFS musíme zapomenout - jen nejsou přístupné přímo z Dynamics AX. Základní možností je Visual Studio (viz také Team Explorer, což je verze VS jen pro přístup k TFS a je zdarma, ovšem potřebujete TFS CAL), některé činnosti ale můžete dělat i třeba v Excelu nebo Projectu. Pro představu jeden obrázek z Visual Studia: A na závěr pár odkazů: Team Foundation Server Team Center Channel9: Team Foundation Server Programátorské večery: Team Foundation Server Visual Studio Team System 2008 Team Foundation Server (90-day Trial) MSDN: AX 2009 Version Control System

pondělí 4. května 2009

Datový model Dynamics AX 4.0

Už loni v září zveřejnil Vanya Kashperuk na svém blogu dokument obsahující datový model Dynamics AX 4.0 (originální příspěvek). Nepotkal jsem ale nikoho, kdo by to zaregistroval, je tedy bezpochyby na místě na to znovu upozornit. Takže, stahujte zde. V dokumentu najdete ER diagramy a textové popisy tabulek a polí (kde už ovšem angličtině neuniknete). No, podívejte se sami... PS: A ne, podobný dokument pro AX2009 k dispozici není.

K čemu tento blog?

Je pravda, že blogů na téma Dynamics AX je mnoho, ale má to dva velké problémy. Za prvé má spousta lidí problém s cizím jazykem, za druhé je sledování mnoha blogů a dalších zdrojů natolik časově náročné, že na něj řada lidí rezignuje úplně. Cílem tohoto blogu je tedy nejen zaznamenat moje osobní postřehy, ale i předložit vybrané příspěvky z anglicky psaných blogů a fór. Blog se zaměřuje na vývoj Dynamics AX, nikoli na uživatelskou stránku. Tu přenechám někomu jinému. :-)