2007/02/07 00:39

갑자기 불연듯 엉뚱한? 생각이 들었다.

 

과연 이런 동작이 될까??

 

1. 클라이언트가 웹페이지를 호출한다.

2. 웹서버는 수십분의 시간이 걸리는 작업 처리 후 응답한다.

 

요런거 냅따 단순 코딩으로 테스트 해보면 되지라는 생각에...

 

VS.NET 2003을 열고 (2005는 내 놋북이 넘 힘들어 한다) 코딩으로 들어갔다...

 

대략적인 코드는...

 

TextBox1에는 작업전의 시간을

 

TextBox2에는 작업후의 시간을

 

그리고... 많이 걸리는 작업을 흉내내기 위해서

 

System.Threading.Thread.Sleep(); 을 이용했다.

 

10분...20분...30분...1시간... 우와~ 거뜬하다... 나만 몰랐던 것인가....ㅠ

 

하지만 만약에 이런 경우를 해야 하는 상황은 웹서비스이다.

 

즉, 클라이언트가 웹서비스를 호출하면 웹서비스는 위에서 말한 수십,수백분의 시간후 결과를

 

리턴해주어야 한다.

 

과연...이게 될까??

 

테스트 해본 결과 작업시간이 초과 되었다는 에러메세지가 나온다.

 

된장...웹서비스는 안된단 말인가...

 

WebService 객체를 생성한 후 객체명. 을 찍어 멤버들을 살펴보니...

 

Timeout속성이 눈에 확~!! 들어오는 것이 아닌가...

 

그 속성의 툴팁엔WebClientProtocol.Timeout이라고 나온다.

 

그리하여... 재빠르게 나의 구세주 MSDN을 열고 뒤지기 시작했다...

 

이 속성은 XML Web services 클라이언트에서 동기 XML Web services 요청이 완료될 때까지 대기하는 시간(밀리초)을 나타냅니다.

 

그런데 Default값이 100000 밀리초다. 음...이 속성값을 늘려주면 되겠지??

 

웹서비스가 작업하는 시간보다 조금 더 시간을 길게 잡아주었다.

 

테스트 시작....Very Good~

 

간단하면서 블로그에 올리긴 좀 민망한 글이 될 수도 있지만 누군가가 이 에러때문에 검색을 할지도 모르니...ㅋ

 

결론은 웹서비스를 호출하는 클라이언트에서 작업시간 초과 에러가 나올 경우

 

클라이언트 프로그램에서 WebService 객체의 Timeout속성의 시간을 길게....잡아주면 된다.

 

여기서 클라이언트는 웹서버가 된다.

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/11/01 23:41
<SCRIPT LANGUAGE="JavaScript">
<!--
var str = "ㄱㄴㄷㄹㅁㅂㅅㅇㅈㅊㅋㅌㅍㅎ가힣";
for(i=0; i<str.length;i++)
{
 document.write(str.charAt(i) + " : " +str.charCodeAt(i) + "<BR>");
}
//document.write(String.fromCharCode(44000));
//-->
</SCRIPT>
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/09/27 20:33

<%


functionRDate(years, months, weeks, weekdays)
   finddate = years & "-" & months
  
  ifmonths="12"then
      nextmonth = "01"
  else
      nextmonth = months + 1
  endif
   prevlastday =DateAdd("d", -1, years & "-" & nextmonth & "-1")'구하려는 달의 마지막날짜
   lastday =DatePart("ww",DateAdd("d", -1, years & "-" & months & "-1"))'전달의 마지막날짜가 몇째주인가
  ifmonths = "1"Thenlastday = "1"
   returnDate = ""
  fori = 1toDay(prevlastday)

  'DatePart로 주를 구하면 1년 단위이므로 아래와 같은 계산식으로 구함
     ifCStr((DatePart("ww",finddate & "-" & i) + 1 - lastday)) = weeksThen

        ifweekdays =CStr(DatePart("w", finddate & "-" & i))Then
            returnDate = returnDate & finddate & "-" & i
           exit for
         end if

      end if
   next
   RDate = returnDate
