반응형

office 문서의  관리 / 편집을 프로그램으로 하기 위해서는 vb나 c#을 이용해야하죠. 특히 다음과 같은 마소의 본연 라이브러리로 하는데요, 기술의 발달로 .Net Framework 가 아닌 .NET core를 넘어 .NET Stardard에서 

 

Microsoft.Office.Interop.Word

Microsoft.Office.Interop.Excel

Microsoft.Office.Interop.Powerpoint

Microsoft.Office.Interop.Outlook 

의 com api를 사용하면 다음과 같은 에러메시지를 맞게 되었죠.

 

일단 이유에 대해서 설명드리겠습니다. 윈도우 전용이었던 .Net Framework 에서 cross platform을 추구하는 .NET core, .NET Standard로 넘어오면서 기본 세팅하에서는 com api를 인식할 수 없게 되었어요. com api는 윈도우에만 존재하기 때문이죠.

 

구글링했을때는 ".net core에서는 사용할 수 없다." 라고 기술되어 포기했었는데, 직접참조하면 된다고해서 도전을 다시 해봤죠. 역시나 안됐어요.

 

그렇다면 어떻게 세팅하면 사용할 수 있을까?

방법은 의외로 간단했어요.

 

platform 세팅을 any 에서 window로 바꾸는 것이죠.

 

1. 솔루션 바로 하단의 어플리케이션을 우클릭 

2. 애플리케이션 -> 일반 

 

3. 대상 OS를 찾아 기본값인 (없음)을 클릭

 

4.Windows를 클릭

 

5. 솔루션 내 종속성 우클릭 후 COM 참조 추가

(Nuget으로 microsoft.office.interop 라이브러리를 추가하면 에러가 나던데, 성공하신분 연락 또는 댓글로 방법 남겨주시기 바랍니다!!)

 

6. 필요한 라이브러리 추가 ( 스크린샷 예제에서는 Microsoft.Office.Interop.Word 를 사용하기 위해 word com object를 추가)

 

word com 객체를 추가하였고 이제 using Microsoft.Office.Interop.Word를 사용하면 라이브러리 사용이 가능하답니다.

 

 

주의할점!!!

1. 플랫폼을 바꾸면 어떻게 되느냐 - 당연히 지정한 플랫폼에서만 사용가능합니다. window10/11 등의 window os가 설치된 PC 또는 window server에서만 사용이 가능한 것이죠.

 

2. 위 예제에서 Microsoft Word 16.0 Object Library가 안보이시는 분들 특히, 이 com 객체를 추가하여 라이브러리를 사용하기 위해서는 개발된 어플리케이션이 설치될 pc에 office가 설치되어 있어야 합니다. 

 

3. 이 포스팅을 업로드하는 시점까지 확정된 microsoft의 com api 지원기간은 2029년까지로 알려져있습니다.

반응형
반응형

지난번에 example 편에서 pdf.js의 공식 웹페이지 https://mozilla.github.io/pdf.js/ 의 example 탭에 있는 pdf.js의 기본 개념들을 익혀보았습니다. 이번에는 모듈로 구현해봅시다. 웹 프레임워크는 asp.net core mvc를 사용했습니다. 어짜피 프론트 모듈에 대한 포스트이기 때문에 node.js나 스프링을 쓰시더라도 주요 포인트는 동일하기 때문에 이해가 되실 것으로 봅니다.

 

 

