( 어제 다 쓰려고 했는데, c2.net 번역 게시물들을 읽다가 시간이 Over되는 바람에 다 적지 못했습니다. )

4. 데이터 접근용 Class (계속)

앞의 Post에서 실제적인 데이터 접근용 클래스의 틀을 만든 거라면, 지금 부터는 그 안에서 실제적인 동작과, 그 활용 방법을 구현하는 작업을 한다.

a. Select

가장 기초적인 구현입니다. 저장된 데이터가 있어야 겠지만, 대부분의 DB 관련 프로그래밍을 하면, 이 Select 에서 시작해서 Select로 끝나는게 대부분이라 생각한다.
앞의 내용까지 따라갔다면, GuestBookDataSource 라는 이 클래스가 있을 것이고, 그 클래스 안에 아래와 같은 Method를 추가한다.

public IEnumerable<GuestBookDataEntry> Select()
{
    var result = from g in this.context.GuestBookDataEntry
                 where g.PartitionKey == "GuestBookRawData"
                 select g;
    return result;
}

이 내용은 그 Hands on Lab의 내용을 그대로 차용한 것이다.
사실 이 문구를 보고서 심각하게 LINQ 부터 시작해야 할 까? 고민을 많이 했다. 아니 C# 안에서 form, select, where를 쓰는 건 이거 솔직히 반칙이다. MS의 수석 엔진니어들에게 욕이라도 퍼붑고 싶어졌다. 그러나 이미 구현되어 있고, 알게 모르게 .NET 개발자들은 이를 새로운 기술로 받아들여 사용 중이니, 불만은 내 속에서만 삭히고 결국 문법을 가만히 보게 되었다.

먼저 Return Value.

아마 DataTable 이라는 개체를 통해 Select 명령어를 쓰신 분은 약간 부담이 없을듯 싶다.
DataTable.Select()의 결과는 DataRow의 배열 값인데, 저 IEnumerable<GuestBookDataEntry> 라는 것은, GuestBookDataEntry의 배열과 같은 형태라 보면 된다. 단지, 배열보다 더 많은 기능과 활용도가 있다는게 그 차이. 그냥 배열 형태를 좀 멋지게 그리고 유연하게 Return 하는 구나 하고 넘어가면 된다.

자, 이제 부터 진정한 산맥.

var.

무슨 JavaScript도 아니고 var 라니. 그러나 이것도 엄연한 C#의 Keyword. 즉 외부에서 온 값 중 그 형태를 정의할 수 없는 기묘한 값인 경우 이 var를 사용한다. 물론 단항이면 object 한방이면 모든 데이터형 감쌀 수 있지만, 저게 배열일지, 단항일지는 모른다. 그래서 var를 사용한다. var 형태로 정의된 변수는 그 데이터가 처음 들어가는 순간 그 형이 결정된다.

  • var strVal = “aaaa”;     // strVal은 이 순간 문자열로써 동작해버린다.
  • var intVal = 55; // intVal은 이 순간 int (정수형)으로써 동작해 버린다.
  • var dblVal = 5.555; // dblVal은 이 순간 dobule 로써 동작해 버린다.

참… 알기 쉬운 내용이지만, 순간 쓰긴 참 뭐시기한 내용이다. 그래서 var는 초기화 자체를 할 때 아주 고민 지대로다.  그래서 위와 같은 메소드를 만들때, 그냥 var result = …; 라고 적어버렸다.

다음은 from .. ..

앞서 만든 클래스 내용 중 GuestBookContext 라는 것이 있다. 그 안에 아무 생각없이 만든 프로퍼티인 GuestBookDataEntry 라는게 있다. 아마 Return 값이 IQueryable<GuestBookDataEntry> 인데, 바로 이 프로퍼티를 통해서 마치 DB의 Table 처럼 쿼리 할 수 있는 것이다. 아마 내부적으로는 Select … from .. 의 from 처럼 DB 테이블에서 값을 긁어오기 위한 무언가의 작업을 수행하는 것이다.
여튼 이 from 뒤에 쓰일 수 있는 것인 TableServiceContext를 상속받은 클래스에서 IQueryable<T>의 Return 값을 돌려주는 프로퍼티를 써야 된다는 사실만 기억하면 된다.
아 여기서 Table의 문법은 다음과 같다.

<변수명> in <context>.<Property>

즉 아래와 같이 볼 수 있다.

g in this.context.LottoSvcDataEntry

그리고 where .. ..

뭐  from 나올때 이미 감 다 잡으셨지만, 맞다. select form where 이다. 단지 그 순서가 미묘하게 다를 뿐.
SQL의 where 절 쓰듯이 쓰면 된다. 단지 비교 연산자가 C#에서 사용되는 비교 연산자의 차이일 뿐이다.
즉 = –> == 로 AND는 && 로 쓰면 된다.

마지막으로 select

select 뒤에 필드명 적게 되어 있는데, 이 필드를 무작정 적는게 아니고, 앞서 Table 선언할 때 사용한 변수를 이용하여 사용한다. 즉 from <변수명> in <IQueryable 프로퍼티> 의 형태에서 있는 <변수명> 이거다.
위의 예제에서는 g 라는 변수를 썼으니 여기서는 g 라고 썼다. 만을 그냥 그 변수명을 쓰면 “*”의 의미가 된다.

아직 실험은 안해봤지만, 특정 필드의 값을 빼려면, <변수명>.<필드명> 하면 될 거라 생각된다. 즉 이름 빼오기 할 때, g.Name 하면 되지 않을까 싶다.나중에 한번 해보려고 한다.

