X++ 소스 코드에 대한 버젼 관리

Posted by Alvin You
2014. 10. 12. 00:48 Dynamics AX

많은 프로젝트를 진행하다보면 소스에 대한 버젼 관리 미흡으로 개발을 진행하는 개발자나 프로젝트를 관리하는 PM에게 당황스러운 일들이 발생하고는 합니다.

 

Dynamics AX 프로젝트 또한 독립적인 개발환경인 MorphX의 특성과 Layer라는 개념 때문에 소스에 대한 충돌 및 소스가 유실되는 경우가 많이 발생이 되고는 합니다. 2012에서는 Model이라는 개념이 등장해 더더욱 혼란을 가중시키는 역할을 하고 있습니다.

 

또한, 개발자간의 소스 이동이라든지 Live 시스템에 소스를 이관하는 과정에서 개발된 소스가 유실되는 경우가 발생이 되곤 합니다. 이렇게 소스에 대한 버젼관리가 절실함에도 이러한 환경에서 프로젝트를 진행해보지 못한 이유로 VCS(Version Control System)에 대한 두려움들이 존재하는 것 같아 버젼관리에 대해서 정리된 자료를 공유해 드립니다.

 

 

Split String in Dynamics AX

Posted by Alvin You
2014. 9. 10. 22:44 Dynamics AX/Development

프로그램 개발을 하다보면 많은 문자열 함수와 부딪히게 됩니다. 그 중 입력 받은 문자열을 특정 구분 문자를 통해서 문자열을 쪼개고 다시 그 값을 다른 계산이나 데이터베이스에 넣게 되는 작업을 많이 진행하게 됩니다.

그렇다면, 위와 같은 작업을 X++에서는 어떻게 진행할 수 있을까요? 많은 방법들이 있겠지만 아래 6가지 방법 중 본인이 편안하게 사용할 수 있는 방법을 가져다가 사용하면 될 것 같습니다.

1. 구분값 위치를 계산해서 문자열을 쪼개는 방법

static void splitString_old(Args _args)

{

    str input = "Minho,Ricky,Hansuk,Sangwook";

    str seperator = ",";

    int lenInput = strLen(input);

    int nextPos;

    int lastPos = 1;

    str result;

    ;

 

    do

    {

        nextPos = strFind(input, seperator, nextPos + 1, lenInput - nextPos);

        if (nextPos == 0)

            nextPos = lenInput+1;

        result = subStr(input, lastPos, nextPos-lastPos);

        info(result);

 

        lastPos = nextPos+1;

    }

    while (nextPos != lenInput+1);

}

2. List Class 사용

static void splitString_list(Args _args)

{

    str input = "Minho,Ricky,Hansuk,Sangwook";

    str separator = ",";

    str result;

    List list;

    ListEnumerator le;

    ;

   

    list = new List(Types::String);

    list = strSplit(input, separator);

    le = list.getEnumerator();

   

    while ( le.moveNext())

    {

        result = le.current();

        info(result);

    }

 

}

3. Container Class 사용

static void splitString_con2str(Args _args)

{

    str input = "Minho,Ricky,Hansuk,Sangwook";

    str separator = ",";

    str result;

    container cont;

    int i;

    ;

   

    cont = str2con(input, separator);

    for (i=1; i <= conLen(cont); i++)

    {

        result = conPeek(cont, i);

        info(result);

    }

}

4. TextBuffer Class 사용

 

static void splitString_textBuffer(Args _args)

{

    str input = "Minho,Ricky,Hansuk,Sangwook";

    str separator = ",";

    str result;

    TextBuffer tb;

    ;

   

    tb = new TextBuffer();

    tb.ignoreCase(true);

    tb.regularExpressions(false);

   

    tb.setText(input);

    while ( tb.nextToken(false, separator))

    {

        result = tb.token();

        info(result);

    }

}

5. Regular Expression 사용

static void splitString_regEx(Args _args)

{

    str input = "Minho,Ricky,Hansuk,Sangwook";

    str separator = "\\,";

    str result;

    int i;

    System.Array resultArr;

    int resultArrLen;

    System.Exception clrException;

    ;

   

    try

    {

        resultArr = System.Text.RegularExpressions.Regex::Split(input, separator);

        resultArrLen = resultArr.get_Length();

       

        for (i=0;i<resultArrLen;++i)

        {

            result = CLRInterop::getAnyTypeForObject(resultArr.GetValue(i));

            info(result);

        }

    }

    catch(Exception::CLRError)

    {

        clrException = CLRInterop::getLastException();

        if(clrException)

        {

            info(CLRInterop::getAnyTypeForObject(clrException.get_Message()));           

        }

    }

}

