본문으로 건너뛰기

C# 함수 디버깅하기

컴파일러는 소스 코드에서 실행 가능하거나 참조 가능한 출력 결과물을 빌드합니다.

.NET Core는 Roslyn 이라고 불리는 컴파일러 API 를 사용하여 C# 코드를 실시간으로 컴파일하여 실행하는 .NET Compiler Platform SDK를 제공합니다.

그림) .NET Compiler API

C# 코드를 컴파일하고 실행하는 자세한 정보는 .NET Compiler Platform SDK를 참조하세요.

C# 함수는 ack 프로그램의 참조 라이브러리에 대한 종속성을 가집니다. 즉 ack 내에서 개발할 수 있는 코드를 함수로 구현 가능합니다.

C# 함수 디버깅하기

HandStack에서 제공하는 function 모듈에서 실행 가능한 CSharp 함수들은 다음과 같은 구조를 가지고 있습니다.

function
└─CSharp
└─HDS
└─HAC
└─HAC010
├─featureMain.cs
└─featureMeta.json

featureMain.cs 파일은 빌드 작업 없이 텍스트 파일로 관리되는 파일이며, featureMeta.json 파일은 함수의 메타 정보를 가지고 있습니다. 예를 들어 다음과 같이 기본적인 문법으로 간단한 LF01 함수를 만들 수 있습니다.

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.IO;

using HandStack.Core.ExtensionMethod;
using HandStack.Core.Extensions;
using HandStack.Data;
using HandStack.Web;
using HandStack.Web.Entity;
using HandStack.Web.MessageContract.DataObject;

using handsup;

using Microsoft.AspNetCore.Mvc;

using Newtonsoft.Json;

using Serilog;

namespace HDS.Function.HAC
{
public class HAC010
{
public DataSet? LF01(List<DynamicParameter> dynamicParameters, DataContext dataContext)
{
string typeMember = "HAC.HAC010.LF01";
using DataSet result = new DataSet();
try
{
result.BuildExceptionData();

string userWorkID = dynamicParameters.Value("UserWorkID").ToStringSafe();
string applicationID = dynamicParameters.Value("ApplicationID").ToStringSafe();

if (string.IsNullOrEmpty(userWorkID) == true
|| string.IsNullOrEmpty(applicationID) == true)
{
result.BuildExceptionData("Y", "Warning", "필수 요청 정보 확인 필요", typeMember);
goto TransactionException;
}

string appBasePath = Path.Combine(GlobalConfiguration.TenantAppBasePath, userWorkID, applicationID);
if (Directory.Exists(appBasePath) == true)
{
string settingFilePath = Path.Combine(appBasePath, "settings.json");
if (System.IO.File.Exists(settingFilePath) == true)
{
string appSettingText = System.IO.File.ReadAllText(settingFilePath);
var appSetting = JsonConvert.DeserializeObject<AppSettings>(appSettingText);
if (appSetting != null)
{
var dataTable = JsonConvert.DeserializeObject<DataTable>(JsonConvert.SerializeObject(appSetting.DataSource == null ? "[]" : appSetting.DataSource));
if (dataTable != null)
{
result.Tables.Add(dataTable);
}
}
}
else
{
result.BuildExceptionData("Y", "Warning", $"applicationID: {applicationID}의 앱 환경설정 파일 확인 필요", typeMember);
goto TransactionException;
}
}
else
{
result.BuildExceptionData("Y", "Warning", $"applicationID: {applicationID} 확인 필요", typeMember);
goto TransactionException;
}
}
catch (Exception exception)
{
result.BuildExceptionData("Y", "Error", exception.Message, typeMember, exception.StackTrace);
}

TransactionException:
if (result.Tables.Count == 1)
{
result.Tables.Add(new DataTable());
}

return result;
}
}
}

코드) function\CSharp\HDS\HAC\HAC010\featureMain.cs 파일 소스

{
"Header": {
"ApplicationID": "HDS",
"ProjectID": "HAC",
"TransactionID": "HAC010",
"DataSourceID": "DB01",
"LanguageType": "csharp",
"ReferenceModuleID": "handsup",
"Use": true,
"Description": "태넌트 앱 dbclient 데이터 원본 관리"
},
"Commands": [
{
"ID": "LF01",
"Seq": 0,
"Use": true,
"Timeout": 0,
"Description": "데이터 원본 데이터 목록 조회",
"ModifiedAt": "2023-07-10 00:00:00",
"Params": [
{
"id": "UserWorkID",
"type": "String",
"length": 36,
"value": null
},
{
"id": "ApplicationID",
"type": "String",
"length": 0,
"value": null
}
]
}
]
}

코드) function\CSharp\HDS\HAC\HAC010\featureMeta.json 파일 소스

C# 함수는 ack 프로그램의 종속성을 가지고 있으며 개발자는 이러한 제한을 염두하고 개발해야 합니다.

C# 함수는 컴파일 없이 텍스트로 관리됩니다. 함수 코드를 개발 및 디버깅하려면 다음중 하나의 방법을 사용할 수 있습니다.

  • 콘솔 프로젝트를 생성하여 함수 코드를 작성합니다.
  • ASP.NET Core API Controller를 추가하여 함수 코드를 작성합니다.

개인적으로는 ASP.NET Core API Controller를 생성하여 함수 코드를 작성하는 것을 추천합니다. 이유는 ASP.NET Core API Controller 프로젝트를 생성하면 함수 코드를 작성하고 디버깅하는데 Postman, Swagger 와 같은 클라이언트 도구들을 활용할 수 있어 편리하기 때문입니다.

FunctionController 작성

using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;

using HandStack.Core.ExtensionMethod;
using HandStack.Core.Extensions;
using HandStack.Core.Helpers;
using HandStack.Web;
using HandStack.Web.MessageContract.Contract;
using HandStack.Web.MessageContract.DataObject;

using handsup.Entity;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

namespace handsup.Areas.handsup.Controllers
{
[Area("handsup")]
[Route("[area]/api/[controller]")]
[ApiController]
public class FunctionController : ControllerBase
{
[HttpPost("[action]")]
public DataSet? Execute([FromBody] List<DynamicParameter> dynamicParameters, [FromQuery] DataContext dataContext)
{
string typeMember = "HAC.HAC010.LF01";
using DataSet? result = new DataSet();

// 여기에 LF01 함수 코드를 작성합니다.

return result;
}
}
}

코드) FunctionController.cs 파일 소스

FunctionController 클래스는 HAC010.LF01 함수를 실행하는 Execute 메서드를 가지고 있습니다. 이 메서드는 다음과 같은 요청을 처리합니다.

http://localhost:8000/handsup/api/function/execute?accessToken=test&loadOptions[option1]=value1&featureMeta.Timeout=0

그림) Postman API 테스트

디버깅을 하기 위한 자세한 내용은 ack 및 module 디버깅하기 문서를 참조하세요.