Team Foundation Server2006. 9. 26. 22:58
 

현재 참여중인 프로젝트에서는 소스 제어 툴로 Team Foundation ServerSource Control사용하고 있다. 하지만, 아직 Beta 상태인 제품이라 부족한 면이 많은싶다. (아니면 원래 스펙에 빠져있는 건지도? -_-;;)


암튼, 문제가 되었던 것은..


개발자 A(편의상..)개인적인 사정으로 프로젝트에서 나가게 되었다. 그런데.. 그만 편집하고 있던 파일을.. 체크인 하지 않고 체크아웃을 버린 채로..나간 것이다.


이럴경우, Visual SourceSafe 이라면 간단하다. Admin Tool접속해서, 강제로 체크인해버리면 끝이니까.


그런데, TFS에는 별도의 Source Control대한 Admin Tool 은 없는 것이다.... -_-;;;


하지만, 방법이 없는 것은 아니다. TF.exe 명령어 Command사용해서 이런 일들을 수가 있다.


TF UNDO filespec /WORKSPACE:workspace;checkout_user

TF LOCK filespec /LOCK:NONE /WORKSPACE:workspace;lock_user


방법을 사용해서 개발자 A체크아웃을 해서 잠궈버린 파일을 다시 돌려 놓을 수가 있다. 위의 두 가지 구문은 사실은 좀 다르지만, 실제 효과는 같다고 보면 된다.


아래는 샘플.. (위의 구문과는 좀 다르지만 /Server 스위치를 사용해서 반드시 TFS서버를 지정하도록 한다.)

TF UNDO $/Project/SomeFile /WORKSPACE:WorkspaceOfA;UserA /Server:TFSServerName

Posted by kkongchi
asp.net2006. 9. 18. 22:38

ASP.NET 2.0에는 Master Page라는것이 새로 생겼다.  마스터 페이지의 개념을 MSDN에 나온 그대로 옮기면 다음과 같다.

"ASP.NET 마스터 페이지를 사용하면 응용 프로그램의 페이지에 대해 일관된 레이아웃을 만들 수 있습니다. 단일 마스터 페이지는 응용 프로그램의 모든 페이지 또는 페이지 그룹에 대해 원하는 모양과 느낌 및 표준 동작을 정의합니다. 그런 다음 표시할 콘텐츠가 포함된 개별 콘텐츠 페이지를 만들 수 있습니다. 사용자가 요청한 콘텐츠 페이지는 마스터 페이지와 병합되어 마스터 페이지의 레이아웃과 콘텐츠 페이지의 콘텐츠가 조합된 결과가 만들어집니다."

그런데, Master Page - Content Page가구성이되면, 마치 ASCX처럼 내부로 중첩된 컨트롤들의 Client ID가 아주복잡해지는 것을 소스보기에서 볼 수가있다. 이렇게..

<input name="ctl00$ContentPlaceHolder1$TextBox1" type="text" id="ctl00_ContentPlaceHolder1_TextBox1" />


그래서, 자바스크립트를 사용해서 제어하고자 할 때 반드시 서버사이드에서 그 컨트롤의 ClientID를 구해서 해야한다.다음은 Master Page에서 자바스크립트로 Content Page의 컨트롤을 제어하는 샘플이다.

마스터 페이지에는 버튼 컨트롤과 텍스트 박스 컨트롤을 하나씩 올려 두었다.

ASPX 소스는 아래처럼 된다.

<%@ Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
  <title>제목 없음</title>
</head>
<body> <form id="form1" runat="server">   
       <input id="Button1" type="button" value="button" onclick="return Button1_onclick()" />&nbsp;
       <input id="Hidden1" type="hidden" runat="server" /><br />
       <br />
       <asp:contentplaceholder id="ContentPlaceHolder1" runat="server">
           </asp:contentplaceholder>   
  </form>
</body></html>


컨텐트 페이지에는 텍스트박스 컨트롤을 하나 올렸다.