(지난 example편 링크 참고: https://pichen.tistory.com/66)

 

[pdf.js] 웹 pdf 뷰어 구현 - example편

아마 문서 관련 시스템을 개발하시는 분들이라면 미리보기에 대한 고민을 많이 하셨을 수 있죠. open source인 pdf.js를 소개합니다. 이 글은 2025년 1월 10일에 작성되었음을 남깁니다. 이 후 영향이

pichen.tistory.com

 

 

먼저, 내려받아 설치를 해야겠죠.

 

 

pdf.js의 웹페이지 진입 후 다운로드(Download) 버튼을 클릭합니다. 아래 캡처 이미지에서 노란색으로 칠해놓았습니다.

https://mozilla.github.io/pdf.js/ 메인페이지

 

 

 

Getting Started 페이지로 진입하는데, Introduction의 바로 아래 Download가 있습니다. 구형 브라우저를 사용하신다면 older browsers를 클릭하셔도 좋고, git을 쓰는 것이 편하시다면 Source에서 clone 하고 오셔도 됩니다. 처음에는 git으로 받아와서 썼지만, git을 못쓰시는 분들을 위해 예제로는 modern browsers의 Prebuilt Stable (v4.10.38)을 다운로드했습니다.

https://mozilla.github.io/pdf.js/getting_started/#download

 

내려 받은 파일을 압축을 풀어줍니다. 

다운로드 파일 압축 풀고 열면

 

압축을 푼 폴더를 소스의 파일시스템에 넣어줍니다. 각각 사용하시는 웹 프레임워크에서 프론트 부분에 넣으시면 되겠습니다. 참고로 저는 asp.net core mvc로 개발하기 위해 "프로젝트\wwwroot\lib"의 하위에 복사하였습니다. 

 

 

node.js 같은 경우에 초반 구성은 공식 문서에 설명을 따라가는 것이 나으실 수도 있습니다. git clone(또는 압축해제) 후 npx gulp server를 실행하면 실행은 바로 된다고 기입되어 있습니다.

 

스프링이나 asp.net core mvc 사용자는 js와 뷰파일의 위치가 분리되어있으실테니 뷰어를 사용할 위치에 viewer.html을 복사해줍니다. 복사한 위치에서는 뷰 소스 내 상대참조 부분에서 에러가 나기 떄문에 참조를 수정해줍니다.

 

<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="locale/locale.json">
<script src="../build/pdf.mjs" type="module"></script>

    <link rel="stylesheet" href="viewer.css">

  <script src="viewer.mjs" type="module"></script>
  </head>

 

view.html을 보시면 위와 같이 기입된 부분이 title부 바로 하단에 있습니다. 이 내용들을 pdf.js 라이브러리 폴더를 옮겼던 부분으로 모두 수정해줍니다.

 

저는 asp.net core mvc를 사용했기 때문에 view.cshtml로 작성하였으며, 아까 말씀드렸던 "프로젝트\wwwroot\lib" 경로를 참조하기 위해 다음과 같이 수정했습니다. 그리고 아래 '여기에 입력하세요'라고 기입된 곳에서 pdf뷰어를 실행하면 됩니다.

<!-- This snippet is used in production (included from viewer.html) -->
<link rel="resource" type="application/l10n" href="/lib\pdfjs-4.10.38-dist\web\locale\locale.json">
<script src="~/lib\pdfjs-4.10.38-dist\build\pdf.mjs" type="module"></script>
<link rel="stylesheet" href="~/lib\pdfjs-4.10.38-dist\web\viewer.css">
<script src="~/lib\pdfjs-4.10.38-dist\web\viewer.mjs" type="module"></script>

<script type="module">

// 여기에 입력하세요.

</script>

 

 

 

pdf뷰어를 경로와 함께 지정하면 실행됩니다.

<script type="module">
	PDFViewerApplication.open(서버 내 파일경로);
</script>

 

 

혹시 지난 sample편에서 base64string으로 뷰어를 띄우고 싶으신 분들 왜 정작 패키지에서는 실행할수 없을까 싶기도 할텐데요. 지난번에 말씀드렸던 개념 기억하실까요?

 

 

url은

const binary-like-data = atob ( ${base64stringData} )

==>>> { data: binary-like-data }

로 치환 가능하다는 사실!

 

 

따라서 base64string을 이용하고자 하신다면 아래와 같이 사용하시면 됩니다.

<script type="module">
    const wsu = 'fileBase64String';
    const pdfData = atob(`${wsu}`);
    PDFViewerApplication.open({data: pdfData});
</script>

 

 

저는 그리드에 문서가 있고 row를 클릭하면 우측에 사이드바로 표출되도록 개발해보았어요. 

 

쉽죠? 백엔드편을 따로 만들까하다가 프론트 모듈이다보니까 이렇게만 마무리 짓는게 나을 것 같네요. 보실 분이 있다면 작성하고 싶긴한데 제 포스트는 보는 분이 별로 없어서 ㅋㅋㅋ 이만 마치겠습니다.

반응형
반응형

아마 문서 관련 시스템을 개발하시는 분들이라면 미리보기에 대한 고민을 많이 하셨을 수 있죠.
 
 
open source인 pdf.js를 소개합니다. 이 글은 2025년 1월 10일에 작성되었음을 남깁니다. 이 후 영향이 큰 업데이트가 있다면 공식문서를 가서 확인하시는 것이 나을거예요. 
 
 
 
pdf.js의 공식문서를 보면서 따라오세요. 공식문서의 링크를 남깁니다.
https://mozilla.github.io/pdf.js/

PDF.js - Home

PDF.js A general-purpose, web standards-based platform for parsing and rendering PDFs. Download Demo GitHub Project

mozilla.github.io

 
pdf 파일처리에 대해서는 example 예제를 그냥 삽입하시면 보통 잘 나옵니다.그래서 파일부분은 공식 문서의 설명과 크게 다르지 않을 수 있습니다.
 
 
다만,  example 내에는 미리보기라면 갖춰야할 확대 축소 기능이 없기 때문에 이 기능이 필요하신 분들 또는
base64String으로 불러오는 부분에는 페이징(previous, next 버튼 및 페이지 길이 표기)도 없기 때문에
이 부분이 필요하신 분들은 본문을 계속 따라 와주시면 됩니다.
 
 
제반요건 - 인터넷 연결 필요
 
(없이 가능하도록 만들 수 있습니다. 어려운일은 아니므로 여기서는 다루지 않습니다.
다만 댓글로 문의 주시면 답변은 드리겠습니다.)
 
 
1. 링크 접속 후 상단 메뉴의 [Example]을 클릭합니다.
 
2. example 페이지 내용을 요약해서 순서대로 적어보겠습니다.
 
 
먼저 모듈을 선언하여 불러와 줍니다. 그리고 pdfjsLib을 선언하고, 라이브러리의 기본옵션을 불러옵니다. (공통)

<script src="//mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
<script type="module">

	var { pdfjsLib } = globalThis;
	pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.mjs';
  
  
	// 여기 위치에 다음내용 입력들어갑니다!


</script>

 
 
다음은 미리보기할 문서를 불러와야겠죠.
 
어떤 문서를 미리보기할지에 따라 다른데, 서버의 파일경로로 존재하는 파일 / 또는 base64String 상태의 파일을 모두  불러 올 수 있습니다.
 
a. 서버경로의 파일을 불러오는 방법

var pdfFileUrl = 'https://어쩌구/저쩌구/test.pdf'
var loadingTask = pdfjsLib.getDocument(pdfFileUrl);

 
b. base64String 형식의 데이터를 불러오는법

var pdfFileBase64Data = atob('베이스64스트링')
var loadingTask = pdfjsLib.getDocument({data: pdfFileBase64Data});

 
a,b에서 보는바와 같이 getDocumenturl 또는 {data: ${atob('base64string')} }를 입력받습니다. 한 번더 강조하는 이유는 이미 고민하고 들어와서 아실 분들도 있을 것이고 아예 처음오신분들은 나중 설명에서 필요하니 기억해두도록 합시다!
 
 
데이터로 선언한 loadingTask는 promise 속성을 가지고 있어 resolve로 불러온 pdf파일을 객체로 돌려줍니다.

loadingTask.promise.then(function(pdf) {
  // 공식 pdf.js 문서와 같이 이 자리부터 pdf파일을 다룰 수 있습니다.
});

 
이제 pdf 파일을 다룰 수 있고, 이후 기본적인 pdf.js의 흐름은 다음과 같아요.
페이지 불러오기 -> 불러온 페이지를 렌더링하기
 
공식페이지 예제 바탕으로 간단하게 써보자면 아래와 같습니다.

// pdf의 페이지를 가져온다.
pdf.getPage(1).then(function(page) {

    // 불러온 페이지를 렌더링한다.
    var scale = 1.5;
    var viewport = page.getViewport({ scale: scale, });
    // Support HiDPI-screens.
    var outputScale = window.devicePixelRatio || 1;

    var canvas = document.getElementById('the-canvas');
    var context = canvas.getContext('2d');

    canvas.width = Math.floor(viewport.width * outputScale);
    canvas.height = Math.floor(viewport.height * outputScale);
    canvas.style.width = Math.floor(viewport.width) + "px";
    canvas.style.height =  Math.floor(viewport.height) + "px";

    var transform = outputScale !== 1
      ? [outputScale, 0, 0, outputScale, 0, 0]
      : null;

    var renderContext = {
      canvasContext: context,
      transform: transform,
      viewport: viewport
    };
    page.render(renderContext); 
});

 
앞서 설명드린내용을 모두 이어서 써서 보여드리겠습니다. pdf 파일은 공식문서의 것을 그대로 사용합니다. ( 혹시 저작권 문제가 있다면 즉시 삭제하겠습니다. )
 

// 모듈 선언 후 불러오기
<script src="//mozilla.github.io/pdf.js/build/pdf.mjs" type="module"></script>
<script type="module">

	// 기본 라이브러리 및 옵션 정보 불러오기
	var { pdfjsLib } = globalThis;
	pdfjsLib.GlobalWorkerOptions.workerSrc = '//mozilla.github.io/pdf.js/build/pdf.worker.mjs';
  
  	// 파일주소로 페이지를 불러올 task 생성
	var pdfFileUrl = 'https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf'
	var loadingTask = pdfjsLib.getDocument(pdfFileUrl);
	
    // 프로미스로 리졸브를 pdf 객체로 반환받는다.
    loadingTask.promise.then(function(pdf) {

      // pdf의 페이지를 가져온다.
        pdf.getPage(1).then(function(page) {

            // 불러온 페이지를 렌더링한다.
            var scale = 1.5;
            var viewport = page.getViewport({ scale: scale, });
            // Support HiDPI-screens.
            var outputScale = window.devicePixelRatio || 1;

            var canvas = document.getElementById('the-canvas');
            var context = canvas.getContext('2d');

            canvas.width = Math.floor(viewport.width * outputScale);
            canvas.height = Math.floor(viewport.height * outputScale);
            canvas.style.width = Math.floor(viewport.width) + "px";
            canvas.style.height =  Math.floor(viewport.height) + "px";

            var transform = outputScale !== 1
            ? [outputScale, 0, 0, outputScale, 0, 0]
            : null;

            var renderContext = {
            canvasContext: context,
            transform: transform,
            viewport: viewport
            };
            page.render(renderContext); 
        });
    });

</script>
<h1>PDF.js 'Hello, world!' example</h1>

<p>Please use <a href="https://mozilla.github.io/pdf.js/getting_started/#download"><i>official releases</i></a> in production environments.</p>

<canvas id="the-canvas"></canvas>

 

[위소스의 html 구현완료 부 예제] 구분선 시작

 

PDF.js 'Hello, world!' example

Please use official releases in production environments.

[위소스의 html 구현완료 부 예제] 구분선 끝

 
이제 기본은 끝났습니다.
 
약간의 응용을 시작하겠습니다. 간단하게, previous버튼, next버튼, (문서 길이 + 현재 페이지), 확대 축소를 구현해보겠습니다. 

 
 
먼저 previous 버튼, next 버튼 구현입니다.
구현이라고 말씀드렸으나 이 두 버튼은 공식문서 example 페이지 내에 있습니다.
그러나 굳이 설명드리는 이유, 본문 서두에 말씀드렸지만 base64string의 예제는 없기 때문입니다.

 
아까 기억하라고 말씀드렸던 getDocument의 변수에는 서버파일의 경로와 base64string을 입력하는 data방식이 있었죠.
getDocument을 호출할때 입력하는 변수파일경로 문자열{data: 베이스64스트링 } 으로 교체만 해주면 됩니다!
 
[Previous/Next example]의 html 소스 내에서 getDocument 부분은 단  한 군데 존재합니다. 이것을 atob(base64string)로 받아온 byteArray-like data로 {data: 'byteArray-like data' } 대체해주면 됩니다. 아래 이미지에 표시해두었으니 참고하시기 바랍니다.

 
 
다음 확대 축소 구현입니다. 이 부분을 읽으시면 다른 속성들도 변경할 아이디어를 챙기실 수도 있을 것 같아요.
 
 
[Previous/Next example] 예제를 기준으로 설명드리겠습니다. 라이브러리 선언, 라이브러리 옵션이 추가된 다음 줄에 변수를 6개 선언하는데요, 이 중 크기를 나타내는 변수는 scale입니다.
 
 
그리고 그 아래 페이지를 랜더링하는 함수가 있죠. 자세히 뜯어 보실 필요는 없으나, 아래 이미지에서 표시한 부분, scale에서 이 부분을 입력 받음을 알 수 있습니다. 따라서 scale 변수를 변경하고, renderPage함수를 호출한다면 사이즈가 조정된다고 판단할 수 있습니다.

 
 
일단 확대 축소를 마우스 휠 등의 이벤트로도 하실 수 있겠지만, 저는 간단한 구현을 위해 확대 버튼과 축소 버튼을 구현하겠습니다.
 

<button id="zoomOut">&nbsp;-&nbsp;</button>
<button id="zoomIn">&nbsp;+&nbsp;</button>

 
 
scale은 한 페이지 내에서는 전역변수 이기 때문에 renderPage함수를 손대실 필요는 없고 scale만 어떤 이벤트로 변경해주면 되겠죠. 저는 확대 축소 버튼을 구현했으므로, 클릭이벤트를 통해 확대 축소를 하겠습니다.

function onZoonIn() {
    if (scale >= 2) {
        return;
    }
    scale += 0.1;
    queueRenderPage(pageNum);
}
document.getElementById('zoomIn').addEventListener('click', onZoonIn);


function onZoomOut() {
    if (scale <= 0.3) {
        return;
    }
    scale-=0.1;
    queueRenderPage(pageNum);
}
document.getElementById('zoomOut').addEventListener('click', onZoomOut);

 
 
 

반응형
반응형

vmware 공식 발표 타이틀

 

 

회사에서 VMWare workstation  Pro 15의 굴레에 갇혀있었는데 희소식이 있습니다.

 

 

 

VMWare를 인수한 Broadcom은 2024년 12월 11일 전면무료화를 선언했다는 점이죠.

 

AMD CPU 사용중인 window 11 Pro 사용자들에게 제약점이 많았죠. core수를 1개 넘게 가상머신을 생성하면 가상머신에서 access violation ( 0xc0000005 Exception)을 내뱉거나, 구동후에도 vmware tools 를 설치하지 않은 상태에서는 호환이 안되서 너무 느린 등의 문제 말이죠.

 

그러나 이제는 고통은 안지 않아도 됩니다. Broadcom에서 상업 무료화를 선언했기 때문이죠.

 

 

변경사항이 사용자들에게 미치는 영향

Vmware fusion pro와 workstation pro는 이제 유료 또는 구독이 아닙니다.

무료로 사용할 수 있습니다.

다만, 앞으로는 유료버전을 더 이상 구매할 수 없습니다. 이미 구매했던 사용자에 대한 cs지원은 계속될 전망이다.

 

 

이전의 개인 무료버전인 player는 스냅샷 캡처 등은 동작하지 않았는데, Pro가 무료화 되다보니 기존 유료 Pro버전에서 사용하던 모든 기능을 이용할 수 있다고 합니다.계약이 활성화 된 고객은 계속 적으로 지원포탈이나 지원팀에 연락하여 도움을 받을 수 있으나, 문제해결을 위한 support ticket 생성은 더이상 제공하지 않는다고 하네요.

 

그러나 무료화와 같이 지원 문서, 사용자 가이드, 커뮤니티 포럼으로 다양한 리소스를 활용할 수 있도록 하겠다는 공지사항입니다.

 

 

 

예상컨데 도커 등의 등장으로 사용자가 감소하고 있는 추세에 사용자들을 늘리고 협업, 커뮤니티, 피드백 등을 통한 성장을 바라보고 있을 것 같아서 긍정적으로 판단해도 단기적으로는 나쁘진 않을 정책인 것 같아요. 구버전의 VMWare Workstation Pro를 사용하기 위해 OS를 다운그레이드하는 슬픈일은 없어지겠네요.

 

다운로드 하는 방법은 broadcom vmware 홈페이지에 가입 후 로그인하여 시도하면 된답니다!

 

 

원문 및 관련링크

https://blogs.vmware.com/cloud-foundation/2024/11/11/vmware-fusion-and-workstation-are-now-free-for-all-users/

https://knowledge.broadcom.com/external/article?articleNumber=368667

 

 

 

 

 

반응형

'Common > Infra' 카테고리의 다른 글

[open source / airbyte] sql server 연결 테스트  (0) 2024.08.14
반응형

Window 운영체제에 내장된 작업스케줄러를 설명드리겠습니다.

 

먼저 작업스케줄러를 실행하는 방법은 다음과 같습니다.

 

  • 시작 메뉴를 열고, "작업 스케줄러" 또는 **"Task Scheduler"**를 검색
  • 또는 Win + R을 눌러 실행 창을 열고, taskschd.msc를 입력
  • 시작 메뉴(Start Menu) -> 프로그램(Programs) -> 관리자 도구(administrative tools) -> 작업스케줄러(task scehduler)
  • 탐색기에서 C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Administrative Tools

 

 

 

 

별도의 설정을 하신 적이 없다면 실행하면 아래와 같이 나오실 것입니다.

 

 

 

 

 

먼저 추가할 작업을 모아둘 폴더를 하나 만들겠습니다.

 

 

 

 

TestFolder라는 이름으로 만들었습니다.

새로만든 폴더를 클릭하고 우측의 Create Task 또는 가운데 하얀 부분에서 우클릭 후 Create new Task를 클릭합니다.

 

 

그러면 작업을 생성할 창이 나오는데요, 이름과 설명은 자율적으로 정하셔도 되겠습니다.

 

 

Run whether user is logged on or not.은 피시가 켜져있다면

사용자로그인이 되어있지 않아도 프로그램을 돌릴지 여부입니다.

 

이 설정은 관리자 계정이어야 가능합니다.

보통은 개발자가 서버에 세팅한다고 생각한다면 주기 작업 등에는 아래와 같이 세팅하시면 되고,

기본 값은 Run only when user is logged on 입니다.

 

 

 

 

 

 

다음은 Trigger 입니다. 영단어 뜻에서와 같이, 어떤 조건이 작업을 실행하게 만들지 정하는 탭입니다.

하단에 new를 눌러보시죠.

 

 

 

 

아래와 같은 창이 나올텐데요. Begin the task에는 조건이 나옵니다.

순서대로

 

주기작업

PC 로그온시

부팅시

...

등이 가능합니다.

 

 

 

이 포스트에서는 주기작업과 PC로그온, 부팅 세가지를 설명드리겠습니다.

1. At start up - 부팅시

 - 단순해서 가장 먼저 적었습니다. 부팅시에는 별도의 디테일한 조건을 달 수 없습니다.

부팅시 이루어질 작업을 action에서 추가하면 되겠습니다.

 

 

2. At log on - PC 사용자 로그온시

 - 모든 사용자 또는 특정 사용자가 로그온 할때를 지정할 수 있습니다.

 

 

3. On a schedule - 계획에 따라 작업

 - 현업에서는 이 기능을 가장 많이 썼던 것 같습니다. 주기작업, 일정 작업

 

 

One time은 지정한 일시에 한 번 실행되도록 하는 trigger 입니다.

 

 

 

 

Daily는 지정한 일시부터 1일 간격으로 반복 하도록 합니다.

 

 

Weekly는 지정한 일시부터 매주 반복하며, 요일도 지정할 수 있습니다.

매주 x요일,y요일 n시 n분을 지정하여 사용할 수 있게 되는 것이죠.

 

Monthly는 일년동안 실행될 날짜들을 모두 추가할 수 있습니다.

어느 월에(복수선택, 전체선택, 단일선택 모두 가능), 몇 일에( 복수선택, 전체선택, 단일선택 모두 가능하며 마지막날도 지정가능) 또는 어느 월에 몇번째 무슨요일에 이렇게도 지정이 가능합니다.

 

 

그런데 이런생각도 하실 수 있습니다. 나는 일간보다 더 작은 간격으로 작업을 반복하고 싶은데?

5분간격 1분간격 1시간간격

 

 

그런 경우에는 하단의 Advanced settings를 이용하시면 됩니다.

임의 간격 지정이 가능하며

repeat task every은 반복될 시간으로 select box를 눌러서 나오는 시간 외에도 숫자 + 단위를 기입하면 입력이 가능합니다. for a duration of 는 반복될 기간입니다.

 

프로그램에 이상이 있을 경우 stop task 류의 세팅을 이용 하실 수 있습니다. 너무 오래돌아가면 작업을 종료시킨다. 라는게 Stop task if it runs longer than: 입니다.

 

 

 

지정하고자 하는 Trigger를 입력하셨다면 Ok버튼을 눌러줍니다.

 

 

Action으로 넘어가겠습니다.

action 탭에서 new 버튼을 클릭하면 다음과 같은 action을 취할 수 있습니다.

다른 조건들이 deprecated 되었기 때문에 프로그램 실행이 가능하다고 생각하시면 되겠습니다.

program/script의 browse...버튼을 통해 실행할 스크립트 파일이나 프로그램을 추가하면 됩니다.

이메일 보내기도 발송프로그램을 만들어서 실행한다면 동작합니다.

 

 

Condition과 Settings 탭은 이미 설정한 내용이 겹쳐있거나 특별히 설명이 필요한 부분이 없으니 읽어보시면 되겠습니다.

Ok를 누르면 로그인한 계정 또는 관리자 계정의 비밀번호를 기입합니다.

 

 

 

지정한 일자에 실행되는 작업스케줄러를 등록하였습니다.

 

반응형
반응형

github에는 작성해놓았는데 블로그에는 이것조차 없네요. 머쓱

 

20241217 - 불필요부분을 뺀다고 뺐는데도 작성길이가 길어 현재 본문에서는

라이브러리 사용시 알아야할 내용과 Get방식만 설명드립니다.

 

 

참고로 .NET Standard 6.0 부터 사용해보았기 때문에

이전 버전은 다르던데 어떻게하는거냐라고 물으신다면 저도 모를꺼예요.

특히 System.Net.Http.Json는 Newtonsoft.Json이 .NET Standard에 와서 System.Text.Json으로 내장되면서 생긴 것으로 알고 있어서, 이전 버전에 없을 확률이 높습니다.

 

 

 

HTTP기초를 먼저 작성하면 좋았을텐데,,, 이 것 부터 쓰게 되네요.

우선 다른데서 공부하고 오셨다는 전제하에 작성해보겠습니다.

 

 

System.Net.Http / System.Net.Http.Json 라이브러리를 사용하기위해 근간에 되는 HttpClient의 인스턴스를 선언합니다.

예제에서는 단순하게 선언하겠습니다.

 

참고로 실제 서버나 프로그램에서 사용하시게되면 httpClientFactory에 넣어서 CreateClient로 가져오시면 매번 선언하지 않고 자원을 아끼면서 적절하게 사용하실 수 있을텐데요. 

 

여기서는 호출방법 자체에 포인트를 맞추고 있어 따로 다루지 않습니다.

(위 내용도 궁금하신 분들은 IHttpClientFactory 인터페이스를 참조하세요.)

 

HttpClient httpClient = new(){
    // 기본 URL 설정
    BaseAddress = new Uri("https://api.example.com/"),

    // 타임아웃 설정 (예: 30초)
    Timeout = TimeSpan.FromSeconds(30)
};

 

 HTTP 메소드에 따라 의 용법도 조금씩 다릅니다.

 

HTTP 헤더 입력값
httpClient.DefaultRequestHeaders.Add("Key", "Value");

위와 같은 형태로 헤더를 입력합니다. 영어를 보시면 Default Request Headers에서 감이 오시는 분이 있을까요?

이렇게 헤더를 추가하게 되면, 같은 인스턴스의 httpClient를 호출할때 항상 헤더값에 입력되게 됩니다.

 

따라서 하나의 httpClient 인스턴스를 돌려쓰시면서, 헤더값을 다르게 해야한다면,

아래의 첫문단과 같이 Clear를 해줍니다.

 

항상 같게 해줘야한다면 아래의 if문과 같이 추가해주는 것이 안정적인 방법일 것입니다.

httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Clear();

if (!httpClient.DefaultRequestHeaders.Contains("Key"))
    httpClient.DefaultRequestHeaders.Add("Key", "Value");

 

GET 방식

본문 상단에서 httpClient를 선언할때 baseAddress를 적어주었기 때문에 호출할때는 뒷부분(endpoint)만 작성하면 됩니다.

 

.NET Standard에 오기전 구 버전에서는 HttpRequestMessage로 작성하여 이것저것 넣어줘야 했다면, 비동기 방식의 System.Net.Http 메소드는 사용이 아주 간편합니다.

string endpoint = "/class/students"
HttpResponseMessage response = await httpClient.GetAsync(endpoint);

 

요청이 성공했는지 보는 방법은 단순합니다.

response.StatusCode에 HTTP status code가 반환됩니다.

 

 

System.Net.Http에서 제공하는 enum type의 HttpStatusCode 중 일부를 정리해보았습니다.
HttpStatusCode.{아래 알파벳}으로 사용하시면 되겠습니다.

다만 목록의 코드별 내용을 자세히 설명하기에는 너무 길어 예제에서 사용하는 것들 정도만 언급드리겠습니다.


ex) if (response.StatusCode ==HttpStatusCode.OK)
또는 if (response.StatusCode == 200)