여튼 이와 같이 select 문을 만들어 var의 변수에 때려 박으면 IEnumerable<T> 형태로 값이 돌아간다.
값이 있든 없던 위의 형태로 들어가게 된다.

b.Insert

사실 이 부분 부터 해야 select 테스트도 되지만, 사실 SQL의 핵은 Select 다 보니, Select를 먼저 설명하게 되었다. 애석하게도(?) Insert는 위의 형태 처럼 C# 같지도 않은 문법으로 처리하지 않는다. 즉 아주 평범하게 (?) Insert를 한다.

먼저 Insert 할 데이터 기본형인 Entitiy 클래스를 new 해서 만든다. 그리고 그 데이터에 값을 넣고, AddObject를 통해 값을 밀어 넣는다. 마지막으로 Save 한다. 이게 전부다.

즉 위의 예제로 본다면 아래와 같다.

public void AddDataEntry(string Name, string Email, string HomePageUrl)
{
    GuestBookDataEntry newItem = new GuestBookDataEntry ();

    newItem.Name = Name;
    newItem.Email = Email;
    newItem.HomePage = HomePageUrl;
    newItem.writtenDate = DateTime.Now;

    this.context.AddObject("GuestBookDataEntry ", newItem);
    this.context.SaveChanges();
}

즉 newItem 이라는 변수에 새로운 데이터를 넣을 공간을 만들고, 그 안에 데이터를 채우고 난 뒤, AddObject 함수를 통해 값을 밀어 넣는다. 이 때, AddObject 라는 함수 첫번째 인자가 문자열을 넣게 되어 있는데, 이 부분에 Entity에 해당하는 클래스 이름을 넣는다. 즉 위에서는 GuestBookDataEntry 이니, 이를 넣으면 된다.
(내부적으로 어셈블리에 대한 reflect 작업을 할 때 사용되는 것 같다. 만일 저 문자열이 틀리면 알아 먹기 힘든 오류가 나기 때문에 주의해서 넣도록 한다. )
자 일단 변경작업을 수행했으니, 마지막으로 SaveChanges 함수를 불러 저장하도록 한다.

c.Update

이것 역시 Insert와 유사하다. 해당하는 Entity의 개체를 꺼내고 그 개체의 내용을 변경한 뒤, 변경용 메소드인 UpdateObject 를 호출하고, 마지막으로 SaveChange 한번 해주면 된다.
뭐 역시 이 또한 코드로 보는게 제일 빠를 듯.

public void ChangeHomePageUrl(string Name, string HomePageUrl)
{
    var result = from g in this.context.GuestBookDataEntry
        where g.PartitionKey == "GuestBookRawData" && g.Name == Name
        select g;

    if(result.Count<GuestBookRawData>() == 1)
    {
        GuestBookDataEntry curEntry = result.ElementAt<GuestBookRawData>(0);
        curEntry.HomePage = HomePageUrl;
        this.context.UpdateObject(curEntry);
        this.context.SaveChanges();
    }
}

보면 특정 Entity의 값을 가져와서 그 값을 변경한 뒤, UpdateObject를 부르고 다시 SaveChange 하는 것을 볼 수 있다. (굵게 칠해진 부분만 참조)

기존 값을 불러오는데는 앞서 사용한 select를 사용했다. 단, 조건이 하나 더 붙는데, Name이 같은 이름을 가진 Name 인경우에 해당하는 것이다. ( 물론 Name이 둘 이상이면 처리하지 않는 문제점은 그대로 안고 가지만… ) 일단, 무조건 이름이 1개라는 가정에서 해당하는 이름이 적은 내용을 가져온 뒤, 최종적으로 꺼내와서 그 안의 값을 변경했다. 여기서는 HomePage가 그 값을 의미한다.
그리고 나서 UpdateObject를 호출한다. AddObject와는 다르게 이미 존재하는 Entity이기 때문에, 굳이 클래스명 따위는 넘길 필요가 없을 것이다. 업데이트가 완료되면 마지막으로 Save를 하는 작업을 하게 된다.

d.Delete

이제 Action의 마지막 Delete 이다. Update와 모든 동작이 동일하며, 단지, UpdateObject를 쓰는게 아니라, DeleteObject를 쓰면 된다. 특정 이름의 항목을 지우는 로직이다.

public void DeleteBook(string Name)
{
    var result = from g in this.context.GuestBookDataEntry
        where g.PartitionKey == "GuestBookRawData" && g.Name == Name
        select g;

   if(result.Count<GuestBookRawData>() > 0)
  {   
     foreach(GuestBookDataEntity entry in result)
    {
        this.context.DeleteObject(curEntry);
     }
     this.context.SaveChanges();
   }
}

Select로 각 Entity 들을 빼내고 그 내용을 DeleteObject를 호출 한 뒤, 맨 마지막에 SaveChanges()를 호출한다.

 

5. 데이터 활용.

자 이제 만들어진 DataSource를 가지고 데이터 조작을 해보도록 한다.
사용자와 직접적인 I/F를 담당하는 것은 Web_Role 부분. 기본적인 Web-Role을 만들었다면, 별도 Web Project가 한개 열렸을 것이다. 이 Web-Role용 프로젝트에서 참조를 하나 추가한다. 추가할 참조는 바로 이 DataSource가 담긴 프로젝트. 일단 참조 관계가 만들어져야 Web-Role에서 사용 가능하다.

