ASP.NET AJAX의 세 가지 얼굴 - (3)
출처 : 한빛 네트워크 "ASP.NET AJAX의 세 가지 얼굴 - (3)"
세번째 얼굴: DOM 심화 연구
가끔씩 커스텀 익스텐더 조차 만족스럽지 못할 때가 있는데, 예를 들어 여러분이 (DHTML을 경유하여) 문서 객체 모델(DOM; Document Object Model)에 접근하여 자바스크립트를 이용해서 그것들을 직접 조작하거나 Update Panel을 매개체로 하지 않고 XMLHttp 객체를 직접적으로 이용하여 브라우저의 비동기적인 기능들을 직접 요청하는 등의 작업들이 그러하다. 이것들은 극도로 어렵고, 상당한 노력을 필요로 하며, 순수 AJAX 코드를 작성해야 하며, 다루기도 쉽지 않다.
순수 AJAX 작동 방식을 보여주기 위하여 필자는 여러분이 텍스트 상자에 문자를 입력하면 지금까지 입력했던 문자들로 시작하는 모든 도시명을 보여줄 워드 휠(word-wheel)을 하나 작성해 볼 것이다. 이렇게 하기 위해서는 도시명에 대한 데이터베이스가 필요한데 여기에서는 AdventureWorks 데이터베이스에 들어있는 도시들의 목록을 이용할 것이다.
우선 앞의 예제를 HardCoreAjax라는 이름의 새로운 웹 사이트로 복사한다.
bin 디렉터리의 내용도 함께 복사되도록 한다
HardCoreAjax 웹 사이트를 열고 Default.aspx를 기본 페이지로 지정한다. 여전히 웹 사이트가 제대로 작동하는지 확인해 보기 위하여 실행시켜 본다.
웹 사이트에 UserNameLookup.aspx라는 이름으로 새 페이지를 하나 추가한다. 이 페이지는 Default.aspx에 포함된 자바스크립트가 서버측 코드를 실행시켜주는 수단으로 사용될 것이다. 페이지가 구동될 때 페이지의 Page_Load 메소드가 사용자명을 데이터베이스로부터 읽어 들인 다음 HTML을 구성하여 읽어들인 결과물로부터 선택 목록을 구축할 것이다. 그리고 나서 이 HTML 텍스트 문자열을 요청하는 자바스크립트로 돌려주어 그것들을 기본 페이지에 비동기적으로 삽입할 것이다.
UserNameLookup.aspx가 소스보기에 나타나면 첫째 줄의 Page 지시자를 제외한 나머지 페이지 전체 내용을 삭제한다. 페이지 내용을 하나의 ASP.NET Literal 컨트롤로 치환하여 파일의 전체 내용을 [예제 1]처럼 만든다. 여러분은 일반적으로 문법 오류를 의미하는 Literal 컨트롤의 asp 태그 아래의 빨간색 표시줄을 무시해도 된다.
[예제 1] UserNameLookup.aspx
이 페이지가 어떤 일을 할지 밝혀보자면 이 페이지의 역할은 데이터베이스에서 도시 이름을 찾아서 그것들을 Default.aspx 페이지에 삽입하고자 하는 HTML로 만들어 그것을 Literal 컨트롤에 넣는 것이다. 그런 다음 우리는 그 HTML을 클라이언트측 페이지에 DHTML과 자바스크립트를 이용하여 삽입할 것이다.
도시이름 가져오기
UserNameLookup과 UserNameLookup.aspx.vb의 코드 비하인드(code-behind) 파일을 연다. 아래의 예제 1-2에 나타나 있는 모든 코드를 추가한다. 이 코드에는 클래스 바깥에 두 개의 import 문장을 포함하고 있는데, 그 문장들은 필요한 Data 네임스페이스와 이벤트 핸들러 메소드인 Page_Load, 그리고 헬퍼 메소드인 UserNamesForPartialName 에 접근할 수 있도록 해준다. 이것들 모두 별다른 것 없는 간단한 서버측 ASP.NET 코드이다.
페이지를 불러오면 페이지에 전달된 쿼리 스트링을 살펴보고 데이터베이스로부터 도시 이름을 뽑아내기 위하여 쿼리를 변환할 것이다. 만약 도시 이름을 받아오게 되면 그것들의 역할은 HTML listbox(Select 객체)에 도시 이름들을 보여줄 HTML 문장들을 생성하는 것이다. 첫 번째 라인은 select 객체를 생성한다:
모든 도시들이 처리되면 선택문이 완성된다.
그 다음 전체 문자열은 Literal 컨트롤에 위치하게 되는데, 그 문자열들은 그대로 .aspx 페이지가 된다. 그러므로 이 페이지는 어디든 삽입할 수 있는 listbox HTML과 다를 바가 없으므로 바로 Default 페이지 마크업의 적당한 <div> 안에 DHTML을 이용하여 넣어줄 수 있다.
[예제 2]는 <select> 엘리먼트가 어떻게 만들어지는지를 보여준다.
[예제 2] UserNameLookup.aspx.vb
사용자명은 HumanResources.Employee 테이블의 Login 컬럼에 “adventure-works사용자명”의 형태로 저장된다. 필자는 필드 외부에서 그것을 파싱하지 않고 단순히 Person.Contact 테이블의 LastName 컬럼을 질의하도록 하였다. 그렇지만 쿼리문에서는 리턴되는 컬럼에 대하여 UserName이라는 별칭을 사용하고 있다. 원한다면 여러분이 직접 쿼리를 수정하여 데이터베이스로부터 실제 사용자명을 검색하게 할 수도 있다.
소스 보기에서 Default.aspx를 연다. 여러분은 페이지 상단의 <head> 엘리먼트에 모든 자바스크립트 코드를 추가할 수 있다. 게다가 TextBox의 txtName 라는 속성을 추가하여 keyup 이벤트를 처리할 자바스크립트 함수 중 하나를 가리키도록 할 수도 있다. 마지막으로 여러분은 <div> 엘리먼트를 추가하여 여러분이 UserNameLookup의 코드 비하인드에서 생성했던 HTML을 삽입할 수 있는 자바스크립트 함수를 추가한다.
Default.aspx는 스크립트를 제외한 나머지 부분은 변경된 것이 없으므로 스크립트만 한번 살펴보기로 하자.
첫 번째 메소드인 showHint는 한 개의 문자열을 인자로 받는데 이 문자열은 텍스트 상자의 내용이다. 만약 문자열이 비어 있으면 메소드는 <div>(TextBoxHint라고 이름을 지정했던)을 비운 다음 그것을 리턴한다. innerHTML 속성은 열고 닫는 <div> 태그 사이의 텍스트를 설정한다.
텍스트가 비어있으면 함수는 XMLHttpRequest를 생성하여 비동기 통신을 처리한다.
여기에 나와있는 것들은 다소 단순화시킨 것들이긴 하지만 당분간은 작동할 것이다. 실제로 다운로드 가능한 코드에서 좀 더 우리가 필요로 하는 것들을 보여줄 것이다.
url 변수를 도시를 검색할 aspx 페이지명(UserNameLookup.aspx )으로 설정하고 그 이름에 현재 우리가 쿼리 스트링 객체에 값을 전달할 것임을 의미하는 “?q” 문자를 추가한 다음, 텍스트 상자에서 획득한 값을 추가하였다(말하자면 사용자가 입력한 도시명의 일부).
이제 UserNameLookup.aspx을 열어 비동기적으로 처리가 완료될 때까지 기다릴 준비를 한다. xmlHttp 객체의 onreadystatechange 메소드가 실행될 때(요청한 페이지가 언제 작업을 완료했는지를) 통지받기 위한 콜백 함수가 하나 필요한데, 우리는 그 메소드의 이름을 statechanged로 할당한다:
여기까지 한 다음 페이지를 열고 null을 전달하여 강제로 메소드를 호출하고 대기 상태로 바뀌도록 한다.
onreadystatechange 이벤트가 발생할 때마다 stateChanged 메소드가 호출되어 페이지가 완료되었는지(ready state가 complete이거나 값이 4)와 상태코드가 OK인지를 확인한다. 만약 그렇다면 xmlHttp 객체로부터 responseText를 가져와서 그것을 Div의 innerHTML에 할당함으로써 앞에서 아무것도 가지지 않았던 Div에 listbox를 집어넣게 된다.
여러분은 데이터베이스 연결 문자열을 web.config에 추가하여 UserNameLookup이 데이터베이스에 접속할 수 있도록 해줄 필요가 있다. 다음 코드를web.config의 <system.web> 엘리먼트 바로 앞에 추가한다.
애플리케이션을 실행하고 텍스트 상자에 문자를 입력해 본다. 선택 목록이 텍스트 상자 아래에 나타날 것이며 이전 예제에서처럼 버튼이 사용가능 상태로 바뀌고 버튼의 텍스트가 변경될 것이다. 두 번째 문자를 입력하면 선택 상자의 목록이 줄어들 것이다.