ASPX 소스는 아래처럼 구성된다.
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true" CodeFile="Default2.aspx.cs" Inherits="Default2" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
  <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
</asp:Content>


목표는 마스터페이지에서 버튼을 눌렀을 때, 컨텐트 페이지의 텍스트 박스에 "aaa"라는 값이 들어가게 하는 것이고, 이를 자바스크립트를 사용해서 수행하는 것이다. 그 코드는 다음과 같다.

protected void Page_Load(object sender, EventArgs e)
{
     //contentPlaceHolder1은 Master페이지에 기본적으로 들어있는 PlaceHolder 컨트롤의 이름이다.
     //이 내부에 각 컨텐트 페이지의 컨트롤들이 들어있다.
     //즉 ContentPlaceHolder1.Controls 를 뒤지면 나온다는 얘기다.
     //그래서 루프를 돌면서 찾도록 한다.
     foreach (Control con in this.ContentPlaceHolder1.Controls)
     {
         //원하는 것을 찾기 위해서는 종류나 ID 같은 것을 알면 된다.
         if (con.GetType().Name == "TextBox" con.ID == "TextBox1")
         {
             //ClientID를 알 수 있다. 히든에다 넣는다.
             this.Hidden1.Value = con.ClientID;
         }
     }
     //자바스크립트를 생성한다.
     //렌더링된 자바 스크립트는 아래와 같은 모양이다.
     //        function Button1_onclick() {
     //        var conID = document.all.item("ctl00_Hidden1").value;
     //        eval("document.all.item('" + conID + "').value = 'aaa'");
     //        }
     //즉, 히든에 넣은 textbox 컨트롤의 ID를 구한 후,
     //eval문을 사용해서 컨트롤에 'aaa'라는 값을 넣는 스크립트를 실행하는 것이다.
     string scriptCode = "function Button1_onclick() {" + System.Environment.NewLine;
     scriptCode += " var conID = document.all.item(\"" + this.Hidden1.ClientID + "\").value;" + System.Environment.NewLine;
     scriptCode += "eval(\"document.all.item('\" + conID + \"').value = 'aaa'\");" + System.Environment.NewLine;
     scriptCode += "}";

     //페이지에 클라이언트 스크립트를 등록한다.
     this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "Click", scriptCode, true);
}


주석에도 설명이 되어 있지만, 포인트는 마스터 페이지에 있는 PlaceHolder 컨트롤 내부에서 그 컨텐트 페이지에 있는 컨트롤을 찾는 것이다. 일단 찾은 후에는 그 ClientID 속성을 구할수 있으므로, 이 샘플보다 복잡한 스크립트도 얼마든지 수행시킬 수가 있다.
Posted by kkongchi
MS office2006. 9. 15. 23:06
별로 바뀐게 없는 것 같은데....







'MS office' 카테고리의 다른 글

[Article]Windows Live Writer  (2) 2006.10.16
[Article]Word 2007 Blog Post 기능  (2) 2006.10.15
[Article]Office 2007 Beta 2  (0) 2006.05.29
Posted by kkongchi
javascript & HTML2006. 9. 9. 23:21

Span 태그와 Div 태그는 실제로 아주 비슷하고 기능상으로 거의 차이가 없다. 하지만 이 두 개의 태그는 사실 매우 다르다. http://webdesign.about.com/od/htmltags/a/aa011000a.htm - 여기에 매우 설명이 잘 되어 있다.

이 문서에 의하면,

The <div> tag defines logical divisions in your Web page. In terms of layout, the <div> tag does only one thing, it determines the alignment of that section of your page.
Div 태그는 웹 페이지에서 논리적인 구획을 정의한다. 레이아웃 적인 측면으로 보면, Div 태그는 한 가지 일만을 하는데, 그것은 바로 페이지의 페이지의 섹션 정렬을 지정하는 것이다.