먼저 기본적으로 생성된 Default.aspx 의 코드에서 Select를 호출해서 사용해 본다.
DataSource로도 바로 이용가능하기 때문에, Hands on Lab을 보면, DataGrid를 이용하여 한 큐에 작성한 결과물을 보여준다. 이 방법도 좋지만, 좀 무식하게 만들어 봐야 실제로 데이터를 꺼내고 하는게 눈에 보일 것 같다.

먼저 TextBox를 Web-Form에 추가한다.
그리고 난뒤 그 TextBox의 이름은 txtResult로 한다. 또, TextMode를 MultiLine으로 하고 Rows를 10 정도로 하자. 그러면 TextArea가 되니까, 결과물 보기에 그냥이다.
이제 다음과 같은 코드를 Page_Load 메소드 안에 추가한다.

GuestBookDataSource ds = new GuestBookDataSource();
IEnumerable<GuestBookDataEntry> result = ds.Select();
System.Text.StringBuilder sbResult = new System.Text.StringBuilder();
foreach (GuestBookDataEntry entry in result)
{
    sbResult.Append(entry.Name);
    sbResult.Append("(");
    sbResult.Append(entry.Email);
    sbResult.Append(" / ");
    sbResult.Append(entry.HomePage);
    sbResult.Append(")");
    sbResult.Append(entry.writtenDate.ToString());
    sbResult.AppendLine();
}
txtResult.Text = sbResult.ToString();

데이터를 꺼내는 방법이 보이지 않는가? 그냥 GuestBookDataSource를 생성하고, 그 결과 값을 이용하여 메소드를 호출하기만 하면 된다. 그리고 그 결과값을 나열하면 된다.
Insert나, Delete, Update도 마찬가지로 GuestBookDataSource를 생성한 뒤 불러 주면 된다.

6. 정리.

데이터 처리 관련해서 올려서 정리해봤다. 사실 LINQ에 대한 기본 지식이 거의 전무하기 때문에, 이 내용에 대해 정확한 동작 방법이나, 올바른 방법이나, 효율적인 처리에 대해서는 거의 알지 못한다.
단지, Hands on Lab을 따라하다가 보니, 이렇게 짜는 구나 정도이다.

필자 처럼 구현에 성급하신 분은 한번 위의 방법대로 구현해 보면 될 것이다.

( 현재 Lotto 당첨 번호 관련된 서비스를 한번 만들고 있다. 별로 로직은 어렵지 않은데, 은근히 Azure 자체의 벽이 높아서 당황했다. 그 중간의 결과를 여기에 기록으로 남기고 있다. )

728x90

( 조심 : 이 정보는 직접 Coding을 해서 얻은 결과 입니다. 실제 Azure 아키텍처를 명확히 이해하여 쓴 글은 아닙니다. )

Windows Azure에서 데이터를 저장하는 방식은 Table 기반의 저장 방식을 따른다.
물론 Azure 서비스 중 하나인 SQL 서비스를 직접 이용하는 방법이 있지만,
사실 그 방법 말고도, .NET 3.5 에서 제공하는 LINQ 방식을 이용하여 만드는 방법이 있다.
그리고 현재 Windows Azure Platform Kit ( 11월 버전 ) 에 담긴 Hands on Lab을 하다 보면,
이렇게 구성하는 구나, 싶다.


1. 데이터 저장을 위한 Table 구성

데이터의 기본은 표. 즉 Table 이다. 그리고 그 Table에 데이터를 쌓는 것을 레코드 혹은 Row 라고 한다.
그리고 각 데이터의 종류를 나타내는 것을 필드 혹은 Column 이라고 한다.

Table

  Column  
Row ->    
     
     

여기서는 위의 구조 중 Row와 Table을 구현하여 데이터를 구성하게 된다.

먼저 Table을 역할을 하는 Data 기본 셋으로 Windows Class Library 프로젝트를 하나 생성한다.
즉 Table이 여러 개 필요하면 그에 맞추어 프로젝트를 생성하면 된다.
( 이 부분은 나중에 Azure 문서 중 Data 관련된 사항을 더 공부하고 정리할 예정이다.)

즉 필요한 Table 만큼의 Windows Class Library 프로젝트를 생성하도록 한다.( Hands on Lab에서는 방명록을 구현하는데 그 때 사용되는 데이터를 구성하기 위해 하나의 Class Library 프로젝트를 만드는데 바로 그게 데이터 저장을 위한 Table 역할을 하게 된다. )

단 .NET Framework 3.5 이상 용으로 만들어야 한다.
    그래서 개발 환경 조건에, Visual Studio 2008 이상이 필요한 것이다.


이 때 프로젝트에는 다음과 같은 어셈블리를 Reference 해야 한다.

System.Data.Services.Client   ( .NET Framework 3.5 )
Microsoft.WindowsAzure.StorageClient   ( Azure SDK )

일단 위의 레퍼런스가 끝났다면 이제 Row을 구성한다.

2. 데이터 구조 잡기 가장 기초 부분 Entity

위에서 언급한 Row 부분 – 관점을 조금 돌리면 Column을 구성하는 것? 이라고 볼 수도 있다. - 을 구성하는 방법이다. 어떤 데이터를 어떻게 저장할 것인지를 결정하는 부분이다.
방법은 다음과 같다.

  1. public 클래스를 만든다.
  2. Microsoft.WindowsAzure.StorageClient.TableServiceEntity 를 상속 받는다.
  3. 생성자를 만든다.
  4. 생성자 안에 PartitionKey 와 Row Key를 설정한다.
  5. 프로퍼티를 만든다.

위의 다섯 단계를 찬찬히 설명하면 아래와 같다.