200번대
OK = 200, Created = 201,  Accepted = 202, NoContent = 204, ResetContent = 205
   
300번대
Ambiguous = 300, Moved = 301, Found = 302, Redirect = 302, RedirectMethod = 303,  Unused = 306,        TemporaryRedirect = 307, PermanentRedirect = 308

400번대
BadRequest = 400, Unauthorized = 401, Forbidden = 403, NotFound = 404, MethodNotAllowed = 405,        NotAcceptable = 406, RequestTimeout = 408, RequestEntityTooLarge = 413, RequestUriTooLong = 414,        UnsupportedMediaType = 415,      

500번대
InternalServerError = 500, NotImplemented = 501, BadGateway = 502, ServiceUnavailable = 503,        GatewayTimeout = 504,

 

Get 방식의 http method는 정보의 조회 등인 경우가 많아 대부분 200번 즉 response.StatusCode 가 HttpStatusCode.OK일 거예요. 다만, 구체적으로 반환되는 HTTP Status Code는 API를 제작한 개발사/개발자에 문의 또는 설명문서를 참조하여 정하시는 것이 좋겠습니다.

 

다만, 200번대가 보통 성공을 나타낸다고 약속되어져 있습니다. (제가 약속한거 아닙니다.)

따라서 다음과 같은 방법으로 200번대면 성공이라고 가정, 아니면 실패를 예외를 던지는 속성과 함수도 존재합니다.