end function
response.write RDate("2006", "9", "3", "7")' 2006년 9월의 셋째주 토요일은??
%>

 

 

<%
functionRe_Date(dates, s_date, e_date)
   s =int(s_date)'구하려는 시작일 1-일, 2-월, 3-화, 4-수, 5-목, 6-금, 7-토
   e =int(e_date)'구하려는 끝일 1-일, 2-월, 3-화, 4-수, 5-목, 6-금, 7-토
   w =DatePart("w",dates)
   dates =CDate(dates)
         re_s =DateAdd("d", dates , s - w)
         re_e =DateAdd("d", dates , e - w)
   Re_Date = "시작일 : " & re_S & "<br>끝일 : " & re_e

end function

Response.WriteRe_Date("2005-06-02",1,7)'2005-06-02가 포함된 주의 시작일과 끝일은??
%>

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/02/01 22:07

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

사실 제가 제일 싫어하는 것 중 하나가 UI와 관련된 삽질이고,그 중에서도 HTML과 Script로 하는 것입니다.그래도 어찌하다 보면 피할 수 없는 경우가 있는데이번 경우 역시 마찬가지 경우인 것 같습니다.

 

삽질을 하게 만든 녀석이 뭐냐하면...

Absolute Positioning을 한 DIV 레이어가 말썽을 부린다는 것입니다.

바로 아래와 같이 말이죠...

사용자 삽입 이미지

DIV 레이어의 경우, Z-Index를 높게 설정한 상태입니다. 그럼에도 불구하고 <SELECT> 태그를 통한 DropDownList가 DIV 레이어의 상위에 나와 버리는 현상입니다.

 

이 문제가 생기는 원인이 뭘까요?

쉽게 말하자면, IE의 삽질(?)인데.. 다음 문서를 읽어보심이 빠를 것입니다.

 

INFO: How the Z-index Attribute Works for HTML Elements

http://support.microsoft.com/kb/177378/

 

유감스럽게도 번역된게 없습니다. 영어가 껄끄러우신 분들을 위해 대략 요점만 말하자면..

웹 페이지의 요소들은 크게 Windowed와 Windowless라는 두 가지 카테고리로 나누어지는데..

일반적인 DHTML 요소들은 전부 Windowless지만, 유일하게 SELECT만 Windowed입니다.

그리고 문서 내에 찾아보면 다음과 같은 문구가 나옵니다.

 

You can rearrange the z-indexing of the elements on each plane,but the windowed plane always draws on the top of the windowless plane.

 

결국 Z-Index 가지고 아무리 삽질을 해도 windowless는 windowed 위에 나올 수 없다는거죠? 그렇기 때문에 windowless인 DIV 위에 windowed인 SELECT가 나오는 것입니다.

Windowed에 ActiveX 같은게 있는 것은 이해가 가지만, 대체 왜 SELECT가 여기에 포함되어 있는지는 저한테 따져봤자 모릅니다. By Design이랍니다. -_-;;

 

MS는 이 문제를 해결하기 위해 IE 5.5부터 IFRAME을 통해 엄청난 꽁수(?)를 발라 놓았습니다.

쉽게 정리해보자면.. IFRAME의 경우, windowed와 windowless 양쪽 모두의 z-index를 따른다는 것입니다.

 

하여간 이리하여.. 우리가 선택할 수 있는 방안은 크게 3가지가 있는데..

첫째, Scriptlet 등을 사용해서 DIV 내용을 windowed element 내에 집어넣는 방법이 있고..

둘째, 스크립트를 통해 SELECT 태그를 숨기는 방법이 있습니다.

셋째, IFRAME을 통한 꽁수를 사용하는 방법도 있으며..

 

우선 첫번째와 두번째 방법은 다음 URL에서 참조했습니다.

http://www.faqts.com/knowledge_base/view.phtml/aid/15145/fid/53

 

첫번째 방법은..