1과 2는 C#의 기초 단계와 다름이 없을 것이다.
일단 using을 써서 Microsoft.WindowsAzure.StorageClient 를 추가하는 줄을 넣는다.

using System;
using Microsoft.WindowsAzure.StorageClient;

그리고 난 뒤에, class 앞에 public 넣고, 맨 뒤에 : 을 넣은 뒤, TableServiceEntitiy를 넣는다

using System;
using Microsoft.WindowsAzure.StorageClient;

namespace GuestBook_Data
{
    public class GuestBookDataEntry : TableServiceEntity
    {

    }

}

위의 단계까지 왔으면 일단 기본은 끝난 것이다.

3~4 번 단계에서는 생성자를 생성하고, 그 안에 고유의 값을 넣는 작업을 한다.
단 기본 생성자로 생성해준다. 그리고, 이 GuestBookDataEntry 클래스는 프로젝트 밖에서  new 해야 되기 때문에, 이 생성자를 반드시 public으로 선언해야 한다. 
생성자 안에서  PartitionKey와 RowKey에 고유의 값을 넣어주도록 한다.
RowKey는 모든 데이터에서도 가장 유일한 값이여야 한다는 것은 이해했지만, PartitionKey는 DB의 Partition 과 유사한 기능 같았다. 그래서 이 부분은 그냥 다른 Table과 구분되는 정도의 레벨의 데이터로 생각하여 넣었다. PartitionKey 는 알아서.. 잘 넣어주시면 될 것 같다.

using System;
using Microsoft.WindowsAzure.StorageClient;

namespace GuestBook_Data
{
    public class GuestBookDataEntry : TableServiceEntity
    {
        public GuestBookDataEntry()
        {
            PartitionKey = "GuestBookRawData";

            RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
        }
    }
}


5번 단계에서는 실제 값이 어떻게 들어갈지를 정의하면 된다.

using System;
using Microsoft.WindowsAzure.StorageClient;

namespace GuestBook_Data
{
    public class GuestBookDataEntry : TableServiceEntity
    { 
       public String Name { get; set; }
        public String Email { get; set; }
        public String HomePage { get; set; }
        public DateTime writtenDate { get; set; }

        public GuestBookDataEntry()
        {
            PartitionKey = "GuestBookRawData";

            RowKey = string.Format("{0:10}_{1}", DateTime.MaxValue.Ticks - DateTime.Now.Ticks, Guid.NewGuid());
        }
    }
}