// response.IsSuccessStatusCode: response가 200번 대면 true를 반환하는 bool값

if(response.IsSuccessStatusCode) {
// 성공
}



// if문도 필요 없이 200번대면 다음 레코드를 읽고, 200번대가  아니면 예외를 던지는 함수
response.EnsureSuccessStatusCode();

 

응답이 성공했으면 원하는 응답을 읽어와야하고, 그 방법에는 여러가지가 있을텐데요. 두가지를 설명드리겠습니다.

 

1. 응답을 모두 string으로 받아오는 방법

c#의 함수나 속성명은 상당히 직관적입니다.

[응답][내용][문자열]으로 불러오겠습니다.

(response)(content)(string)

var responseContent = await response.Content.ReadAsStringAsync();

 

 

그런데 대부분은 string 자체를 사용하진 않을 것입니다. 약속된 API라면 반환값이 json형태의 문자열이기 때문이죠.

따라서 json형태의 문자열을 다음과 같이 클래스로 바꿔줍니다.( System.Text.Json 필요)

var result =  JsonSerializer.Deserialize<ResultClass>(responseContent, new JsonSerializerOptions());

 

JsonSerializerOptions 옵션 등과 같은 System.Text.Json의 고유 기능은 제가 자세히 설명해놓은 글

(링크:  https://pichen.tistory.com/52 ) 을 참조하시기 바랍니다.

 

[.NET 라이브러리] System.Text.Json

안녕하세요. 예전에 NewtonSoft.Json 라이브러리를 설명드렸었는데요. 이번엔 System안에 속한 Json 컨버팅 라이브러리를 설명드리도록 하겠습니다. NewtonSoft.Json( [c# dotnet nuget] Newtonsoft.Json (tistory.com) )

pichen.tistory.com

저의 경우 NewtonSoft.Json은 .Net Framework에서는 많이 사용했지만. Net Standard에 와서는 내장된 System.Text.Json을 적극 사용하고 있습니다. 특히 아래 2번 방법과 JsonSerializerOptions 을 공유하고 있기 때문에 사용하시는 것을 권장드립니다.

 

 

 

2. 응답내용을 불러올때 클래스로 만드는 방법입니다. (using System.Net.Http.Json 필요)

ResultClass result = await response.Content.ReadFromJsonAsync<ResultClass>();

저는 보통 클라이언트 호출부를 함수로 만들어

return await response.Content.ReadFromJsonAsync<ResultClass>();

형태로 사용하거나 var로 선언하긴하지만, 여러분에게 명시적으로 보여드리기 위해 클래스로 선언부를 작성하였습니다.

개발 초기에는 응답내용을 전부 로그를 찍기 위해 1번으로 시작할때도 있지만, 주로 2번을 사용하고 있습니다.

ReadFromJsonAsync의 정의를 보면, System.Text.Json의 JsonSerializerOptions 옵션을 공유합니다.

null처리, 기본값 처리 등을 손쉽게 할 수 있고, 그에 따라 api의 상세한 요구조건을 컨트롤 할 수 있으니 반드시 알아두시면 좋겠습니다.

 

ResultClass가 무엇인가요? 라고 물으실 수 있을 것 같아요. 아무렇게나 작성한 임의의 클래스입니다.

{"number": 1} 이라는 형태의 json이 왔고 약속된 형태라면,

ResultClass은 아래와 같이 정의가 되었을 것입니다.

class ResultClass{

	public int Number {get; set;}

}

// 또는

class ResultClass{

	[JsonPropertyName("number")]
	public int Sequence {get; set;}
    
}

 

serialize했을때 json이 되는 클래스를 만들었다라고 보시면 되겠습니다.

이 포스트는 json, json과 클래스의 관계에 대한 설명글이 아니기 때문에 이 정도만 작성하도록하고, 여태까지 설명 내용을 한 번에 보실 수 있도록 담아보겠습니다.

 

// json문자열을 역직렬화할 Model 클래스
class ResultClass{

	[JsonPropertyName("number")]
	public int Sequence {get; set;}
    
}


// HttpClient 선언
HttpClient httpClient = new(){
    BaseAddress = new Uri("https://api.example.com/"),
    Timeout = TimeSpan.FromSeconds(30)	// 굳이 적지 않아도 되나 기본값이 30초
};

// 필요시 헤더 추가
if (!httpClient.DefaultRequestHeaders.Contains("Key"))
    httpClient.DefaultRequestHeaders.Add("Key", "Value");

// Get 방식 호출
HttpResponseMessage response = await httpClient.GetAsync("/class/students");

// 성공 여부 검증
response.EnsureSuccessStatusCode();

// 성공시 json을 역직렬화하여 변수에 담는다.
var result = await response.Content.ReadFromJsonAsync<ResultClass>();
반응형
반응형

폴더 형태의 구조를 담은 DB 또는 그러한 형태를 반환하는 API를 경험할 일이 많아졌다.

 

[상위폴더 여부 | 상위 폴더 Id | 폴더 Id | 폴더 이름]

 

간추려 위와 같은 컬럼이 있는 DB가 있거나,

유사형태의 값을 반환하는 API를 만났다.

 

DB만 있었다면 DB에서 recurrsive 테이블로 재귀로 뽑아 내는 것도 방법이겠지만

API를 사용해야만 하는 시점에서는 위 형태의 반환 값을 폴더구조로 풀어내는 것에 대한 고민이 있었다.

 

(공부 뒤 블로그나 github에 올리지 못한 내용이 더 많아서 공부를 뜨문뜨문한다고 보실 분들도 있겠지만...

필자는 계속 책을 구매하거나 인강을 듣거나 아주 작은 단위의 프로젝트를 혼자 진행하며

공부하고 찾아보면서 학습중이었다는 점....)

 

 

그러다 DFS를 여기 적용할 수 있겠다는 생각이 들었다.

이 포스트에서는 그러한 예제를 풀어가려한다.

 

 

재직회사에서 C#을 쓰고 있어 C#으로 개발하였으니 다른언어를 하셨더라도 원리로 가져가면 될 것 같다.

 

 

특히,

폴더명으로 검색하기에는

a \ b

a \ c \ b 

의 경우 처럼 이름은 같지만 다른 위치에 있는 것을 프로그램은 구분해서 조회할 수 없기 때문에 폴더구조로 뽑아오거나 id를 뽑아오는 것은 매우 필연적이기 떄문에 이 작업이 필요할때가 많다.

 

 

먼저 아래와 같은 클래스를 작성했다.

DB에서 4개 컬럼을 읽어다 넣었거나, API 반환값이거나, 혹은 읽거나 받은 정보를 여기에 담았다고 가정하자.

class Folder
{
    public int ParentId { get; set; }
    public int Id { get; set; }
    public bool HasParent { get; set; }
    public string Name { get; set; }
    
    public string NameHierarchy { get; set; }
    public string IdHierarchy { get; set; }
}

 

 

Folder 클래스의 인스턴스에 HasParent, ParentId, Id, Name이 기입 되어있는 List가 있다고 가정하자.

(NameHierarchy, IdHierarchy는 폴더구조를 \ 구분자로 만들 필드로 처음엔 빈칸으로 시작한다고 가정한다.)

List<Folder> wholeFolders = new List<Folder>();

 

 

DFS 알고리즘을 적용하기 위해 시작 노드를 정리할 필요가 있다.

다만, 폴더구조를 로그를 찍었을때 직관적으로 더 잘 보이게 하기위해 visited는 생성하지 않는다.

 

HasParent 같은 친절한 필드 또는 컬럼이 없는 경우가 있겠지만 그런경우에는 parent id가 null이거나 0 등 특별히 최상위 폴더를 알 수 있는 조건이 있을 것이다. 여기서는 HasParent가 true가 아니면 최상위 폴더이다.

List<Folder> rootfolders = wholeFolders.Where(f => !f.HasParent)
				.ToList();

 

 

위에서 filtering한  인스턴스들을 Stack을 선언하여 노드로 push한다.

최상위 폴더는 폴더이름, 폴더 id 자체가 폴더구조 이므로 이 값을 Hierarchy류 필드에 넣는다.

Stack<Folder> stack = new Stack<Folder>();
foreach (var rootfolder in rootfolders)
{             
    rootfolder.IdHierarchy = rootfolder.Id.ToString();
    rootfolder.NameHierarchy = rootfolder.Name;
    stack.Push(rootfolder);
}

 

 

이제 루프를 돌린다.

첫 번째 순회에서는 root folder들을 stack에 쌓았으므로

가장 마지막 node를 pop하여, 전체 폴더 중에서 parent id가 root folder의 id와 동일한 폴더들을 찾아 리스트로 반환하게 된다.

그렇게 조회한 하위 폴더를 상위폴더\현재폴더 값으로 Hierarchy류에 입력하고 stack에 push한다.

다음루프에서는 방금 중 가장마지막에 push한 폴더를 꺼내 다시 한번 절차를 거치게 된다.

이렇게. 최상위폴더에서 최하위 폴더까지 순회 후 다음 노드로 넘어가게 된다.

Folder folder = new Folder();
while (stack.Count > 0)
{
    folder = stack.Pop();               
    foreach (var child in wholeFolders.Where(f => f.ParentId == folder.Id))
    {
        child.NameHierarchy = $@"{folder.NameHierarchy}\{child.Name}";
        child.IdHierarchy = $@"{folder.IdHierarchy}\{child.Id}";
        stack.Push(child);
    }
}

 

한번에 작성해보면

List<Folder> wholeFolders = new List<Folder>(); // 무언가 조회된 것이라 가정한다.

Stack<Folder> stack = new Stack<Folder>();
foreach (var rootfolder in wholeFolders.Where(f => !f.HasParent)) // 1회 순회 - IEnumerable사용
{             
    rootfolder.IdHierarchy = rootfolder.Id.ToString();
    rootfolder.NameHierarchy = rootfolder.Name;
    stack.Push(rootfolder);
}


Folder folder = new Folder();
while (stack.Count > 0)
{
    folder = stack.Pop();               
    foreach (var child in wholeFolders.Where(f => f.ParentId == folder.Id))  // 1회 순회 - IEnumerable사용
    {
        child.NameHierarchy = $@"{folder.NameHierarchy}\{child.Name}";
        child.IdHierarchy = $@"{folder.IdHierarchy}\{child.Id}";
        stack.Push(child);
    }
}


class Folder
{
    public int ParentId { get; set; }
    public int Id { get; set; }
    public bool HasParent { get; set; }
    public string Name { get; set; }
    
    public string NameHierarchy { get; set; }
    public string IdHierarchy { get; set; }
}

 

DFS를 폴더구조화에 적용한 예제였다. DFS가 나같은 비전공자에게는 한번에 와닿지 않으나, DFS의 개념을 이해는 못한체 외우고만 있다가 필요할때 써보려고하니 어떤 로직으로 어떻게 적용되는지 이해가 되어 기뻤던 개발이었다.

 

 

반응형
반응형

처음 개발을 공부할때 자바스프링을 인텔리제이를 구매해서 사용하겠다고 맥북을 사고는 homebrew를 애용했어요. 자바 스프링을 사용하던 회사에 문제가 많아 3개월 후 퇴사하고나서 c# .net을 사용하는 회사로 이직했는데요.

 

window를 사용하는 곳에 입사하다보니 window 노트북도 다시 세팅을 했고 맥북의 homebrew 같은 친구가 window에 있을까? 고민 하던 중 chocolatey를 알게 됐었죠. 한참을 당연하게 생각하고 있다가 최근에 RabbitMQ를 설치할 일이 있어서 설치 문서를 보다가 chocolatey가 있어서 겸사겸사 포스트합니다.

 

 

chocolatey의 공식 홈페이지 https://community.chocolatey.org/

 

Community

Chocolatey is software management automation for Windows that wraps installers, executables, zips, and scripts into compiled packages. Chocolatey integrates w/SCCM, Puppet, Chef, etc. Chocolatey is trusted by businesses to manage software deployments.

community.chocolatey.org

 

 

공식 홈페이지를 접속하면 Install Chocolatey가 바로 보입니다.

 

 

먼저 선행조건 - window, powershell v2+ (윈도우 10, 11 사용자는 그냥 된다고 보셔도 무방합니다.)

.net 4.8 설치 

 

영어를 할 줄 아신다면, 공식 홈페이지 쭈욱 따라 가시면 됩니다.

 

영어가 익숙치 않은 분들을 위한 포스팅에 가깝다고 보시면 되겠습니다. 그러나 업계 특성상 시간이 조금만 흘러도 내용이 변경 되기 때문에 공식 홈페이지와 이 포스트간에 차이가 있다면 무조건 공식 홈페이지를 따르시는 것이 좋습니다. 영어를 설사 거의 하시 못하더라도 명령어 - copy 부분은 개발자니까 알아보실 거라고 믿어요!

 

 

설치가 완료되면 powershell을 실행합니다.

 

powershell의 Get-ExecutionPolicy의 기본값이 Bypass가 아닌 경우가 많은데, 

 

Get-ExecutionPolicy를 cmd에서 입력 후에 Restricted가 나오면 

Set-ExecutionPolicy AllSigned 또는 Set-ExecutionPolicy Bypass -Scope Process를 입력하시면 됩니다.

 

 

다음 

Set-ExecutionPolicy Bypass -Scope Process -Force; [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))

를 입력합니다.

 

(계속 말씀드리지만 2024년 8월 20일 기준으로 번역에 가깝기 때문에 이러한 명령어의 복사 자체는 포스트의 것이 아닌, 공식 홈페이지를 방문하여 기술된 문구를 복사하는 것을 권장드립니다. 시간이 경과하여 문구가 바뀐 것은 포스트에서 팔로우 할 수 없음을 계속해서 말씀 드립니다.

 

 

 

설치가 완료된 것이예요! 명령어를 알고 있는 패키지는 cmd를 치셔도 되고

 

공식 홈페이지에서 검색을 하셔도 좋습니다. Looking for Packages를 클릭 후 검색하시면 되는데요,

 

본문 초에 말씀드렸지만 RabbitMQ를 설치하려던 것이기 때문에 그것을 검색헀어요.

cmd나 powershell에서 우측의 복사버튼을 누른뒤 붙여넣기 하시면 설치가 실행됩니다!

반응형

+ Recent posts