The <span> tag has very similar properties to the <div> tag, in that it affects the style of the text it encloses. Items in the <span> can be aligned or given specific style attributes.
Span 태그는 div 태그와 매우 비슷한 속성을 가지는데, 그것이 감싸고 있는 텍스트들의 스타일에 영향을 준다. Span 태그 안의 아이템들은 특정한 스타일 속성을 가지게 되거나 정렬될 수 있다.

The primary difference between the <span> and <div> tags is that <span> doesn't do any formatting of it's own. The <div> tag acts as a paragraph break, because it is defining a logical division in the document. The <span> tag simply tells the browser to apply the style and align rules to whatever is within the <span>.
Span 태그와 div 태그의 가장 큰 차이는, span 태그는 자체로는 어떤 기능도 하지 않는다는 것이다. Div 태그는 마치 한 문단처럼 행동하는데, 문서의 논리적인 구획을 정의하기 때문이다. Span 태그는 그 내부의 요소들이 특정한 스타일이나 정렬 규칙을 가진다는 것을 브라우저에게 알려줄 뿐이다.

그래서 (내가 몇 번 겪었던 일이긴 한데) Div 태그를 두 개 연속으로 쓸 경우에는 줄나눔이 발생을 하게 된다.

자, 그래서

<div>div1-text</div><div>div2-text</div>
<br>
<br>
<span>span1-text   </span><span>span2-text</span>

이렇게 작성된 HTML의 경우, 이렇게 보인다.






요즘은 Ajax 때문에...HTML에 관심이 많다...ㅎㅎㅎ

Posted by kkongchi
Tools for Developer2006. 9. 9. 12:18

우리는 Internet Explorer 등의 웹 브라우저를 통해서 인터넷을 보게 된다. 주소 창에 주소를 입력하거나, 즐겨 찾기에서 선택을 하기도 하고, 또는 링크를 누르는 동작을 통해서 웹 페이지들을 탐색한다. 하지만, 그 내부적으로는 HTTP 프로토콜을 통해서 서버에 Request를 보내고 그에 대한 Response를 받는 복잡한 동작이 이루어지게 된다. 그 Request에는 Cookie나 사용자의 입력값 등의 정보 들이 Header에 들어가게 되고, 이런 정보들은 실제 웹 브라우저에서는 보이지 않는다.


웹 애플리케이션을 개발한다면, 이런 정보들이 제대로 들어가고 있는지를 보는 것은 중요하다. 대부분의 웹 애플리케이션에서 서버 사이드에 있는 로직들은 이런 Header정보를 많이 사용해서 처리하게 되는데, 디버깅 환경이 아니라 실제 운영 환경에서 문제가 생겼을 때 브라우저에서는 Header 정보를 볼 수가 없기 때문에 문제를 해결하기가 쉽지가 않다.


Fiddler는 이 HTTP Request/Response 정보를 볼 수 있게 해주는 아주 유용한 툴이다. http://www.fiddlertool.com/fiddler/ 에서 다운로드받을 수 있다. NetMon 등을 통하면 물론 그 컴퓨터의 모든 네트워크 트래픽을 모니터링 할 수가 있지만, 이 Fiddler는 인터넷 프로토콜만을 모니터링해주기 때문에 웹 개발자들에게 아주 유용하다.


Fiddler의 화면이다. 왼쪽에는 History가, 오른쪽에는 각 세션의 자세한 정보가 나타나게 된다.




각 세션의 Request/Response Header 정보를 자세하게 볼 수 있다.




또 하나의 유용한 기능, 웹 페이지의 Response Time 정보를 알 수가 있다.


'Tools for Developer' 카테고리의 다른 글

[Article]IE Developer Toolbar  (2) 2006.09.01
Posted by kkongchi
C# & VB.NET2006. 9. 9. 00:00
 

C# 1.X에서는 파라미터로 넘어온 문자열에 대해서 보통은 아래와 같은 방식으로 체크를 했었다.


if (str != null && str.Length != 0)

{

}


하지만, 이제 C# 2.0에서는 이렇게 길게 코딩할 필요가 없어졌다...!!!