C# 3.0 에서 사용되는 프로퍼티의 기본형으로 써주면 된다.
public으로 정의하고 그 데이터 형을 결정한 뒤, get과 set을 정의해주면 된다.
( C# 3.0에서 보면, 프로퍼티에서 그냥 get;set; 을 써주면 알아서 저장된다. )

아직은 기본형만 써봐서, 다른 형태의 Class 데이터나 복합형 데이터는 만들어보지는 않았다.
일단, 위와 같은 형태로 구성한다.

그러면 기본적인 Row 가 정의된다.

3. Context 구성하기.

데이터의 입출력을 할 때, 그 흐름을 정의하는 부분이라고 보면 된다.
어디서 저장되고, 어디로 저장되며 어떻게 진행되는지. 그러나, 실제로의 구현은 모두 기본값 만을 이용하여 생성할 예정이다. 그러므로 코드는 무척 간단하다.

using System;
using System.Linq;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace GuestBook_Data
{
    public class GuestBookDataContext : TableServiceContext
    {
        public GuestBookDataContext(string baseAddress, StorageCredentials credentions)
            : base(baseAddress, credentions)
        {
        }

        public IQueryable<GuestBookDataEntry> GuestBookDataEntry
        {
            get
            {
                return this.CreateQuery<GuestBookDataEntry>("GuestBookDataEntry");
            }
        }
    }
}

위의 코드 중 굵은 부분만 구성해주면 된다. 그런데, 저 붉은 부분은 좀 신경써서 정리해주어야 한다.
만일 저 붉은 내용의 문자열이 조금이라도 틀리면 알기 힘든 오류를 내어 디버깅 자체가 어려워 질 수 있다.
반드시 저 붉은색 부분은 신경써서 넣어주기 바란다. 저 붉은 부분에 넣는 것은 앞서 선언한 Entity 에 대한 Class 이름이다.

4. 데이터 접근용 Class.

사실 위의 두개의 class만 있어도 기본적인 데이터 접근은 가능하다. 하지만, 외부에서 데이터 호출을 위한 로직을 직접 선언하여 구축하는건 조금 지저분 해지기 때문에, 가급적 이런 대리자의 역할을 하는 클래스 구성이 효율적일 수 있다.

이 클래스는 굳이 상속 받을 필요는 없다. 생성 한 뒤, 데이터를 쿼리하거나 데이터를 넣는 정도의 인터페이스만 제공하면 되는 클래스 이기 때문이다.

먼저 Skelton 코드로는 다음과 같다.

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;

namespace GuestBook_Data
{
    public class GuestBookDataSource
    {
        private static CloudStorageAccount storageAccount;
        private LottoSvcDataContext context;

        static GuestBookDataSource()
        {
            storageAccount = CloudStorageAccount.FromConfigurationSetting("DataConnectionString");

            CloudTableClient.CreateTablesFromModel(
                typeof(GuestBookDataContext),
                storageAccount.TableEndpoint.AbsoluteUri,
                storageAccount.Credentials);
        }

        public GuestBookDataSource()
        {
            this.context = new GuestBookDataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
            this.context.RetryPolicy = RetryPolicies.Retry(3, TimeSpan.FromSeconds(1));
        }

    }
}

위에서 보는 것과 같이 생성자를 두 개 만든다.

둘 다 생성자이기는 하지만 그 역할을 판이하게 다르다. static 으로 선언한 생성자는 프로그램이 시작할 때 new 하던지 말던지 1회성으로 무조건 1번 실행하는 단발성 생성자다. 여기서는 앞서 만든 테이블 구조에 따라 가상의 테이블을 만들어주는 역할을 하게 된다.

그리고 두번째에 위치한 생성자는 일반적인 생성자로, 실제 이 데이터 관련 작업을 수행할 때 new 해서 생성하면 불리는 생성자다.

그리서 첫번째의 static 생성자에서는 CloudStorage 관련 도구를 사용하여 Table을 실제적인 인스턴스를 생성하는데 그 역할을 다하며, 두번재의 일반 생성자에서는 그 만들어진 Table에 접속하기 위한 기초적인 내용이 담기게 된다. 이 때, Static 생성자에서 사용하는 DataConnectionString 부분을 주목하자.
저 문자열이 뜬금없이 나온 문자열은 아니다. 분명 누군가가 저 값을 가져왔기에 그 내용을 쓸 수 있는 것이다.

저 내용은 이 DataSource를 New 해서 만들어서 사용하는 주체인 Web-Role 혹은 Worker-Role의 옵션에서 설정하게 된다. 이에 대한 설명은 나중에, 그냥 설정하는 방법은 다음과 같다.

  1. Solution Explorer 안에서 Service 목록이 나오는 곳을 찾는다. ( Azure 프로젝트로 만듦면 특이한 아이콘으로 생긴 프로젝트가 보인다 )
  2. 그 중에 설정하려고 하는 Role 부분에서 오른쪽 버튼을 클릭한다.
  3. 속성 창이 뜨면, 왼쪽 항목 Tab에서 Settings를 선택하고 AddString을 한 뒤, Name에 DataConnectionString을 넣고, Type은 ConnectionString을 Value는 그냥 기본값을 둔다. ( 기본값으로 하면, 로컬 DB에 저장하겠다는 의미 )

일단 이 DataSource 라는 것을 사용하는게 Web-Role이라는 가정하예서, Web-Role에 있는 설정을 변경하는 작업을 나타낸다.

일단 여기까지.
실제 DataSource 의 Select, Insert, Update, Delete 구현은 다음으로~

728x90

Azure 관련 개발을 하려면 제일 먼저 로컬 컴퓨터에서 어느정도 개발을 할 수 있어야 할 것이다.
그러려면, 개발에 필요한 각종 환경을 갖추어야 하는데, 이를 위한 준비물로는 다음과 같다.

준비물

Windows Vista 혹은 Windows 7 ( 단 Professional 버전 이상. IIS가 설치될 수 있어야 한다. )
Visual Studio 2008과 그 서비스팩 1
SQL Server 2008 Express 버전.
Azure SDK 최신 버전( 현재 : 11월 버전 )
Visual Studio 지원 확장팩 ( 현재 :11월 버전 )

구성하기

IIS 활성화

먼저 IIS Feature를 활성화 한다.
" 시작 -> 제어판 -> 프로그램 -> 윈도우 기능 활성/비활성 "에 들어간다.
그리고 "인터넷 정보 서비스" 항목에 들어가 다음에 보이는 것 처럼 체크하여 활성화 시키도록 한다.
(아래의 그림은 Windows 7 Professional 버전 임 )


상세한 설정 방법은 다음 페이지를 참고하도록 한다.
http://msdn.microsoft.com/en-us/library/dd179419.aspx


SQL 서버 설치.
일단 여기까지 준비가 되었다면 이제는 SQL Server 2008 Express를 설치한다.
일반 DB 설치와 거의 동일하다. 기본 값으로 설정해주면 된다.

Azure SDK를 설치
이 설치 작업도 기본값 대로 설치만 해주면 된다.
만일 위의 단계에서 IIS를 설치 안한다면 설치가 안된다.

Visual Studio 지원 확장 팩.
처음 부터 날로 코딩할 의도가 아니라면 최소한 이 지원팩은 설치하도록 하자.
Visual Studio 안에서 각종 틀을 잡는데 시간이 오래 걸리는 것을 최대한 방지할 수 있다.
Visual Studio의 버전이나, 서비스 팩의 유무에 따라 설치가 안될 수 있으니 반드시 확인하고 설치하도록 하자.

Azure Database 서비스 흉내 내도록 만들어주기.
시작 -> 프로그램 -> Windows Azure v1.0 -> Windows Azure SDK Command Prompt 를 실행한다.
(Azure SDK 가 설치된 위치를 알면, 그 위치에 있는 bin 폴더로 가도 된다. )
거기서 csrun.exe /devstore start 를 실행한다.


Azure 서비스 확인 UI 도구 실행하기.
위와 동일한 위치에서 ( 시작 -> 프로그램 -> Windows Azure v1.0  ) Developement Fabric을 실행한다.
그러면 트레이 아이콘으로 윈도 마크가 보이는데 이 UI가 백그라운드로 실행 중인 Azure 에뮬레이터 비스무리 한 내용을 보여주는 내용이다.

프로젝트를 한번 만들고 빌드 해보자.
그러면 최종적으로 빌드 결과물에 다음과 같은 폴더를 볼 수 있다.


저 위치로 명령어 창으로 들어가, 이제 아래와 같이 입력한다.

csrun /run:{솔루션이름}.csx;Publish\ServiceConfiguration.cscfg /launchBrowser

그러면 로컬 Azure 에뮬에 등록되어 올라가면서 자동으로 해당 사이트가 웹브라우저로 뜨게 된다.
728x90
Azure 서비스 는 현재 x64 환경에서 동작되고 있다.
그래서 컴파일이라든가, 구성하는 경우 종종 x64 관련 경고가 뜨게 된다.
가급적 개발 자체는 x64에서 하는 것이 좋다.

The Windows Azure development fabric and development storage are running on a 32-bit workstation. In the cloud, Windows Azure Hosted Services run in a 64-bit environment. The use of native code execution or .Net Full Trust features such as P/Invoke may require migration to 64-bit. See http://go.microsoft.com/fwlink/?LinkId=145047 for details.


다음과 같은 경우에는 조심해야 할 것같다.

Role 구성시 FastCGI를 사용하는 경우.
서브 프로세스를 생성하는 경우.
P/Invoke를 사용해서 내장 라이브러리를 호출하는 경우.

즉, 순수 .NET으로 구성하거나, 시스템과 직접적으로 부딛히는 경우가 없다면 전혀 신경 쓸 필요 없다는 사실.
x85이나 x64나... 뭐...



728x90
지금 ClearQuest로 XMLHttpRequest를 해야 되는 경우가 발생되어 적용하는 중,
예제로 준 방법이 Perl 방법이라 난해 한데다 제대로 수행되지 않는 경우가 발생했다.
그래서 VBScript로 적용 선회를 했고 간신히 성공했다.
여기저기 사이트를 통해 알아본 결과 내용을 정리하면 아래와 같다.


맨 먼저 VB에서 HttpRequest 처리를 하려면, XMLHttpRequest를 지원하는 Object를 만들어야 한다.

Dim xmlhttp

xmlhttp = CreateObject("Microsoft.XMLHTTP")


위의 내용을 보면 Microsoft.XMLHTTP라는 오브젝트를 생성하게 되는데, 대개 위의 오브젝트를 생성하면 크게 버전문제와 상관 없이 동작할 것이다. 간혹 유사한 이름이긴 한데, 다른 형태의 XMLHTTP를 부르려면, XML 버전에 따라 지원하기도 하고 안하기도 하는 변덕을 구경하기 때문에, 그냥 위의 내용 처럼 적용해주면 된다.

xmlhttp.open "POST" "http://localhost/ReceiverForData.aspx", false


이번엔 위에서 정의해서 만든 HttpRequest 오브젝트로 실제 호출하기 위한 구성을 해준다.
POST 부분은 데이터가 어떻게 HttpRequest를 타고 전달되는지를 결정하게 되는데,
GET으로 하게 되면 주소값 내에 전달할 데이터가 담기게 되고, POST를 하게 되면 별도로 데이터를
추가해 넣을 수 있다. 이 때 데이터가 크거나 다양한 경우 가급적 POST로 전달하는게 좋다.

xmlhttp.setRequestHeader "Content-Type","application/x-www-form-urlencoded"

  
사실 HttpRequest는 일종의 숨겨진 웹브라우저를 띄워 웹서버를 호출 하는 것이다. 단지 사용자 눈에 브라우저가 뜬 것을 보지 못할 뿐, 뒤쪽에서는 마치 그런 짓을 하고 있는 것이다. 이 때 웹 서버를 호출하는 순간 웹서버에게 자신의 신분을 알려주는 작업을 해야 하는데, 이 작업에 해당하는게 바로 Header에 데이터를 넣는 것이다.
여기서는 현재 웹서버에 데이터를 전달 할때, form 기반으로 데이터를 전달하는 형태라는 것을 알리게 된다.

xmlhttp.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.2)"

  
위와 동일한 역할을 한다. 단지 이 부분은 현재 웹브라우저나, 컴퓨터 설정 상태들을 담는 내용이다. 완전히 웹서버를 속이고 자신이 마치 IE 8.0 인양 알려주는 작업이다. 간혹 일부 웹서버에서는 위와 같이 브라우저 버전이 IE, FireFox, 같은게 아니면 튕기는 작업을 당할 수 있기 때문에, 가급적 자신의 신분을 저렇게 숨겨 놓는게 제일 좋다.
xmlhttp.send "ID=OKSK&Name=OsakuSakurazo"