[그림 13] 실행중인 HardCoreAjax (확대하려면 클릭하시오)
다음 단계
우리는 이제 여러분이 마이크로소프트에서 제공한 AJAX와 컨트롤을 이용하여 오랜 시간 동안 지낼 수 있을 것이라 확신하며 Control Toolkit에 포함되어 있는 예제들을 컴파일하고 살펴보기를 강력히 권하고 싶다.
익스텐더에 대해 좀 더 알아보기 위한 가장 확실하고 안전한 방법은 자바스크립트에 관한 좋은 책(David Flanagan이 지은 JavaScript The Definitive Guide 를 추천한다)을 옆에 놓고 우리가 만들어 보았던 예제로부터 시작해서 그것을 다양하게 변형시켜 보는 것이다.
만약 여러분이 DHTML을 파고들려고 결정하고 순수 AJAX 코드를 작성하려고 한다면 특히 AJAX에 관한 자세한 정보들이 업데이트 되어 있는 Danny Goodman이 지은 Dynamic HTML, the Definitive Reference를 강력히 권하고 싶다.
이 기사의 모든 자료들은 곧 출간될 Jesse Liberty와 Dan Hurwitz가 지은 Learning ASP.NET 에 나오는 내용을 새로이 ASP.NET에 입문하는 프로그래머에게 맞게 확장한 것이다. 동일한 내용에 대한 다소 다른 관점을 Jesse Liberty와 Alex Horovitz가 지은 Programming .NET 3에서도 다루고 있다.
이 기사에서 사용된 코드는 Jesse의 웹 사이트인 http://www.gotdotnet3.com/에서 다운로드 할 수 있으며 지원 포럼, 오타, 그리고 다른 흥미있는 것들도 웹 사이트에서 찾아볼 수 있을 것이다.
Jesse Liberty는 Microsoft .NET MVP이며 O'Reilly Media의 베스트 셀러인 Programming ASP.NET, Programming C#, Programming VB2005의 저자이며, 웹과 객체지향 프로그래밍에 관한 다수의 서적의 저자이기도 하다. 그는 그가 contract programming, 닷넷 컨설팅과 현장 교육을 담당하고 있는 Liberty Associates, Inc의 대표이다.
Dan Hurwitz 는 Sterling Solutions, Inc.의 대표이며 2년 가까이 다양한 분야의 클라이언트에 대한 contract programming, 데이터베이스 개발을 담당해오고 있다.
세번째 얼굴: DOM 심화 연구
가끔씩 커스텀 익스텐더 조차 만족스럽지 못할 때가 있는데, 예를 들어 여러분이 (DHTML을 경유하여) 문서 객체 모델(DOM; Document Object Model)에 접근하여 자바스크립트를 이용해서 그것들을 직접 조작하거나 Update Panel을 매개체로 하지 않고 XMLHttp 객체를 직접적으로 이용하여 브라우저의 비동기적인 기능들을 직접 요청하는 등의 작업들이 그러하다. 이것들은 극도로 어렵고, 상당한 노력을 필요로 하며, 순수 AJAX 코드를 작성해야 하며, 다루기도 쉽지 않다.
순수 AJAX 작동 방식을 보여주기 위하여 필자는 여러분이 텍스트 상자에 문자를 입력하면 지금까지 입력했던 문자들로 시작하는 모든 도시명을 보여줄 워드 휠(word-wheel)을 하나 작성해 볼 것이다. 이렇게 하기 위해서는 도시명에 대한 데이터베이스가 필요한데 여기에서는 AdventureWorks 데이터베이스에 들어있는 도시들의 목록을 이용할 것이다.
우선 앞의 예제를 HardCoreAjax라는 이름의 새로운 웹 사이트로 복사한다.
bin 디렉터리의 내용도 함께 복사되도록 한다
HardCoreAjax 웹 사이트를 열고 Default.aspx를 기본 페이지로 지정한다. 여전히 웹 사이트가 제대로 작동하는지 확인해 보기 위하여 실행시켜 본다.
웹 사이트에 UserNameLookup.aspx라는 이름으로 새 페이지를 하나 추가한다. 이 페이지는 Default.aspx에 포함된 자바스크립트가 서버측 코드를 실행시켜주는 수단으로 사용될 것이다. 페이지가 구동될 때 페이지의 Page_Load 메소드가 사용자명을 데이터베이스로부터 읽어 들인 다음 HTML을 구성하여 읽어들인 결과물로부터 선택 목록을 구축할 것이다. 그리고 나서 이 HTML 텍스트 문자열을 요청하는 자바스크립트로 돌려주어 그것들을 기본 페이지에 비동기적으로 삽입할 것이다.
UserNameLookup.aspx가 소스보기에 나타나면 첫째 줄의 Page 지시자를 제외한 나머지 페이지 전체 내용을 삭제한다. 페이지 내용을 하나의 ASP.NET Literal 컨트롤로 치환하여 파일의 전체 내용을 [예제 1]처럼 만든다. 여러분은 일반적으로 문법 오류를 의미하는 Literal 컨트롤의 asp 태그 아래의 빨간색 표시줄을 무시해도 된다.
[예제 1] UserNameLookup.aspx
<%@ Page Language="VB" AutoEventWireup="false" CodeFile="UserNameLookup.aspx.vb"
Inherits="UserNameLookup" %>
<asp:Literal id="UserNames" runat="server" />
이 페이지가 어떤 일을 할지 밝혀보자면 이 페이지의 역할은 데이터베이스에서 도시 이름을 찾아서 그것들을 Default.aspx 페이지에 삽입하고자 하는 HTML로 만들어 그것을 Literal 컨트롤에 넣는 것이다. 그런 다음 우리는 그 HTML을 클라이언트측 페이지에 DHTML과 자바스크립트를 이용하여 삽입할 것이다.
도시이름 가져오기
UserNameLookup과 UserNameLookup.aspx.vb의 코드 비하인드(code-behind) 파일을 연다. 아래의 예제 1-2에 나타나 있는 모든 코드를 추가한다. 이 코드에는 클래스 바깥에 두 개의 import 문장을 포함하고 있는데, 그 문장들은 필요한 Data 네임스페이스와 이벤트 핸들러 메소드인 Page_Load, 그리고 헬퍼 메소드인 UserNamesForPartialName 에 접근할 수 있도록 해준다. 이것들 모두 별다른 것 없는 간단한 서버측 ASP.NET 코드이다.
페이지를 불러오면 페이지에 전달된 쿼리 스트링을 살펴보고 데이터베이스로부터 도시 이름을 뽑아내기 위하여 쿼리를 변환할 것이다. 만약 도시 이름을 받아오게 되면 그것들의 역할은 HTML listbox(Select 객체)에 도시 이름들을 보여줄 HTML 문장들을 생성하는 것이다. 첫 번째 라인은 select 객체를 생성한다:
"<select id='slctName' size=5 onchange=""SelectName();"">"그 다음에는 데이터 테이블의 전체 행을 반복하면서 각각의 도시 이름들에 대하여 option을 생성하고 그것의 값과 텍스트를 도시의 이름으로 설정한다.
For Each row In dt.Rows
returnString = returnString + "<option value='" + _
row("UserName").ToString() + "' >" + _
row("UserName").ToString() + _
"</option>"
Next
모든 도시들이 처리되면 선택문이 완성된다.
returnString = returnString + "</select>"
그 다음 전체 문자열은 Literal 컨트롤에 위치하게 되는데, 그 문자열들은 그대로 .aspx 페이지가 된다. 그러므로 이 페이지는 어디든 삽입할 수 있는 listbox HTML과 다를 바가 없으므로 바로 Default 페이지 마크업의 적당한 <div> 안에 DHTML을 이용하여 넣어줄 수 있다.
[예제 2]는 <select> 엘리먼트가 어떻게 만들어지는지를 보여준다.
[예제 2] UserNameLookup.aspx.vb
Imports System.Data
Imports System.Data.SqlClient
Partial Class UserNameLookup
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load
If (Request.QueryString.Count > 0) Then
Dim queryUserName As String = Request.QueryString.Get(0).ToString()
Dim dt As DataTable = UserNamesForPartialName(queryUserName)
If (dt Is Nothing Or dt.Rows.Count = 0) Then
UserNames.Text = _
"Sorry no user names found with that letter combination."
Else
Dim returnString As String = String.Empty
returnString = returnString + _
"<select id='slctName' size=5 onchange=""SelectName();"">"
Dim row As DataRow
For Each row In dt.Rows
returnString = returnString + "<option value='" + _
row("UserName").ToString() + "' >" + _
row("UserName").ToString() + _
"</option>"
Next
returnString = returnString + "</select>"
UserNames.Text = returnString
End If
Else
UserNames.Text = String.Empty
End If
End Sub
Public Function UserNamesForPartialName(ByVal strPartialName As String) _
As DataTable
Dim connectionString As String = _
ConfigurationManager.AppSettings("AdventureWorks")
Dim connection As SqlConnection = New SqlConnection(connectionString)
Dim queryString As String = _
"select distinct LastName as UserName from Person.Contact where " + _
"LastName like '" + _
strPartialName + "%' order by LastName"
Dim ds As DataSet = New DataSet()
Try
Dim dataAdapter As SqlDataAdapter = _
New SqlDataAdapter(queryString, connection)
dataAdapter.Fill(ds, "Names")
Catch ex As Exception
'' Handle exception
UserNames.Text = ex.Message
Finally
connection.Close()
End Try
Return ds.Tables("Names")
End Function
End Class
사용자명은 HumanResources.Employee 테이블의 Login 컬럼에 “adventure-works사용자명”의 형태로 저장된다. 필자는 필드 외부에서 그것을 파싱하지 않고 단순히 Person.Contact 테이블의 LastName 컬럼을 질의하도록 하였다. 그렇지만 쿼리문에서는 리턴되는 컬럼에 대하여 UserName이라는 별칭을 사용하고 있다. 원한다면 여러분이 직접 쿼리를 수정하여 데이터베이스로부터 실제 사용자명을 검색하게 할 수도 있다.
소스 보기에서 Default.aspx를 연다. 여러분은 페이지 상단의 <head> 엘리먼트에 모든 자바스크립트 코드를 추가할 수 있다. 게다가 TextBox의 txtName 라는 속성을 추가하여 keyup 이벤트를 처리할 자바스크립트 함수 중 하나를 가리키도록 할 수도 있다. 마지막으로 여러분은 <div> 엘리먼트를 추가하여 여러분이 UserNameLookup의 코드 비하인드에서 생성했던 HTML을 삽입할 수 있는 자바스크립트 함수를 추가한다.
Default.aspx는 스크립트를 제외한 나머지 부분은 변경된 것이 없으므로 스크립트만 한번 살펴보기로 하자.
<script language="javascript" type="text/javascript">
var xmlHttp
function showHint(str)
{
if (str.length==0)
{
document.getElementById("TextBoxHint").innerHTML=""
return
}
xmlHttp = new XMLHttpRequest()
var url="UserNameLookup.aspx"
url=url+"?q="+str
xmlHttp.onreadystatechange=stateChanged
xmlHttp.open("GET",url,true)
xmlHttp.send(null)
}
첫 번째 메소드인 showHint는 한 개의 문자열을 인자로 받는데 이 문자열은 텍스트 상자의 내용이다. 만약 문자열이 비어 있으면 메소드는 <div>(TextBoxHint라고 이름을 지정했던)을 비운 다음 그것을 리턴한다. innerHTML 속성은 열고 닫는 <div> 태그 사이의 텍스트를 설정한다.
텍스트가 비어있으면 함수는 XMLHttpRequest를 생성하여 비동기 통신을 처리한다.
여기에 나와있는 것들은 다소 단순화시킨 것들이긴 하지만 당분간은 작동할 것이다. 실제로 다운로드 가능한 코드에서 좀 더 우리가 필요로 하는 것들을 보여줄 것이다.
url 변수를 도시를 검색할 aspx 페이지명(UserNameLookup.aspx )으로 설정하고 그 이름에 현재 우리가 쿼리 스트링 객체에 값을 전달할 것임을 의미하는 “?q” 문자를 추가한 다음, 텍스트 상자에서 획득한 값을 추가하였다(말하자면 사용자가 입력한 도시명의 일부).
var url="UserNameLookup.aspx" url=url+"?q="+str
이제 UserNameLookup.aspx을 열어 비동기적으로 처리가 완료될 때까지 기다릴 준비를 한다. xmlHttp 객체의 onreadystatechange 메소드가 실행될 때(요청한 페이지가 언제 작업을 완료했는지를) 통지받기 위한 콜백 함수가 하나 필요한데, 우리는 그 메소드의 이름을 statechanged로 할당한다:
xmlHttp.onreadystatechange=stateChanged
여기까지 한 다음 페이지를 열고 null을 전달하여 강제로 메소드를 호출하고 대기 상태로 바뀌도록 한다.
onreadystatechange 이벤트가 발생할 때마다 stateChanged 메소드가 호출되어 페이지가 완료되었는지(ready state가 complete이거나 값이 4)와 상태코드가 OK인지를 확인한다. 만약 그렇다면 xmlHttp 객체로부터 responseText를 가져와서 그것을 Div의 innerHTML에 할당함으로써 앞에서 아무것도 가지지 않았던 Div에 listbox를 집어넣게 된다.
function stateChanged()
{
var OK = 200
if (( xmlHttp.readyState == 4 || xmlHttp.readyState == "complete" )
&& xmlHttp.status == OK )
{
document.getElementById("TextBoxHint").innerHTML = xmlHttp.responseText
}
}
여러분은 데이터베이스 연결 문자열을 web.config에 추가하여 UserNameLookup이 데이터베이스에 접속할 수 있도록 해줄 필요가 있다. 다음 코드를web.config의 <system.web> 엘리먼트 바로 앞에 추가한다.
<appSettings>
<add key="AdventureWorks" value="Data Source=ServerName;
Initial Catalog=AdventureWorks;Integrated Security=True;" />
</appSettings>
애플리케이션을 실행하고 텍스트 상자에 문자를 입력해 본다. 선택 목록이 텍스트 상자 아래에 나타날 것이며 이전 예제에서처럼 버튼이 사용가능 상태로 바뀌고 버튼의 텍스트가 변경될 것이다. 두 번째 문자를 입력하면 선택 상자의 목록이 줄어들 것이다.