6. NET String Function 사용

static void splitString_dotNet(Args _args)

{

    System.String input = "Minho,Ricky,Hansuk,Sangwook";

    System.Char[] separator = new System.Char[1]();

    System.Char symbol = System.Char::Parse(',');

    System.String[] result;

    int resultLen;

    int i;

    ;

   

    separator.set_Item(0, symbol);

    result = input.Split(separator);

    resultLen = result.get_Length();

   

    for (i=0;i<resultLen;i++)

    {

        System.Windows.Forms.MessageBox::Show(result.get_Item(i));

    }

}

 

[Powershell]AX 사용자 관리

Posted by Alvin You
2014. 8. 17. 23:58 Dynamics AX

MS가 UNIX 환경의 Shell 환경처럼 많은 Command들을 이용해서 시스템을 관리할 수 있도록 발표한 것이 Powershell 일 것입니다.

Windows 관리에만 사용되던 Powershell을 AX 설치 후 추가된 Microsoft Dynamics AX 2012 Management Shell을 통해서 AX관리에 Powershell을 사용할 수 있습니다.

오늘은 AX 사용자와 관련된 몇 가지 Command를 다뤄 볼 생각입니다.

1. AD(Active Directory) 사용자 및 AX User 생성

New-AXUser -AccountType WindowsUser -AXUserId Alvin –UserDomain "ZSP" -PartitionKey initial Enabled -UserName Alvin -Company ZSPK

2. 사용자 계정 Disable 처리

Disable-AXUser –AXUserId Alvin

3. 사용자 계정에 Role 연결

Add-AXSecurityRoleMember –AxUserId Alvin –AOTName -SYSADMIN-

Korea AX User Group을 만들었습니다.

Posted by Alvin You
2014. 8. 12. 23:46 Dynamics AX

많은 국가에서 AXUG(AX User Group)을 만들어 AX 사용자들간에 정보 교류를 하는 것을 보고, 제가 국내 AX User Group을 만들었습니다.

 

네이버 블로그에 관련 카페를 만들었으며, AXUG 도메인을 등록해 카페 접속을 손쉽게 할 수 있도록 했으니 많은 AX 사용자 또는 관심 있으신분들의 회원 가입 부탁 드리겠습니다.

 

Korea Dynamics AX User Group : http://www.axug.co.kr

 

아직은 컨텐츠가 많이 부족하지만 제 개인 블로그에 있는 내용들이라도 퍼 나르도록 하겠습니다.

 

감사합니다.

X++에서 XML 파일로 데이터 저장하고 읽기

Posted by Alvin You
2014. 8. 2. 09:35 Dynamics AX/Development

오늘은 AX의 데이터를 XML 파일로 저장 후 다시 데이터를 읽어 오는 샘플 코드를 보여 드릴까 합니다. 외부 시스템과의 데이터 교환을 DB-To-DB 형태로 교환 할 수도 있지만, 특정 시스템들은 XML 파일로 주고 받을 수 있기 때문에 시스템 구축시 아래 코드가 도움이 되었으면 좋겠습니다.

  • VendTable에서 데이터를 읽어와 vendList.xml 파일로 저장

static void ZSPK_CreateXMLFile(Args _args)