Post 형태의 데이터를 전송할 때 저렇게 한다. 보낼 데이터가 없으면 빼면 되고, 있다면, 변수이름=값 형태로 쭉 나열한다. 2개 이상의 값을 전송할 때는 사이에다 "&"를 넣어주도록 한다.

만일 결과물이 필요하다면....

xmlhttp.responseText


에서 빼오면 된다.(웹페이지 내에서 Text만 쭉 긁은 값이 나오게 된다.)

이 자료를 만드는데 사용한 Reference들은 다음과 같다.
http://web5.w3.org/TR/XMLHttpRequest/
http://msdn.microsoft.com/en-us/library/ms535874%28VS.85%29.aspx

728x90

요즘 뜨는 화두중 하나가 바로 클라우딩 컴퓨터다.
인터넷을 통해 각종 서비스를 제공하는 일종의 ASP 같은 형태인데, 기존 ASP와는 다르게, 동작을 위한 Platform을 제공한다는 것이다. 그렇다고 웹 호스팅 업체 처럼 운영체제 단을 제공하는 것은 아니고, .NET 환경의 응용 프로그램이 동작하기 위한 기초 서비스들을 제공한다는 의미이다.

사실 획기적인 사업 아이템은 아니라 생각된다. 호스팅 업체 잡고 하거나, IP 업체와 Join 해서 네트워크 선을 사내에 끌고 들어와 사내 서버실에서 하면 되었고, 사실 지금도 그렇게 하고, 계속 그렇게 진행될 것이다.
하지만, 작은 업체에서 자체적인 서버실은 무리가 있고, 그렇다고 비싼 호스팅 업체에 네트워크 비용 뿐만 아니라, Rack이나 서버 임대료등은 역시나 무리가 있다. 그렇다고 운영체제에 SQL 까지 사다 보면, 어느새 돈 천만원이 넘어가버린다. 얼마로 책정될지는 모르겠지만, 최소한 호스팅 업체보다 싸다고 한다면, 분명 이런 클라우드 컴퓨터 시스템은 나름 괜찮은 비용으로 훌륭하게 서비스 받지 않을까 싶다.