if(!String.IsNullOrEmpty(str)

{

}


이렇게 간단하게 한 번의 메소드 호출로...해결할 있다.


그리고, 차라리 젤 위에 있는 예전 방식으로 하고, 아래 방식은 절대로 쓰지 말 것...

If(str != null && str != "")

{
}

Posted by kkongchi
Tools for Developer2006. 9. 1. 15:46
http://www.microsoft.com/downloads/details.aspx?FamilyID=e59c3964-672d-4511-bb3e-2d5e1db91038&displaylang=en#Overview

다음 주소에 가시면, IE Developer Toolbar라는 것을 다운로드받을 수가 있다. 이 툴바는 웹 애플리케이션 개발자/디자이너에게 아주 유용한 많은 기능을 제공한다.

Developer Toolbar 화면





Show Ruler
이 기능은 마우스로 드래그한 부분만큼의 길이를 측정해주는 기능이다. 웹 페이지를 만들다 보면 사실 넓이나 높이를 지정해줘야 하는 경우가 꽤 있는데, 이럴 때 나는 사실 대부분 첨엔 대충 정해놓고 고치면서 맞추는 방식을 사용했다. 하지만, 지금은 이 기능을 사용해서 꽤 자세하게 맞출 수가 있다.

Ruler를 사용하는 화면




Resize
특정 해상도에 맞춰서 IE 창 크기를 자동으로 조절해준다. 디자이너가 여러 해상도에서 어떻게 화면이 나올지를 보는데 좋을 것 같다.

Images
이걸 선택하면 페이지 상의 이미지의 정보들을 화면에서 볼 수 있다. 파일 사이즈, 경로 등의 정보들을 선택해서 볼 수 있고, 통합 리포트도 볼 수가 있다.


Validate
HTML, CSS 등의 표준에 맞는 지를 검증해주는 기능이다. 클릭하면 http://validator.w3.org 사이트로 링크되면서 페이지에서 표준에 맞지 않는 에러등을 리포트해준다. (Visual Studio 2005 등에도 거의 비슷한 기능이 있다)


Outline
가장 잘 쓰고 있는 기능이다. 대부분의 웹 페이지는 Table 이나 Div 등을 써서 페이지의 레이아웃을 잡게 되는데, 이런 용도로 사용된 태그들은 대부분 border 라인을 보이지 않게 한다. (레이아웃만을 잡는 태그니까, 보이지 않게 하는 것이 디자인 상 좋기 때문에) 이 기능을 쓰면 그 숨겨진 경계선들이 다 보이게 된다. 간혹 웹 페이지를 개발하다가 레이아웃이 깨지는 경우가 있는데, 이런 경우에 경계선이 숨겨져 있으면 참 찾기가 힘들다. 그럴 때 아주 유용하다.

Table의 모든 Cell 태그를 outline한 화면




View
HTML 내부에 있는 Class, ID, Link 등의 정보를 화면에 출력해준다.

Disable
화면에서 Cache, 쿠키, 자바스크립트, CSS를 Disable시켰을 때의 효과를 알고 싶다면, 이 기능을 사용하면 된다.

View DOM
이 기능을 선택하면 DOM Explorer라는 것이 브라우저의 하단에 생긴다. 이 DOM Explorer를 통해서 페이지의 HTML구조를 트리 형태로 탐색해 볼 수가 있다. 트리에서 노드를 선택하면, 그 노드에 대한 정보가 옆쪽에 출력이 되고, 브라우저에서도 해당되는 부분이 깜박이면서 표시가 된다. 이 역시 웹 페이지 개발할 때 아주아주 유용하다. 그리고 HTML의 구조를 파악하는데 도움이 되기 때문에, 디자이너가 준 HTML을 개발자가 이해할 때 매우 도움이 될 것 같다.

DOM Explorer 화면

'Tools for Developer' 카테고리의 다른 글

[Article]Fiddler  (2) 2006.09.09
Posted by kkongchi
Team Foundation Server2006. 8. 31. 11:11

지금 제가 참여하고 있는 프로젝트에서는 Microsoft Team Foundation Server를 사용하고 있다. 그래서 소스 제어도 TFS의 기능을 사용한다. 처음 쓸 때는 그 전에 많이 사용했던 Visual SourceSafe와 큰 차이가 없어 보였는데, 쓰면 쓸수록 이제 좀 차이들이 보이고 있다.


그리고 얼마 전에 아주 큰 차이를 하나 알게 되었다. 그리고 아주 당황...-_-;; 이 차이 때문에, 소스 제어를 사용하는 습관을 일부 바꿔야 하기 때문이다..


내용은 다음과 같다. 기존 VSS에서는 소스를 편집하기 위해서는 Check-out이란 것을 해야 한다. Check-out은 그 소스를 내가 편집하고 있다라고 마킹을 하면서, 다른 개발자들이 사용하지 못하게 Lock을 거는 것을 말한다. 이 점은 TFS도 다르지 않지만, 그 후에 결정적인 차이가 있다. VSS에서는 Check-out을 하게 되면, VSS 서버에 있는 최신 버전을 자동적으로 로컬로 다운로드 받게 된다. 당연히 다른 개발자가 뭔가 추가를 했거나 수정을 했을 수도 있기 때문에, VSS 서버에 있는 버전을 받아야 최신 상태의 소스를 가지고 편집을 할 수가 있다. 그런데, TFS의 소스 제어에서는 Check-out을 할 때에 서버 버전을 받지 않는다. 기존에 로컬 PC에 있던 버전이 그대로 있을 뿐이다.. 즉, 최근에 최신 버전을 받은 시점으로부터 Check-out을 하기 전 사이에 다른 개발자가 그 소스를 수정했다면, 그 수정 사항이 반영되지 않은 소스를 그대로 가지고 있게 된다는 것.


사실 혼자서 작성하고 수정하는 소스라면 전혀 상관은 없다. 혼자서만 작업하기 때문에, 굳이 서버에서 최신 버전을 받지 않아도 된다. 하지만, 두 사람 이상이 같이 작업하는 소스라면, 좀 불편한 상황이 발생한다. Check-out을 하기 전에 항상 최신 버전을 받아야만, 다른 사람이 작업한 부분을 로컬로 받을 수가 있는 거다. 그래서, VSS를 사용할 때와 달리 항상 Check-out과 Get Latest Version을 같이 해 주어야 하는 수고..가 발생을 한다. VSS 때의 습관(Check-out만 하는)을 가지고 작업하다 보면, 큰 문제가 발생할 수도 있다..(개발자들끼리 사이가 나빠지게 될 수도...-_-;;;)


이 사항은 TFS 소스 제어의 Bug가 아니라, By-Design이다. 하지만, 공식 문서에는 이 내용에 대해서 상세한 언급은 없다. MSDN의 블로그에 좀 자세한 이유를 분석한 기사가 있는데 참고할만한 내용이다. (http://blogs.msdn.com/buckh/archive/2005/08/20/454140.aspx) 이 글의 개요는 "TFS의 소스 제어에서는 각 개발자가 가지고 있는 로컬 복사본을 어떤 특정 시점의 Snapshot이라고 생각하고 있다. 그렇기 때문에 이 Snapshot의 통일성을 유지하기 위해서 이런 형태로 동작하게 만들었다" 라는 것이다. 음.. 뭐 일리가 있긴 하지만, 아무래도 여러 사람이 작업하는 경우에는 불편하지 않나 생각이 든다. 물론 거의 대부분 하나의 소스 파일은 한 명의 개발자가 작업하긴 하겠지만, 반드시 그 개발자만이 작업한다고는 볼 수가 없다. 잘 모르는 부분에 대해서 도움을 받는다던 지, 추가할 기능이 생겼다던지 등의 경우가 얼마든지 생길 수가 있다. 그럴 경우에는 연관된 개발자들이 꽤 불편하지 않을까 하는 생각이 든다.

Posted by kkongchi
.NET General2006. 7. 25. 23:40

FxCop은 MS에서 만든 코드 분석 툴이다. 닷넷 코드를 분석해서 표준적인 규칙에 맞는지, 성능에 문제가 없는지 등을 검사해주는 도구로, 많은 프로젝트에서 코드 리뷰를 위한 툴로 많이 사용되고 있다.


이번 Visual Studio Team System에서는, 이 FxCop이 아예 Visual Studio 내부에 내장되어서, 아주 간단하게 코드 분석을 해볼 수 있게 되었다. 솔루션 탐색기에서 프로젝트를 오른쪽 클릭해서 나오는 컨텍스트 메뉴에서 "코드 분석 실행"이라는 것을 클릭하면 바로 FxCop을 이용한 코드 리뷰를 실행하고 그 결과를 얻을 수 있다.


솔루션 탐색기에서 코드 리뷰 실행




코드 리뷰 결과 화면




이 코드 분석 툴에는 200개 정도의 기본 규칙들이 있다. 디자인, 명명, 보안, 사용, 상호 운용성, 성능, 안정성, 유지 관리, 이동성, 이식성, 전역화 등으로 분류된 이런 규칙들은 MS에서 제시하는 닷넷의 매우 표준적인 규칙에 의거해서 제작되었기 때문에 이 규칙들을 적용해서 코드를 분석해보고 규칙에 따르도록 코드를 고치는 것은 전체적인 코드의 질을 높이고 결과물의 퀄리티와 성능, 유지 관리성 등을 높이는데 매우 도움이 된다.


그런데, 실제 SI 프로젝트에서는 아무래도 Custom Rule이 필요하다. 많은 사람들이 참여하는 프로젝트에서 이런 자동화된 툴을 사용해서 개발 표준 준수여부를 분석하는 것은 시간과 리소스의 절약을 가져오기 때문에, 그 프로젝트에만 있는 규칙에 대한 준수 여부를 체크할 수 있는 규칙을 만들어서 사용한다면 아주 유용하다.


그리고, 이 FxCop은 Custom Rule을 작성할 수 있는 구조를 지원한다. FxCop의 규칙은 닷넷 어셈블리(DLL) 형태로 만들어져 있는데, 이 DLL을 만들 수 있도록 FxCopSdk.dll, Microsoft.Cci.dll 등의 참조할 수 있는 어셈블리를 제공하고 있다. 이 FxCop은 코드를 분석하는데 reflection을 쓰지 않고 introspection이라는 것을 사용한다. 이 introspection은 reflection과 같이 MSIL 코드를 분석해서 어셈블리(내부의 클래스 등의 모든 정보 또한)의 정보를 추출하는데, reflection보다 더 빠르다.


Custom Rule을 만드는 절차는 다음과 같다.


1. Visual Studio 2005에서 클래스 라이브러리 프로젝트를 만든다.


2. FxCopSdk.dll 과 Microsoft.Cci.dll을 참조해야 한다. 이 DLL들은 비주얼 스튜디오가 설치된 프로젝트 아래에 \Team Tools\Static Analysis Tools\FxCop 폴더에 있다.


3. 먼저 BaseRule 클래스를 만들어야 한다. 이 Base 클래스는 현재 만드는 프로젝트 내부의 모든 Rule 클래스들이 상속하게 될 클래스로, 리소스 XML파일을 로딩하는 역할을 한다. 이 Base 클래스는 Microsoft.FxCop.Sdk.Introspection.BaseIntrospectionRule 클래스를 상속해서 만들어야 하고, 아래의 샘플 코드와 똑같이 만들면 된다. (물론 두번째 파라미터의 XML 리소스 이름, 세번째 파라미터 내부의 클래스 자신의 이름은 바꿔주어야 한다)


using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.FxCop.Sdk.Introspection;
using Microsoft.FxCop.Sdk;
using Microsoft.Cci;


namespace FxCopSampleRule
{
// 반드시 BaseIntrospectionRule 클래스를 상속해야 한다.
public abstract class BaseFxCopSampleRule : Microsoft.FxCop.Sdk.Introspection.BaseIntrospectionRule
{
protected BaseFxCopSampleRule(string ruleIdentifier)
  : base(ruleIdentifier, "FxCopSampleRule.FxCopSampleRule", typeof(BaseFxCopSampleRule).Assembly)
{
}
}
}


4. 리소스 XML 파일을 만든다. 이 리소스 파일에는 이 어셈블리의 규칙 클래스들이 사용하게 될 메시지(규칙을 어긴 문제에 대한 이름, 설명, 해결책 등)들이 들어가게 된다. 만들 때는 리소스 파일이 아니라 XML 파일로 만들어야 하며, 중요한 것은 이 XML 파일의 속성에서 반드시 빌드 작업을 "포함 리소스"로 해야 한다는 것.




<Rules FriendlyName="AARule">
<Rule TypeName="ShouldHaveAANameSpace" Category="AA.Naming" CheckId="AA0001">
<Name>Should Have AA NameSpace</Name>
<Description>Should Have SK NameSpace</Description>
<Url></Url>
<Resolution Name="Namespace">네임스페이스는 반드시 AA.BB로 시작해야 합니다. {0} 네임스페이스를 고치세요</Resolution>
<Email>kkongchi@interdev.co.kr</Email>
<MessageLevel Certainty="95">Error</MessageLevel>
<FixCategories>Breaking</FixCategories>
<Owner>kkongchi</Owner>
<GroupOwner>AA</GroupOwner>
<DevOwner>kkongchi</DevOwner>
</Rule>
</Rules>


5. 이제 규칙을 만들 차례이다. 규칙은 하나의 클래스로 만드는데, 3번에서 만든 BaseRule 클래스를 상속해서 만든다. 이름은 규칙을 잘 나타내도록 만드시기 바란다. 생성자에서 Base 생성자를 상속할 때에 현재 만드는 규칙이 사용할 메시지의 RuleName을 파라미터로 넣어서 그 메시지를 로드할 수 있도록 해야 한다.


6. 그리고 그 규칙 클래스에서는 Check 메소드를 오버라이드해서 체크할 규칙을 구현하면 된다. Check 메서드에는 많은 오버로드된 버전이 있기 때문에 만들려고 하는 규칙에 맞는 것을 선택해야 한다. 아래의 샘플은 어셈블리의 네임스페이스를 체크하는 것이기 때문에 Module이 파라미터인 것을 선택했다. 체크해야 할 규칙에 어긋나는 케이스가 발생했을 때, Problems 프로퍼티에 새로운 Problem 객체를 Add시키면 된다. 그리고 그 Problem 객체에는 XML에서 로드하는 Resolution 객체가 필요하다. (코드를 보면 알겠지만, {0} 등의 형태로 메시지 내부의 문자열에 현재 검사한 모듈의 이름 등을 넣을 수가 있도록 되어 있다.


using System;
using System.Collections.Generic;
using System.Text;

using Microsoft.FxCop.Sdk.Introspection;
using Microsoft.FxCop.Sdk;
using Microsoft.Cci;

namespace FxCopSampleRule
{
// 먼저 만든 Base 클래스를 상속한다.
public class ShouldHaveAANameSpace : BaseFxCopSampleRule
{
//리소스 XML파일에 있는 규칙들 중에서 ShouldHaveAANameSpace (이름)이 반드시 있어야 한다.
public ShouldHaveAANameSpace() : base("ShouldHaveAANameSpace")
{
}

/// <summary>
/// 네임스페이스가 AA.BB로 시작하는지를 체크하는 규칙이다.
/// </summary>
/// <param name="module"></param>
/// <returns></returns>
public override ProblemCollection Check(Module module)
{
for (int i = 0; i < module.GetNamespaceList().Length; i++)
{
  if (!module.GetNamespaceList()[i].FullName.StartsWith("AA.BB"))
  {
   //Problem 객체를 만들어서 base.Problems에 더해야 한다.
   //GetResolution 함수의 파라미터는 XML에 정의된 Resolution에서 {0}, {1} 로 표시된 문자열을 채우는 값이다.
   base.Problems.Add(new Problem(GetResolution(new string[1] { module.GetNamespaceList()[i].FullName })));
  }
}

return base.Problems;
}
}
}


7. 코드가 완성되면 컴파일을 하면 된다. 컴파일된 DLL을 비주얼 스튜디오가 설치된 디렉토리 아래의 Team Tools\Static Analysis Tools\FxCop\Rules 폴더에 복사하면, 바로 그 후부터 코드 분석 시에 새로 만든 규칙을 사용할 수가 있다.


Posted by kkongchi
.NET General2006. 7. 22. 02:29

1. SQL Injection 이란?


a. SQL Injection은 SQL 쿼리에 사용되는 사용자의 입력값에 대해서 제대로 유효성 검사를 하지 않았거나 타입 체크를 하지 않아서, 쿼리가 제대로 동작하지 않거나 시스템에 문제를 일으킬 수 있는 다른 코드가 실행될 수 있게 만드는 애플리케이션 상의 보안 취약점이다.



2. SQL Injection의 예


a. 사용자 정보가 DB에 있으며, 로그인 페이지에서 다음과 같은 쿼리를 호출해서 인증을 처리한다고 생각해보자

SELECT * FROM USERS WHERE USERID = '" + UserIDTextBoxValue + "' AND PASSWORD = '" + PasswordTextBoxValue + "'"


b. 여기서 UserIDTextBoxValue에 a' or 1=1 -- 이라는 값을 넣는다면, or 1=1 부분에 의해서 참이 되고, -- 에 의해서 그 다음부터는 주석처리가 되기 때문에 전혀 쿼리에 영향을 주지 않는다. 그러므로, 실제로 실행되는 쿼리는 다음과 같다.

SELECT * FROM USERS WHERE USERID = 'a' or 1=1 -- AND PASSWORD = ''


3. 해결책


a. ADO.NET에서 제공하는 SqlCommand, SqlParameter 객체를 사용하면, 이 SQL Injection 공격으로부터 안전한 코드를 작성할 수 있다. SqlParameter 객체를 통해서 전달된 값은 쿼리 자체에 영향을 끼치지 못하고 문자열로만 취급되기 때문이다. 즉, 위의 쿼리에 Parameter로 a or 1=1 -- 이란 값을 넣어도 'a or 1=1 --" 이라는 문자열과 USERID를 비교하게 되기 때문에 일치하는 값이 없는 것으로 결과가 나오게 될 것이다. 이런 방식을 Parameterized Query라고 한다.

//SqlCommand 객체 생성
System.Data.SqlClient.SqlCommand oCom = new System.Data.SqlClient.SqlCommand();
oCom.CommandText = "SELECT * FROM USERS WHERE USERID = @param1";
oCom.CommandType = CommandType.Text;

//SqlParameter 객체 생성
System.Data.SqlClient.SqlParameter oParam = new System.Data.SqlClient.SqlParameter();
oParam.DbType = DbType.String;
oParam.Value = "value";
oParam.ParameterName = "param1";

//SqlCommand객체에 SqlParameter를 적용한다.
oCom.Parameters.Add(oParam);


b. Stored Procedure를 사용하게 되면 반드시 SqlParameter객체를 사용해야 하기 때문에 Sql Injection으로부터 안전할 수 있다.


c. 하지만 Stored Procedure 내부에서 문자열과 파라미터를 더해서 쿼리를 구성한다면, SQL Injection에 취약한 코드가 된다. 그래서, 이런 Dynamic Query로 이루어진 Stored procedure를 사용할 때는, 아주 엄격하게 Validation을 해야 할 것이다.

Posted by kkongchi