{

XmlDocument doc;

XmlElement nodeXml;

XmlElement nodeTable;

XmlElement nodeAccount;

XmlElement nodeName;

VendTable vendTable;

Filename fileName;

int i;

#WinAPI

;

 

doc = XmlDocument::newBlank();

nodeXml = doc.createElement('xml');

doc.appendChild(nodeXml);

 

while select vendTable order by vendTable.AccountNum

{

i++;

nodeTable = doc.createElement(tableStr(VendTable));

nodeTable.setAttribute(fieldStr(VendTable, RecId), int642str(vendTable.RecId));

nodeXml.appendChild(nodeTable);

 

nodeAccount = doc.createElement(fieldStr(VendTable, AccountNum));

nodeAccount.appendChild(doc.createTextNode(vendTable.AccountNum));

nodeTable.appendChild(nodeAccount);

 

nodeName = doc.createElement(fieldStr(vendTable, ZSPK_Name));

nodeName.appendChild(doc.createTextNode(vendTable.ZSPK_Name));

nodeTable.appendChild(nodeName);

 

if (i == 5) break;

}

 

fileName = WinAPI::getFolderPath(#CSIDL_PERSONAL);

fileName += '\\vendList.xml';

doc.save(fileName);

info("완료");

}

 

  • vendList.xml 파일을 읽어오는 코드 샘플 코드

static void ZSPK_DataSetRead(Args _args)

{

System.Data.DataSet dataSet;

System.Data.DataTableCollection dataTableCollection;

System.Data.DataTable dataTable;

System.Data.DataRowCollection dataRowCollection;

System.Data.DataColumnCollection dataColumnCollection;

System.Data.DataRow dataRow;

System.Data.DataColumn dataColumn;

int i,j,TotalCol,TotalRow;

str _xml;

;

 

dataSet = new System.Data.DataSet();

dataSet.ReadXml(@"C:\Users\Administrator\Documents\vendList.xml");

dataTableCollection = dataSet.get_Tables();

dataTable = dataTableCollection.get_Item(0);

dataColumnCollection = dataTable.get_Columns();

dataRowCollection = dataTable.get_Rows();

TotalRow = dataRowCollection.get_Count();

TotalCol = dataColumnCollection.get_Count();

 

for (i=0;i < TotalRow; i++)

{

dataRow = dataRowCollection.get_Item(i);

//setprefix(CLRInterop::getAnyTypeForObject(DataRow.get_item(i)));

for (j=0;j < TotalCol; j++)

{

//dataRow = dataRowCollection.get_item(i);

if (dataRow.IsNull(j))

_xml = 'null';

else

_xml = dataRow.get_Item(j);

 

info(strFmt("%1 - %2 - %3", i, j, _xml));

}

}

 

}

 

사용자가 Session Date 변경을 못하도록 권한 빼기

Posted by Alvin You
2014. 7. 30. 23:31 Dynamics AX

오늘은 Dynamics AX에서 과거 날짜의 Transaction Data를 발생시키기 위한 방법 중 하나인 File > Tools > Session date and time 메뉴에 대한 권한을 막는 방법에 대해서 설명해 드리겠습니다.

특정 권한을 가진 Key User(Power User)에게만 권한이 주어지면 좋겠지만 System User Role이라는 가장 기본적인 Role에 해당 권한이 들어가 있어 모든 사용자가 아래와 같은 날짜 변경 화면을 사용할 수 있도록 되어 있습니다.

 

결론을 말씀 드리면, Session Date and time 메뉴의 Entry Points인 SystemDate가 속한 ClientEssentials Privileges에서 해당 Entry Points를 빼고 새롭게 만든 Privileges에 해당 Entry Points를 넣으면 System User Role에 해당하는 일반 사용자에게서 해당 권한이 빠지게 됩니다.

Role

Duty

Privileges

Entry Points

System User

  

  

  

  

SysServerAXBasicMaintain

  

  

  

  

ClientEssentials

  

  

  

  

SystemDate

 

ERP 시스템에서 중요하게 다루어져야 하는 Transaction Date에 대해서 생각해 봤습니다.

X++에서 직접 SQL 실행하기

Posted by Alvin You
2014. 7. 29. 20:17 Dynamics AX/Development

X++에서 직접 SQL을 실행시키는 코드는 아래 내용을 참고 하시면 됩니다.

static void getCustomersDirectSQL(Args _args)

{

Connection userConnection;

Statement stmt;

str sqlString;

ResultSet rs;

;

 

userConnection = new Connection();

stmt = userConnection.createStatement();

sqlString = 'select * from custTable';

new SqlStatementExecutePermission(sqlString).assert();

rs = stmt.executeQuery(sqlString);

CodeAccessPermission::revertAssert();

 

while(rs.next())

{

// print rs.getString(1);

info(rs.getString(1));

}

}

Job에서 직접 코딩 후 실행시키면 아래와 같은 에러창이 뜨면서 실행이 되지 않습니다.

해당 코드는 Server 환경에서 실행되어야 하는데 Job에서는 해당 내용을 지시할 수 없어 아래 그림과 같이 Action Menu를 만들어 Run On 속성에서 Server를 지정해 주신 후 Action Menu를 실행시키시면 됩니다.

실행 결과 :

The WCF subset supported by NetCF

Posted by Alvin You
2014. 7. 24. 23:24 Dynamics AX

Dynamics AX 2012와 산업용 PDA의 연계 작업을 진행하면서 부딪힌 .NET Compact Framework의 한계 ㅎㅎ

아래 내용은 Desktop WCF와 Compact WCF간의 차이를 보여주는 내용입니다.

 

http://blogs.msdn.com/b/andrewarnottms/archive/2007/08/21/the-wcf-subset-supported-by-netcf.aspx

 

[Updated: 21Nov07 to clarify that custom headers are supported, but not in NetCFSvcUtil proxy generation]
[Updated: 27Aug07 to correct Gzip sample, and clarify on transports & extensibility]
[Updated: 23Aug07 to add SecurityAlgorithmSuite enumerable]

Many people have been asking about what subset of .NET 3.0's Windows Communication Foundation (WCF) will be supported by the .NET Compact Framework 3.5.  Well, here is a table I put together with the answer to that question:

Feature

Desktop WCF

Compact WCF

Bindings:    
· BasicHttpBinding Yes Yes
· CustomBinding Yes Yes
· WindowsMobileMailBinding N/A Yes
· ExchangeWebServiceMailBinding Yes, via NetCF install Yes
Formatters:    
· SoapFormatter Yes Yes
· BinaryFormatter Yes No
Encoders:    
· TextMessageEncoder Yes Yes
· BinaryMessageEncodingBindingElement Yes No
· MTOMEncoder Yes No
· GzipEncoder Sample available Sample available
Transports:    
· HttpTransportBindingElement Yes Yes
· HttpsTransportBindingElement Yes Yes
· MailTransportBindingElement Yes, via NetCF install Yes
· MsmqTransportBindingElement Yes No
· TcpTransportBindingElement Yes No
· (other transports) Yes No
XmlDictionaryReader/Writer Yes Yes; stub around XmlTextReader/Writer
DataContractSerializer Yes No; but can be wire-compatible with DCS via XmlSerializer
Service proxy generation Yes; via SvcUtil.exe Yes; via NetCFSvcUtil.exe, not integrated into VS2008
· Non-HTTP transports in generated proxies Yes Not built-in
· Custom headers in generated proxies Yes Not built-in
WS-Addressing Yes Yes
WS-Security message level security    
· X.509 Yes Yes
· Username/password Yes No
· SecurityAlgorithmSuite.Basic256Rsa15 Yes Yes
· SecurityAlgorithmSuite.Basic256 Yes No
WS-ReliableMessaging Yes No
Patterns    
· Service model Yes No
· Message layer programming Yes Yes
· Buffered messages Yes Yes
· Streaming messages Yes No
· Endpoint descriptions in .config files Yes No
Channel extensibility Yes Yes
Security channel extensibility Yes No

Enterprise Portal의 Listpage 표시행 수 조정하기

Posted by Alvin You
2014. 7. 23. 15:25 Dynamics AX

AX의 Enterprise Portal의 List Page의 표시되는 행수를 셋팅할 수 있는 곳은 아래 이미지의 경로인 System administration > Setup > Enterprise Portal > Enterprise Portal Parameters의 General항목에서 조정할 수 있습니다.

하지만, 위 이미지와 같이 0 ~ 100 사이가 아닌 숫자를 넣게되면 기본적으로 10개가 표시되도록 내부적으로 기본값 셋팅이 되어버립니다.

이것을 설정한 값이 그대로 Listpage에 표시되도록 하기 위해서는 AOT 환경에 들어가

Data Dictionary > Tables > EPGlobalParameters > Methods 에 있는 rowsDisplayedinListPage() 의 내용 중 아래 내용을 주석 처리하면 됩니다.

// set the return value to the default if it is an invalid value

    if (rowsDisplayed < 0 || rowsDisplayed > 100)

    {

        rowsDisplayed = 10;

    }

 

MS Dynamics AX 2012의 AIF 기능에 대한 소개

Posted by Alvin You
2014. 3. 25. 22:04 Dynamics AX

Tectura Korea 재직시절 첫 내부 세미나를 진행했던 자료입니다.

AX 2012와 외부 시스템과의 통합을 어떻게 할 수 있는지 고민해 볼 수 있었던 시간이었고, 스펀지처럼 AX 2012의 기술 요소들에 대해서 정리해 볼 수 있었던 시간이었습니다.