<object type="text/x-scriptlet" data="your_page.html"
style="position:absolute;z-index:2"></object>

이런 식으로 처리하는 것이고..

 

두번째 방법은..

function hideElms(elmTag) {
 for (i=0; i<document.all.tags(elmTag).length; i++){
  obj = document.all.tags(elmTag)[i];
  if (!obj || !obj.offsetParent) continue;
  obj.style.visibility = "hidden";
 }
}

 

function showDiv(obj) {
 hideElms('SELECT');
 obj.style.visibility = "visible";
}

 

개인적으로 그나마 깔끔하게 떨어지는 건 세번째 같은데..

다음 URL에서 내용을 참고했습니다.

http://www.wwwcoder.com/main/parentid/36/site/2245/68/default.aspx

 

이 방법은 간단히 설명하자면..

SELECT Dropdown 위를 IFRAME으로 덮고.. DIV를 그 IFRAME 위에 올려두는 것입니다.

이 때 Z-Index는 SELECT < IFRAME < DIV 순이 되어야겠죠?

 

<div id="divPanel" style="left: 20px; position: absolute; top: 20px;z-index:2; background-color:blue;width:200px;height:100px;" >...</DIV>
<iframe id="HelpShim"  scrolling="no" frameborder="0" style="left: 20px; position: absolute; top: 20px;z-index:1; width:200px;height:100px;"></iframe>

 

이렇게 했을 때 결과는 다음과 같습니다.

잘 된 것처럼 보이죠?


사용자 삽입 이미지

그런데 이 방법은 한가지 문제가 있는게.. 이 상태에서도 DropDown이 클릭이 가능하며.. Tab을 통해 Focus를 받을 수도 있다는 것입니다. DropDown이 펼쳐지면 다시 아래와 같은 문제가 발생합니다. -_-;


사용자 삽입 이미지

그래서 DIV가 올라올 때는 Dropdown의 disabled를 true로 지정해서 사용불가능하게 만드는 것이 좀 더 바람직할 듯 합니다.


사용자 삽입 이미지

IE 7.0쯤 되면.. 이게 개선되어서 나올려나.. 쩝.. -.-

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/01/10 21:54

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

예전 Voice of .NETXPERT 2003 행사 때, 저희 회사의 김유철 책임이 발표했던 내용인 '아무도 가르쳐 주지 않는 .NET 애플리케이션 개발 Tips 18가지'를 정리해서 올립니다.

 

세번째로 ADO.NET 관련 팁 2가지입니다.

 

Tip 6. Strict Typed Parameter 사용하기

데이터액세스 작업을 수행하다보면 Parameterized Query나 SP를 사용하는 경우, SqlParameter와 같은 Parameter Class를 사용하여 매개변수를 전송해야 하는 경우가 많습니다.

SqlParameter를 만드는 방법에는 여러가지가 있지만, 일반적으로 다음 생성자를 사용하는 경우가 많습니다.

 

SqlParameter(string parameterName, object value);

 

매개변수명/값 쌍으로만 전달하면 되므로, 다음과 같이 작성하기만 하면 되어서 전반적으로 매우 편리하기 때문입니다.

 

SqlParameter param = new SqlParameter("@ProductID", "50");  // Case1

SqlParameter param = new SqlParameter("@ProductID", 50);    // Case2

 

둘 중 어느 것을 사용하더라도 상관은 없습니다. 그런데, 이 두개만 하더라도 실제 SQL 프로파일러로 찍어보면 결과가 서로 다른 것을 알 수 있습니다.

 

exec...@ProductID',N'@ProductIDnvarchar(4000)', @ProductID = N'50'  // Case1

exec...@ProdcutID',N'@ProductIDint', @ProductID = 50                         // Case2

 

이러한 결과가 나타나는 이유는 ADO.NET이 매개변수의 값으로부터 매개변수의 Type을 추론해내기 때문입니다. 명시적으로 지정을 하든, 지정을 하지 않든 Type은 어느 경우나 반드시 필요합니다. 위의 예에서는 Case2가 좀 낫긴 하지만, 만약 ProductID가 int가 아닌 다른 숫자형이었다면?

 