[그림 13] 실행중인 HardCoreAjax (확대하려면 클릭하시오)
다음 단계
우리는 이제 여러분이 마이크로소프트에서 제공한 AJAX와 컨트롤을 이용하여 오랜 시간 동안 지낼 수 있을 것이라 확신하며 Control Toolkit에 포함되어 있는 예제들을 컴파일하고 살펴보기를 강력히 권하고 싶다.
익스텐더에 대해 좀 더 알아보기 위한 가장 확실하고 안전한 방법은 자바스크립트에 관한 좋은 책(David Flanagan이 지은 JavaScript The Definitive Guide 를 추천한다)을 옆에 놓고 우리가 만들어 보았던 예제로부터 시작해서 그것을 다양하게 변형시켜 보는 것이다.
만약 여러분이 DHTML을 파고들려고 결정하고 순수 AJAX 코드를 작성하려고 한다면 특히 AJAX에 관한 자세한 정보들이 업데이트 되어 있는 Danny Goodman이 지은 Dynamic HTML, the Definitive Reference를 강력히 권하고 싶다.
이 기사의 모든 자료들은 곧 출간될 Jesse Liberty와 Dan Hurwitz가 지은 Learning ASP.NET 에 나오는 내용을 새로이 ASP.NET에 입문하는 프로그래머에게 맞게 확장한 것이다. 동일한 내용에 대한 다소 다른 관점을 Jesse Liberty와 Alex Horovitz가 지은 Programming .NET 3에서도 다루고 있다.
이 기사에서 사용된 코드는 Jesse의 웹 사이트인 http://www.gotdotnet3.com/에서 다운로드 할 수 있으며 지원 포럼, 오타, 그리고 다른 흥미있는 것들도 웹 사이트에서 찾아볼 수 있을 것이다.
Jesse Liberty는 Microsoft .NET MVP이며 O'Reilly Media의 베스트 셀러인 Programming ASP.NET, Programming C#, Programming VB2005의 저자이며, 웹과 객체지향 프로그래밍에 관한 다수의 서적의 저자이기도 하다. 그는 그가 contract programming, 닷넷 컨설팅과 현장 교육을 담당하고 있는 Liberty Associates, Inc의 대표이다.
Dan Hurwitz 는 Sterling Solutions, Inc.의 대표이며 2년 가까이 다양한 분야의 클라이언트에 대한 contract programming, 데이터베이스 개발을 담당해오고 있다.
Twitter
Facebook
RSS
back to top
Recent Comments
패왕넷 - 최근 댓글