일단 .NET 기반의 어셈블리등을 배포 할 수 있고, SQL의 기본적인 데이터형은 대부분 지원한다. 게다가 IIS 7에 ASP.NET 3.5 그리고 각종 Workflow에 WCF의 기본 구성까지 모두 가능하다.
그런데 국내 각종 소개 자료를 보면, 지금까지 글로 쓴 내용 처럼 무언가 비지니스 적으로 좋거나, 기존 기술 보다 낫다는 수준에 불과해 내가 이해하기가 애매 했다.
그러다가 하나씩 문서를 보면서 문득 이 Azure 서비스가 바로 MVC를 기반으로 제공된 또하나의 프로그래머들의 놀이터라는 생각이 들었다.


 
복잡허니 무언가 무척 많았지만, 사실 저 3가지의 형태를 갖춘 것이 바로 Azure였다.
사용자와 직접 맞부닥치는 웹 페이지나, 웹 서비스는 모두 Web Role에서 관장한다.
그리고 Worker 부분에서는 데이터를 조작하거나, 변경, 계산하는 작업을 하게 된다.
이 때 Worker는 마치 윈도우의 서비스 처럼 주기적을고 계속 뱅뱅이를 도는 구조로
되어 있다. 즉 Web에서 사용자의 Action이 없어도 알아서 무언가를 처리하려 할 때
바로 이 Worker를 사용한다.
Storage 부분에서 데이터를 저장하게 된다. 기본적으로 DB의 구조를 따르고 있지만,
굉장히 추상적으로 구성되어 있는데, 아직까지 상세한 내용은 잘 모르겠다.

이 때, 괄목할만한 사항이 있는데, 바로 Web과 Worker간의 통신이다.
물론 Web쪽에서 Worker를 직접 부를 수도 있겠지만, 여기서는 직접 부르기 보다,
Queue라는 비동기 로직을 통해 주고 받는 구조로 되어 있다.
즉 View와 Control의 직접적인 커플링을 최소화 하겠다는 의지인 것이다.

실시간으로 데이터를 업데이트 하는데는 조금 무리수가 있지만,
비동기적으로 처리하려 할 때 이보다 좋은 구조가 없으리라 생각된다.

지금 계획적인 개인적인 프로젝트가 있는데, 한번 이 Auzre를 이용해 구현 해봐야 겠다.
728x90

Server 끼리 동작되는 모듈 개발자나, 아키텍처 개발자는 별 상관 없는 이야기 일듯 싶다.
이 부분은 End-User 들이 직접 만지는 Presentation 영역을 개발하는 개발자들에게 해당되는 이야기이다. 요즘은 IE로 통일된 웹 브라우저 시장이 모조리 분할되어가고 있다. 사실 FireFox나 Chrome, 그리고 사파리가 대세가 되고 있는 상황이다. 이에 다급한 MS는 부랴부랴 8.0 을 만들어 배포하기는 했지만, 이제 마음 돌린 사용자들의 마음을 쉬이 돌리기는 어렵다. 국내와 미국 내 브라우저 시장을 보면 아래와 같다.

국내브라우저 시장(자료 출처 : Internet Trend)

미국내 브라우저 시장(자료 출처: Market Share)

자료를 보면 아직은 70%를 넘는(우리나라는 절대 다수가…) IE 이긴 하다. 그래서 모든 개발의 중심이 IE로 구성되어 있는 것도 사실이다. 그렇지만, Trend는 변하게 된다. 사실 MS도 IE 6.0 에서 여차하면 비표준 Javascript와 Active X 기술로 대충 매꾸고 넘어왔다. 그러나 지금은 보안적인 이슈 문제나 비 표준의 불이익을 하나씩 겪으면서 IE도 표준의 대열로 들어오고 있고 규칙을 지키기 위해서 안간힘이다.

그런데 우리나라 브라우저 시장은 전혀 그렇지 않다.

사실 게임 사이트와 은행 사이트에 들어가면 Active X가 3개 이상 설치되는 건 예사다. 게다가 IE가 아니면 Javascript가 비정상 동작하는 바람에 선택상자가 제대로 표시안되는 경우도 종종 있다.

그런데, 요즘 웹 트렌드를 쫒아 간다는 포탈(네X버)에서 조차 이런 현상이 발견된다. 아마도 Front 부분만 다른 브라우저와 동일하게 나오면 되지.. 이런 마음일까?

아니다. 이건 그 회사 잘못이라기 보다는 지금까지 일해오던 웹 프로그래머들의 생각자체가 문제라 생각이 든다. 한 사람이 한 회사의 메인 플랫폼이나 개발 프레임워크를 갈아 엎는건 불가능하겠지만,  최소한 자신의 모듈에 대한 개발 시에 표준을 지키기 위해 하나씩 맞추어 갔으면 이런 자잘한 오류는 발생되지 않을까?