결론적으로 가장 바람직한 것은 매개변수의 Type을 정확하게 지정해주는 것이 좋다는 것입니다. 그러므로 매개변수명/값 쌍 형태보다는 다음과 같이 매개변수명/Type 쌍으로 생성한 후, 값을 따로 지정해주는 것이 보다 바람직합니다. Type 외에도 Size, Precision 등이 있는 경우, 이를 지정해주면 더욱 더 좋습니다.

 

SqlParameter param = new SqlParameter("@ProductID", SqlDbType.Int);

param.Value = 50;

 

프로파일링을 해보면 알 수 있지만 보다 많은 사항을 명시적으로 지정해줄 수록 서버 측 리소스를 절감해서 쿼리 속도 및 성능이 개선되는 것을 알 수 있습니다. 정리하자면 개발자의 편의성과 성능은 반비례한다는 것이 되겠죠. ^^

 

Tip 7. ADO Recordset으로부터 DataSet 만들기

기존 시스템이 ASP로 되어 있었고, ADO Recordset을 반환하는 비즈니스 로직 컴포넌트를 호출해서 데이터를 가져오는 3-Tier 구조로 되어 있었다고 가정합시다.

그러던 어느날 프리젠테이션 부분을 ASP.NET으로 교체한다고 회사에서 결정을 내렸습니다. 윗 사람은 이미 비즈니스 로직은 다 작성되어 있어서 프리젠테이션 부분만 작성하면 되니깐 금방 하겠다고 하면서 프로젝트 일정을 말도 안되게 짧게 잡아 놓았습니다. 안된다고 말을 할려니, 이전에 3-Tier 구조의 장점을 역설했던 일이 거짓말이 되어버리게 생겼습니다. 그렇다고 기존 Recordset을 그대로 사용하려니 ASP.NET에서의 데이터바인딩과 같은 장점을 전혀 사용할 수가 없습니다. 어쩔수 없이 밤을 새서라도 기존 비즈니스 로직 컴포넌트를 .NET으로 재작성하려고 생각을 했는데, 엎칱데 덮친 격으로 기존 컴포넌트에 해당하는 소스가 현재 나한테 없습니다. 이러한 경우, 도대체 어떻게 해야 할까요?

이러한 경우, 기존의 Legacy 로직을 재사용하는 것으로 방향을 잡는 것이 바람직합니다. 처음부터 재작성을 하기에는 시간과 비용이 모자라기 때문입니다.

 

이때 유용한 것이 바로 OleDbDataAdapter의 Fill 메서드입니다. 다른 DataAdapter들과는 다르게, OleDbDataAdapter의 Fill 메서드에는 다음과 같은 오버로딩이 존재합니다.

 

public int Fill(DataSet dataSet, object ADODBRecordSet, string srcTable);

 

이 메서드는 ADODBRecordSet의 내용을 DataSet 내에 srcTable이라는 이름의 DataTable로 채워 넣는 역할을 수행합니다. 이렇게 하여 RecordSet의 내용을 DataSet으로 옮길 수 있게 됩니다.

이렇게 할 때 장점은 다음과 같습니다.

첫째, 기존 Legacy 로직을 수정/변경 없이 그대로 재사용이 가능합니다.

둘째, 기존 Recordset이 Connection 기반이더라도 이를 통해 Disconnected 모델로 전환이 가능합니다.

셋째, 기존 Recordset의 커서 타입에 관계없이 자유롭게 Disconnected 모델에서 사용이 가능합니다.

넷째, 기존 Legacy 로직을 XML 웹 서비스나 .NET 리모팅으로 쉽게 재사용할 수 있게 만들 수 있습니다.

 

단, 이렇게 할 경우, 재사용을 통해 시간과 비용을 절감할 수는 있겠지만, 성능적인 측면에서는 오히려 저하될 수도 있다는 것에 주의해야 합니다.

 