실제로 우리회사 내 웹 프로그래머는 아직도 버릇 처럼 document.all[xxx']를 쓴다.
웃기기 그지 없지 않나? 뭔가 좀 생각을 바꾸고 하나씩 자신의 포지션에 대해 생각하면서,
막연히 남의 일처럼 흘려 보내지 말고 고쳐 보면 어떨까?

지금 당신 Javascript로 무언가 짜고 있다면 WebBrowser-Independency 하게 하나씩 구성해보는 건 어떨까? 불가능하다고 생각하고 있다면 한번 JQuery를 보고 그 말한마디 부탁한다.

728x90

이번 프로젝트에서 최초로 Front End 웹페이지 부분을 프로그래밍 하다 보니, 내 나름대로 CSS에 대한 개념을 다시 쌓게 되었다. 이에 대해서 정리하도록 한다.

예전에는 CSS의 역할에 대해서 크게 생각해본적이 없었다. 대부분은 Front End 웹페이지에 대한 수정이나 편집 보다는 대부분 Back 단 서비스 계열의 구성이 대부분이였기 때문이다. 또한 디자이너가 임의로 수정 또는 구성한 CSS를 그대로 가져다 쓰고, 일부 프로그램으로 구성 중에 변경될 필요가 있는 경우, Internet Explorer Toolbar를 이용하여 특정 CSS를 찾아 해당 되는 값을 변경하는게 전부였다.

그런데, 금번 프로젝트에서 JQuery를 하면서 내 자체적으로 필요한 CSS 들을 정의하고, 구성하다 보니, 디자이너들이 구성했던 내용과는 다른 구성이되어버렸다.

현재 디자이너들이 정의한 CSS들의 유형을 보면 다음과 같다.

1. HTML Element 별로 구성.
   <td> 혹은 <span>, <input> 등 특정 엘리멘트에 대해 디자인적인 적용 작업.

2. 필요한 값에 따라 구성.
   padding-left가 5 가 필요하면 gg_pl_5p 라는 이름으로,
   text가 bold로 표시되는 부분이 있으면, gg_txt_bold 라는 이름으로 정의된 방법.

각 HTML을 보면, 일단 전반적인 구성 내용은 1번의 유형대로 HTML Element에 전반적인 설정을 시도했다. 그래서 모든 페이지 해당 Element들은 기본적으로 동작하게 했다. 그리고 난 뒤, 세세한 변경 작업은 해당 부분의 class=" " 안에 특정한 상태 값에 따라 필요한 값에 해당하는 클래스들을 추가하는 방식이였다.

만일 padding-top 이 10px이고, padding-left와 right가 5px이고, 이텔릭 체라면....

class="gg_pt_10p gg_pl_5p gg_pr_5p txt_italy"

처럼 구현되어 구성되어 있는 것이다.

물론 HTML 코딩된 내역을 요청하면 필요한 사항에 맞게 구성되어 있으므로 디자이너가 원하는 대로 나오게 된다.

그런데, 이렇게 구성되면 특정 구성요소에 대한 수정이 필요한 경우, 해당 구성요소의 class들을 따라 들어가 수정하게 된다. 즉 HTML 코드가 되었든, .NET의 C# cs 코드가 되었든, PHP z코드가 되었던, 해당 코드의 class 부분을 수정하고 다시 배포를 해야 한다.

이것을 만일에 역할별로 Css를 정의하게 되면 어떨까?

현재 필자가 하는 작업이 WSS의 SharePoint이므로, WSS를 기준으로 예를 들어보겠다.

SharePoint도 결국은 WebPage를 표시하는 것이므로 WebPage 가 있을 것이다.
그리고, 그 WebPage 내에 특별한 경우가 아니라면 WebPart와 WebControl들이 있다. 그리고 그 WebPart와 WebControl을 각기 기능에 따라 다르게 구현되곤 한다.

이렇게 프로그램이 구성된 것과 동일한 구조를 가진 CSS를 가지게 되면 어떨까하는 것이다.

먼저 WebPage 라는 class를 구성한다. 그 class에서는 전반적인 페이지 자체의 css를 정의한다. 배경색이나, 기본 폰트라든가....

그리고 WebControl 에서는 WebControl이라는 class를 구성한다. 이 class에서는 기본적으로 WebControl들이 갖는 기본 형태에서 필요한 구성요소들을 정의한다. 모든 WebControl들은 이런 배경색을 가지고, Line-height 등을 결정한다. 그리고 그 WebControl로 만들어지는 특정 WebControl (예를 들면 달력 같은)이라면, 다시 NewCalendar 라는 class를 구성한다. 이 class는 WebControl의 내용을 그대로 상속 받고 단지 그 안에서 다시 overriding 해서 재 구성하게 되는 것이다.

WebPart도 마찬가지다.


즉 css를 스타일을 묶는 단순한 도구로 생각하여 구성하는 것이 아니라, 화면에 대한 전반적인 동선이나, 구성에 따라 class를 묶어 재구성하는 것이다. 이렇게 되면, 나중에 디자인적인 변경이 필요할 때, 특정 구성요소를 html 소스 상에서 편집하는 것이 아니라, css 내의 특정 값만 변경 만으로 디자인 자체를 변경할 수 있는 첫걸음이 될 수 있는 것이다.

이 개념이 나만의 특별한 생각이 아닌 현재 외국계 디자이너들의 CSS 구성하는 방법이라 생각된다.

728x90

+ Recent posts

728x90