다음 번에는 ASP.NET 관련 팁일듯 합니다. ^^

크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/01/10 21:54

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

예전 Voice of .NETXPERT 2003 행사 때, 저희 회사의 김유철 책임이 발표했던 내용인 '아무도 가르쳐 주지 않는 .NET 애플리케이션 개발 Tips 18가지'를 정리해서 올립니다.

 

두번째로 .NET Framework 관련 팁 2가지입니다.

 

Tip 4. StringBuilder의 잘못된 사용

문자열(System.String)의 경우, 소위 말하는 Immutable 패턴을 따르고 있기 때문에 독특한 특성을 가지는데, 간략하게 설명하면 다음과 같습니다. 우선 다음 코드를 봅시다.

 

string s = "Hello";

s = s + ", ";

s = s + "World !";

 

이렇게 했을 때, 실제 메모리 상에서는 다음과 같이 문자열에 해당하는 메모리 공간이 3번 점유됩니다.

 

Memory #0 : [Hello]

Memory #1 : [Hello, ]

Memory #2 : [Hello, World!]

 

즉 동일한 메모리 주소(#0)에 추가되는 것이 아니라, 문자열 연산을 수행한 결과의 문자열이 새로운 메모리 주소에 할당된다는 것입니다.

이에 비해 StringBuilder라는 클래스를 우리가 일반적으로 생각하는 방법처럼 동일 메모리 주소(#0)에 문자열을 추가함으로써 재할당의 오버헤드, 불필요한 메모리 공간의 낭비를 줄입니다. StringBuilder를 사용할 경우, 위 코드는 다음과 같이 됩니다.

 

StringBuilder sb = new StringBuilder();

sb.Append("Hello");

sb.Append(", ");

sb.Append("World!");

 

이 때문에 상당수의 .NET 프로그래밍 팁에서는 문자열 연산을 여러번 수행하는 경우, StringBuilder를 사용하면 성능이 좋아진다고 설명해놓은 경우가 많습니다.

문제는 이를 맹신하고 남용하는 사람들이 많다는 것입니다. 실제로 다른 .NET 팁을 보고 나서 무조건 StringBuilder를 사용해서 코드를 작성하는 프로그래머를 본 적도 있습니다. 과연 그게 맞을까요? 위에서 본 두 가지 경우와 아래의 경우 중 성능이 가장 좋은 것은 어느 것일까요?

 

string s = "Hello" + ", " + "World!";

 

가장 바람직한 것은 바로 위, 즉 맨 마지막의 경우입니다. 바로 위처럼 작성한 경우, C# 컴파일러는 MSIL을 생성할 때 위 코드를 다음과 같이 최적화합니다.

 

string s = "Hello, World!";

 

그러므로 문자열 상수 연산이나 보통 5개 이하의 문자열 연산에는 StringBuilder를 사용하지 말고 + 연산자를 사용하는 것이 바람직합니다. StringBuilder를 써야 할 경우는 다수의 문자열 연산을 수행하거나, 반복문(for, while 루프 등) 내에서 문자열 연산을 수행할 경우입니다.

성능 뿐만 아니라 코드 가독성 측면에서도 + 연산을 사용하는 것이 StringBuilder.Append()를 사용하는 것보다 훨씬 나으므로, 코드 생성기나 HTML 렌더링과 같은 특수한 작업을 수행하지 않는 일반적인 경우라면 + 연산을 사용하는 것을 권장하고 싶습니다.

 

Tip 5. 콘솔 애플리케이션 출력 캡쳐

요즘은 대부분 웹이나 윈도우 애플리케이션으로 작성하긴 하지만, 간혹 가다 콘솔(커맨드라인) 애플리케이션을 작성해야 할 경우도 있습니다. 이럴 경우, 콘솔 애플리케이션의 출력 내용을 캡쳐하는 방법은 없을까요?

System.Diagnostics.ProcessStartInfo 클래스를 사용하면 이를 간단하게 수행할 수 있습니다. 다음 코드를 보죠.

Process cmd = new Process();
ProcessStartInfo procInfo = new procInfo();
procInfo.RedirectStandardOutput = true;  // 표준 출력을 Redirect
procInfo.UseShellExecute = false;             // 표준 입/출력 Redirect 시에는 false로 설정
procInfo.CreateNoWindow = true;            // 윈도우를 생성하지 않음
cmd.StartInfo = procInfo;
cmd.Start();
cmd.StandardOutput.Read();                    // StreamReader를 통해 출력을 얻음
 
다음 번엔 ADO.NET 관련 팁을 올리도록 하겠습니다.
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari
2006/01/10 21:54

Written by 안재우(Jaewoo Ahn), 닷넷엑스퍼트(.netXpert)

 

예전 Voice of .NETXPERT 2003 행사 때, 저희 회사의 김유철 책임이 발표했던 내용인 '아무도 가르쳐 주지 않는 .NET 애플리케이션 개발 Tips 18가지'를 정리해서 올립니다.

 

먼저 첫번째로 Visual Studio .NET 관련 팁으로 시작합니다.

 

Tip 1. 참조 추가 대화상자에 나의 어셈블리나 컴포넌트를 보이게 할 수 있는 방법은?

 

다음과 같이 나타나게 하는 것을 의미합니다.

사용자 삽입 이미지

 

사실 처음에는 GAC(Global Assembly Cache)에 올라가면 나오지 않을까 생각했었는데, 막상 그렇지 않다는 것을 알게 되었습니다.

어쨌든 참조 대화상자에 표시하는 방법은 크게 2가지 방법이 있습니다.

 

첫번째 방법은 폴더를 이용하는 방법으로서, 다음 폴더에 위치하면 됩니다.

C:\Program Files\Microsoft Visual Studio .NET\Common7\IDE\PublicAssemblies

 

두번째 방법은 레지스트리를 이용하는 방법으로서,HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\VisualStudio\7.0\AssemblyFoldersPublicAssemblies하위키를 이용하면 됩니다.

 

Tip 2. 디버깅 빌드 속도 개선?

기본적으로 VS.NET은 빌드 수행 시 솔루션 내의 모든 프로젝트에 대해 빌드를 수행합니다. 그런데, 프로젝트의 갯수가 많아지다보면 디버깅을 위해 빌드를 수행하는데 걸리는 시간이 점점 많이 걸리게 됩니다.

이를 개선하기 위해서는 다음과 같이 옵션을 지정하여, 빌드 속도를 개선할 수 있습니다.

사용자 삽입 이미지
 

Tip 3. 인텔리센스 동적 도움말

내가 직접 만든 컴포넌트에 다음과 같이 인텔리센스 도움말이 나타나게 하려면?

사용자 삽입 이미지

 

일단 기본적으로 다음과 같은 XML 주석을 달면 된다는 것은 대부분 알고 있을 것입니다.

사용자 삽입 이미지

 

그런데 이 컴포넌트를 담고 있는 프로젝트와 이 컴포넌트를 사용하는 프로젝트가 동일 솔루션 내에 있는 경우에는 자동적으로 인텔리센스 도움말이 표시되지만, 문제는 이 컴포넌트의 DLL만 배포해서, DLL 참조를 수행할 경우입니다.

이러한 경우, 다음과 같이 프로젝트 속성에서 구성속성/빌드/XML 문서 파일에서 XML 파일의 이름을 지정해서 빌드를 수행할 때 XML 파일을 생성하게 합니다.

사용자 삽입 이미지

이제 DLL과 XML을 같이 배포하고, 이 DLL을 다른 프로젝트에서 참조하면 자동적으로 해당 XML 파일이 로드되어 인텔리센스 도움말을 지원하게 됩니다.

사용자 삽입 이미지

 

나머지 팁은 나중에 이어서 올리도록 하겠습니다.

 
크리에이티브 커먼즈 라이선스
Creative Commons License
Posted by mari