영어를 잘 못해서 그런건지.. (잘 해도 어려울꺼 같은)
메니페스트는.. 일단 말부터 너무 어려운거 같아요..

일단 메니페스트가 뭔지. (더불어 어셈블리가 뭔지 한번 정리를 해보죠... 제가 잘 몰라서.. )




네이뇬이 이렇게 가르쳐 주네요...
하지만 제가 원하는 대답은 아니네요..

이제 곧 영국으로 가버리는(이제 얼굴좀 익혔는데. ㅠ) 경훈씨가 HOONS에 올린 글을 보면..


.NET Assembly

닷넷을 어느정도 공부해본 사람들은 어셈블리(assembly)에 대한 말을 많이 듣게 되는데, 닷넷 어셈블리가 무엇인지, 어떻게 사용하는 것인지 한번 생각해 보도록 합시다.

 

어셈블리란 무엇인가

1. 어셈블리는 코드들의 논리적인 묶음이다.

2. 어셈블리는 물리적으로 DLL또는 EXE로 존재한다.

3. 한 개의 어셈블리는 한 개이상의 파일을 포함할 수 있다.

4. 어셈블리안에는 어떤 형태의 파일도 포함될 수 있다(예: 텍스트 파일, 이미지파일등)

5. 작성된 소스코드가 어셈블리로 묶여지지 않다면, 다른 어플리케이션에서는 이용할 수가 없다.

6. 어셈블리파일엔 자체정보를 가지고 있는데 이를 어셈블리 메니페스트(Manifest)라 한다.

 

어셈블리 메니페스트(manifest) 대해

1. 어셈블리 메니페스트는 해당 어셈블리의 정보들을 저장하고 있는 데이터 구조(data structure)이다.

2. 이러한 정보는 어셈블리 파일(DLL/EXE) 자체에 포함되어 있다.

3. 메니페스트는 버전정보나, 구성된 파일의 리스트등을 포함하고 있다.

 

Private assembly VS Shared assemly

단일 어플리케이션에만 사용되는 어셈블리를 private assembly라 한다. 예를 들어서, 여러분이 업무로직을 가지고 있는 DLL을 하나 만들었다면, 그리고 DLL을 사용하는 클라이언트 어플리케이션이 오직 한 개이라면, 그것은 대부분 private assembly인 것이다. 이 때 프로그램이 제대로 동작되기 위해서는 프로그램이 설치된 같은 폴더에 DLL이 존재해야만 한다. 

이와 반대로, 만약 하나의 DLL을 만들고 나서 이를 여러 어플리케이션에서 사용하도록 만들었다면, 각 어플리케이션의 해당 폴더마다 복사본이 존재하는 것이 아니라, DLL을 Global Assembly Cache에 위치시켜야만 한다. 이러한 어셈블리를 shared assembly라 한다.

 

Global Assembly Cache ?

GAC(Global Assembly Cache)는 모든 shared assembly가 저장되는 특정 폴더일 뿐이다.

이 폴더의 위치는 <드라이브명>:/winnt/assembly 이다. 실제 이 폴더에 들어가보면, 많은 전역 어셈블리들을 볼 수 있다.

 

어셈블리는 DLL 지옥을 해결하였다는데

앞에서 언급했듯이 직접 작성한 대부분의 어셈블리는 private이다. 그러므로 각 어플리케이션은 자체적으로 설치된 폴더에 있는 어셈블리를 참조한다. Private형식에서는 같은 이름의 여러버전이 있다하더라도 충돌을 피할 수 있다.

이해를 돕기위해 한가지 예를 들어본다.

1. Assembly1이라는 이름의 어셈블리를 제작한다.

2. Assembly1을 이용하는 Client1이라는 어플리케이션을 만든다.

3. 클라이언트 프로그램을 c:\MyApp1이라는 폴더에 설치하고, Assembly1도 이 폴더에 설치한다.

4. 며칠이 지난 후에 Assembly1이 수정이 되었다고 가정한다.

5. 수정된 Assembly1을 이용한 클라이언트 어플리케이션(Client2)를 제작한다.

6. 이 클라이언트 프로그램을 c:\MyApp2라는 폴더에 설치하고 Assembly1도 이 폴더에 설치한다.

7. 각각의 프로그램은 같은 이름의 Assembly1이라는 어셈블리를 사용하고 있지만, 버전은 서로 다른 것이며, 아무 문제없이 충돌없이 동작된다.

 

여기까지는 Private Assembly의 예를 든것이다. 이처럼 어셈블리는 각각의 폴더에 설치되어 있기 때문에 직접 변경이 되지 않는 한 버전변경에 영향을 받지 않는다고 할 수 있다. 그럼 이번에는 Shared 어셈블리에 대해 알아보겠다. 이 경우에서는 버전이 매우 중요하다. 버전번호는 다음과 같은 형태로 생성된다.

major.mino,build.revision

만약 어셈블리에 변경을 가했을 경우, major, minor버전이 같다면 변경된 어셈블리는 기존 것과 호환된다고 할 수 있다. 만약 클라이언트 프로그램에서 어셈블리의 사용을 요청하게 되면, major,minor버전이 맞는 것중에서 가장 최근의 build와 revision을 갖는 어셈블리가 제공된다.

 

Shared Aassembly 만드는 

1. DLL/EXE를 제작할 소스코드를 준비한다.

2. SN 유틸리티를 이용하여 유니크(unique)한 어셈블리명을 생성한다.

3. AssemblyInfo 파일을 수정하여 private key를 서명한다.

4. DLL/EXE를 컴파일한다.

5. 생성된 DLL/EXE를 GACUTIL 유틸리티를 이용하여 global assembly cache에 위치시킨다.

이렇게만 하면, shared 어셈블리가 작성이 된다. 그러면 한가지씩 자세하게 알아보도록 하자.

 

Unique Assembly Name 생성법

마이크로 소프트에서는 어셈블리의 유일성을 보장하기 위해서 public-private key(공개키/개인키)기반의 로직을 이용한다. 이 공개키/개인키의 짝(pair)은 SN.EXE 라는 유틸리티를 이용해서 생성한다.(SN은 shared name의 의미를 갖고있다) 여러가지 다양한 옵션이 있지만, 일반적인 syntax는 다음과 같다.

sn -k 생성될 파일명

k는 키(key)를 생성하겠다는 의미이며, 이를 실행하면 파일이 하나 생성된다.

 

전자서명

어셈블리를 shared cache에 위치시키기 위해서는, sn유틸리티를 이용해서 만든 키를 이용하여 서명을 해야한다. 이 때 서명에 관련한 정보들을 담는 특별한 파일이 AssemblyInfo파일이다. AssemblyInfo 파일에 다음을 추가한다.

<Assembly: Assemblykeyfile("파일명")>

 

Global Assembly Cache에 등록하기

GACUTIL /i my_dll.dll

이렇다고 하네요. 아주 깔끔하게 정리가 잘 되어있네요. ㅎㅎ
(원본은 개발자가 알아두면 좋은 ASP.NET 지식 (어셈블리) 405 0 minotech@join )

자 그러면 어셈블리의 메니페스트에 저장되는 정보에는 어떤것이 있는지 보죠..

Assembly name : 어셈블리의 이름을 나타냅니다.

Versioning information :  이녀석은 4개의 부분으로 되어있고, 버전넘버가 저장되어 있습니다. 개정및 빌드넘버/ major 버전넘버와 minor 버전넘버도 포함되어 있어요

An (optional) shared name and signed assembly hash : 여긴 어셈블리 배포정보가 있어요.

Files : 어셈블리에 있는 모든 파일의 목록이 있습니다.

Referenced assemblies : 메니페스트의 어셈블리에서 직접 참조하는 모든 외부 어셈블리 목록이 있습니다.

Types : 타입이 저장되어있는 모듈과 매핑된 어셈블리의 모든 타입에 대한 목록이 포함되 있습니다. 
         
Security permissions : 어셈블리에서 명시적으로 거부된 보안사용권한(permission)의 목록입니다

Custom attributes : 타입에 따라 사용자정의(custom) 어트리뷰트는 리플렉션시 빠르게 접근하기 위해서 어셈블리의 메니페스트에 저장됩니다.

Product information Company, Trademark, Product, Copyright 값도 저장되어 있습니다




짧은 지식으로 지금 일을 하고 있지만
역시나 알아야 할것(인지는 모르겠지만ㅎㅎ)이 참 많네요.
부지런해야 겠습니다.

by 피요히코~ 2009. 4. 24. 00:34
아주 간단한 소스코드를 빌드를 하고
IL DASM로 불러들였습니다.

namespace insideCSharp
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("OTZ");
        }
    }
}


정말 간단한 소스네요....

이걸 IL DASM으로 불러들이면


이렇게 보입니다.
여기서 두번째 줄에 있는 MANIFEST를 더블클릭하면 어셈블리 정보를 설명하는
메타데이터 정보를 볼수가 있어요

// Metadata version: v2.0.50727
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 2:0:0:0
}
.assembly insideCSharp
{
  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                              00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 0C 42 6C 61 63 6B 45 64 69 74 69 6F 6E 00   // ...BlackEdition.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0C 69 6E 73 69 64 65 43 53 68 61 72 70 00   // ...insideCSharp.
                                                                                                00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 1E 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright ..
                                                                                                  42 6C 61 63 6B 45 64 69 74 69 6F 6E 20 32 30 30   // BlackEdition 200
                                                                                                  39 00 00 )                                        // 9..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 64 63 37 31 35 34 62 61 2D 30 30 65 34   // ..$dc7154ba-00e4
                                                                                                  2D 34 33 62 31 2D 61 30 30 61 2D 34 36 62 32 61   // -43b1-a00a-46b2a
                                                                                                  35 62 37 64 32 33 36 00 00 )                      // 5b7d236..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..

  // --- 다음 사용자 지정 특성이 자동으로 추가됩니다. 주석 처리를 제거하지 마십시오. -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )

  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module insideCSharp.exe
// MVID: {8A57E23A-CCB3-4592-9075-A79E5D701B7F}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x03F60000

참 기네요..
이걸 처음봤을때는(지금도 물론) 눈앞이 캄캄하네요....
가뜩이나 가로로 쭉쭉 늘어선 글을 붙여넣으니 당췌 뭐가뭔지 모르겠네요...

여기서 첫번째 블럭은 외부어셈블리를 참조하는데 사용되는 .assembly 레코드입니다.

어셈블리의 가장 큰 장점중 하나는 버전관리가 가능하다는 것... 이라고 하는데요. 아직 저에게는 그다지 와닿지 않는 내용입니다. --ㅋ
제가 컴파일한 insideCSharp  어셈블리는 mscorlib 어셈블리의 2.0.0.0 버전을 사용하고 있다네요.

두번째 블럭은 이 어셈블리에 대한 정보를 포함하고 있습니다.
책에서 본 바로는 명시적으로 빌드 프로세스중에 버전 넘버를 지정하지 않으면 0.0.0.0 이라고 하는데
왜 저는 1.0.0.0 인걸까요.........

책이 version 2003이니.. 바뀐걸수도 있겠고. 제가 모르는 무언가가 있는지도 모르겠네요... ㅠ
위에 노란블럭안을 보면 몇가지 어트리뷰트가 나와 있는데요.
위의 어트리뷰트에 대한 내용들은 공부가 더 진행된후에 다시 언급하도록 할께요.
(그나저나 책에서는 Debug쪽 어트리뷰트만 나오더니. 제꺼에서는 상당히 많은 어트리뷰트가 보이는군요....
 책과 다르면 매우 난감한데요....)

다음으로는 클래스의 생성자를 볼께요. (6번째줄의 .ctor : void() 를 더블클릭하면 나와요)

.method public hidebysig specialname rtspecialname
        instance void  .ctor() cil managed
{
  // 코드 크기       7 (0x7)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ret
} // end of method Program::.ctor

첫째줄에서 두번째줄까지는 단순히 메소드가 public이고, specialname, rtspecialname 어트리뷰트의 특징을 나타냅니다.
이러한 특정 메서드에 대한 코드는 CLI(Common Language Infrastructure)에 대한 의미를 가지고 있다고 하네요.
cil managed 어트리뷰트는 managed 메서드라는 걸 의미합니다.

메소드는 처음으로 Idarg라는 opcode를 통해 인자를 스택으로 로드합니다.
Idarg 다음의 '0'은 첫번째 인수를 뜻합니다.
두번째 call 이라는 opcode는 System.Object를 호출하는데 사용됩니다.
마지막 ret opcode는 단순히 호출메소드로 컨트롤을 반환한다고 하네요.
(코드는 쉬운데. 이놈은 어렵네요....)

이번에는 Main 메소드가 어떻게 생겼는지 볼죠..

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // 코드 크기       13 (0xd)
  .maxstack  8
  IL_0000:  nop
  IL_0001:  ldstr      "OTZ"
  IL_0006:  call       void [mscorlib]System.Console::WriteLine(string)
  IL_000b:  nop
  IL_000c:  ret
} // end of method Program::Main
위에서 한번 보고 나니.
조금 눈에 들어오네요

하지만 책과 또 다른!!!!
IL_0000과 000b의 nop은 뭐하는 녀석일까요...

나머지 녀석들은 위랑 비슷한데 말이죠..
Idstr은 문자열 OTZ를 스택에올려주고.
call을 사용해서 System.Console::WriteLine을 불러냅니다.

문자로된 문자열을 넘겨도. 이 값은 실제로는 System.String 클래스의 인스턴스입니다.(문자니깐요)



IL DASM으로 내부정보를 보면
개발자가 알아야할 지식을 갖추는데도 도움이 되고
개발 생산성도 높일수 있을것이라고 하니(책에서... 실제로는 어떨지 아직 모르겠군요.. 도움이 되긴 하겠죠..)
앞으로 이 녀석과 친해질수 있도록 많이 노력해야 겠네요..
by 피요히코~ 2009. 4. 24. 00:17
책을보고 공부를 하던중
ILDASM을 직접 실행해보고 싶어서 따라해봤지만.
도저히 찾을수가 없더라구요.

PATH를 등록해도. 계속 없다고 나오길래
해당폴더에 갔더니. 파일이 없더라구요.

그래서 다운을 받아보려고 했지만.
350MB정도인데. 다운로드시간이 40분....

ILDASM을 해보려고 삽질한지 한시간이 훌쩍 넘어서 시간은 1시가 넘어고.
'에잇! 안해!!' 하고 책을 덥고

혹시나 하는 마음에
시작 - 프로그램 을 뒤지는데.


IL 디스어셈블러....

책이. version 2003임을 감안해서 찾아봤어야 하는건데...
OTZ

실행해서 해보니. 잘 되더군요.(당연하겠지.....)


두둥.... ㅠㅠ
by 피요히코~ 2009. 4. 23. 23:43
일단
.NET의 가장 중요한 두가지 특징에 대해 살펴보면
1. 모든 .NET언어가 동일한 .NET 기능에 엑세스 한다는것
2. 다양한 언어로 작성된 코드가 밀접하게 상호 운용된다는 점


이런 기능을 지원하는 일등공신은 MSIL인데, .NET 컴파일러는 소스코드등을 통해 Windows PE가 아닌 MSIL을 생성한다

MSIL의 등장으로 .NET 응용프로그램은 표준적이고 공통적인 포맷으로 컴파일되므로
일관성있게 .NET 런타임 환경에서 운용된다.

.NET 응용프로그램을 컴파일하고 실행할때 어떤일이 발생할까?

1. .NET 언어를 사용해 소스코드를 작성
2. 소스코드는 컴파일되 EXE파일로 작성
3. .NET 컴파일러는 MSIL 코드와 메니페스트를 생성하고 이 정보를 EXE의 한부분으로 포함시킨다.
    .NET 컴파일러가 생성하는 EXE는 기타 EXE와 마찬가지로 표준 PE헤더를 포함하고 있다.
    (메니페스트는 .NET 바이너리의 내용과 런타임 요구사항에 대한 정보를 포함하고 있다.
     메니페스트는 .NET 바이너리 파일에 저장되는 정보를 언급한다. )
4. (가장중요한단계) 컴파일러가 산출물을 생성할 때 .NET 런타임에서 _CorExemail이라는 이름의 함수를 임포트 한다.
5. 사용자가 응용프로그램을 실행하면 운영체제는 PE파일과 관련된 DLL 파일들을 로드한다.
    이 DLL 중에는 _CorExeMail 함수가 정의되어 있는 mscoree.dll 파일들이 포함된다.
    이 파일은 모든 .NET PE 파일이 실행될때 로드된다.
6. 운영체제 로더는 PE내 진입점(entry point)으로 점프한다.(휘릭~) 모든 PE는 Windows에서 이런 프로세스에
   따라 진행된다.
7. 운영체제에서 MSIL 코드를 실행할 수 없기 때문에 진입점은 mscoree.dll의 _CorExeMail으로 점프하는
   루틴에 불과하다.
8. _CorExeMail 함수는 컴파일러에서 PE에 놓아 둔 MSIL코드를 실행한다.
9. MSIL코드는 직접 실행될수 없다.(실행가능한 형식이 아니므로. )
    따라서 CLR에서 JIT 컴파일러를 사용해 MSIL을 CPU전용 명령어로 컴파일한다.
    JIT 컴파일러에서 컴파일할 때 프로그램의 메서드로만 호출되며, 컴파일된 실해오드는 시스템에 임시로
    저장되고 소스코드가 별경될때만 재컴파일 된다.

출처 : INSIDE C#
by 피요히코~ 2009. 4. 22. 23:54
by 피요히코~ 2009. 4. 21. 18:49
protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
ArrayList arrColumn = new ArrayList();
DataSet ds = null;
ds = getDBData
arrColumn.Add(CreateBoundColumn("code_title", "구분"));
arrColumn.Add(CreateBoundColumn("dlscnt", "제정"));
arrColumn.Add(CreateBoundColumn("dlrcnt", "개정"));
arrColumn.Add(CreateBoundColumn("dltotcnt", "Total"));
arrColumn.Add(CreateBoundColumn("lscnt", "제정"));
arrColumn.Add(CreateBoundColumn("lrcnt", "개정"));
arrColumn.Add(CreateBoundColumn("ltotcnt", "Total"));
arrColumn.Add(CreateBoundColumn("scnt", "제정"));
arrColumn.Add(CreateBoundColumn("rcnt", "개정"));
arrColumn.Add(CreateBoundColumn("totcnt", "Total
string fileName = "order" + DateTime.Now.ToString("yyyyMMdd") + ".xls";
SaveAsExcel(ds, arrColumn, "", fileName); } private void SaveAsExcel(DataSet dsResult, ArrayList columns, string subject, string fileName) { if (fileName.Equals(null) && fileName.Equals("")) fileName = DateTime.Now.ToString("yyyyMMdd") + ".xls"; System.Web.HttpContext.Current.Response.Buffer = true; DataGrid dgExcel = new DataGrid(); dgExcel.ShowHeader = true; dgExcel.Caption = subject; dgExcel.AutoGenerateColumns = false; foreach (object column in columns) dgExcel.Columns.Add((BoundColumn)column); dgExcel.HeaderStyle.BackColor = Color.FromName("powderblue"); dgExcel.HeaderStyle.HorizontalAlign = HorizontalAlign.Center; dgExcel.HeaderStyle.Height = 25; dgExcel.HeaderStyle.Font.Bold = true; dgExcel.DataSource = dsResult; dgExcel.DataBind(); System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8)); System.Web.HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("euc-kr"); System.Web.HttpContext.Current.Response.AppendHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8) + ";charset=euc-kr"); System.Web.HttpContext.Current.Response.ContentType = "application/unknown"; ////////////////////////////////////////////////////////// /// 한글이 깨지는 경우 web.config의 globalization을 euc-kr로 바꿔주세요. ////////////////////////////////////////////////////// System.Web.HttpContext.Current.Response.Write(""); dgExcel.EnableViewState = false; System.IO.StringWriter sWriter = new System.IO.StringWriter(); System.Web.UI.HtmlTextWriter htmlWriter = new System.Web.UI.HtmlTextWriter(sWriter); dgExcel.RenderControl(htmlWriter); System.Web.HttpContext.Current.Response.Write(sWriter.ToString()); System.Web.HttpContext.Current.Response.End(); dgExcel.Dispose(); } public BoundColumn CreateBoundColumn(string DataFieldValue, string HeaderTextValue) { // Create a BoundColumn. BoundColumn column = new BoundColumn(); // Set the properties of the BoundColumn. column.DataField = DataFieldValue; column.HeaderText = HeaderTextValue; return column; } public BoundColumn CreateBoundColumn(string DataFieldValue, string HeaderTextValue, string FormatValue, HorizontalAlign AlignValue) { // Create a BoundColumn using the overloaded CreateBoundColumn method. BoundColumn column = CreateBoundColumn(DataFieldValue, HeaderTextValue); // Set the properties of the BoundColumn. column.DataFormatString = FormatValue; column.ItemStyle.HorizontalAlign = AlignValue; return column; }
by 피요히코~ 2009. 4. 17. 14:40
function Button1_onclick() {
    window.open('../../Common/pop_person.aspx', '인원선택', 'toolbar=no,scrollbars=no,width=850px,height=595px');
}

function Callback(value){
   for(var i = 0 ; i < value.length ; i++)
   {
        alert(value[i].DEPT_NAME);
        alert(value[i].EMP_NAME);
        alert(value[i].POS_NAME);
   }
}

부모창에서는 이렇게 해서 자식창을 뜨게 해줍니다.
Callback함수는 자식창에서 호출해줄 함수에요

그 다음에는 자식창입니다.

일단 JSON등등을 사용하기 위해서



이녀석들을 추가해 줍니다.
(경로를 잘 맞춰줘야 겠죠? )

그 다음에는 실제로 DB에서 Data를 가져올 페이지를 만들어줍니다.
이름은 retrieveUserList.aspx 고
이녀석은 aspx쪽에는 아무것도 없어요.(실제로 사용자쪽에선 보이지도 않는 페이지구요)
cs쪽에서는
넘겨받은 QueryString을 이용해서 DB에 접속해서 dataset을 넘겨받고


string jsonStr = ""; jsonStr = this.parsingDataSet(ds); Response.Write(jsonStr);



private string parsingDataSet(DataSet ds) { int rowCount = ds.Tables[0].Rows.Count; string jsonStr = "{"; jsonStr = jsonStr + "'rowCount':'" + rowCount + "',data:["; for (int i = 0; i < rowCount; i++) { jsonStr = jsonStr + "{'EMP_ID':'" + ds.Tables[0].Rows[i]["EMP_ID"].ToString() + "'"; jsonStr = jsonStr + ",'EMP_NAME':'" + ds.Tables[0].Rows[i]["EMP_NAME"].ToString() + "'"; jsonStr = jsonStr + ",'DEPT_NAME':'" + ds.Tables[0].Rows[i]["DEPT_NAME"].ToString() + "'"; jsonStr = jsonStr + ",'POS_NAME':'" + ds.Tables[0].Rows[i]["POS_NAME"].ToString() + "'"; jsonStr = jsonStr + ",'DEPT_ID':'" + ds.Tables[0].Rows[i]["DEPT_ID"].ToString() + "'"; jsonStr = jsonStr + ",'OFFICE_PHONE':'" + ds.Tables[0].Rows[i]["OFFICE_PHONE"].ToString() + "'"; jsonStr = jsonStr + "},"; } jsonStr = jsonStr.Remove(jsonStr.Length - 1, 1); jsonStr += "]}"; return jsonStr; }

이런식으로 처리해서 리턴해 줍니다.
JSON으로 바꿔주는 형식
은 http://www.json.org/ << 여기에 나온데로 처리를 한거구요.


이제 pop_person쪽에서 처리하는걸 보여드리면요

retrieveUserList = function(value) { var url = "./retrieveUserList.aspx?dept_code="+value; var ajaxObj = new Ajax.Request(url, { method:'post', onComplete:showJsonData } ); }


이렇게 해서 retrieveUserList.aspx페이지를 호출해서 data를 가져오구
요 onComplete에서 showJasonData 함수를 호출해 줘요
var rowCount
var jsonStrObj
var array1 = new Array();

//여기까지는 그냥 필요한 변수들
showJsonData = function(originalData) {
jsonStrObj = originalData.responseText;
jsonStrObj = jsonStrObj.evalJSON();
rowCount = jsonStrObj.rowCount;
var results = "";
for(var i=0; i<ROWCOUNT; id='"+jsonStrObj.data[i].EMP_ID+"' ?<div + results="results" { i++)>";
results = results + "<TABLE id=cgv style="BORDER-RIGHT: white 1px solid; BORDER-TOP: white 1px solid; BORDER-LEFT: white 1px solid; WIDTH: 95%; BORDER-BOTTOM: white 1px solid; BORDER-COLLAPSE: collapse; HEIGHT:26px" rules=rows border=1 rowindex="0" ellspacing="0">";
results = results + "<TBODY><TR class=cgvRow><TD style="WIDTH: 10%" onclick='chkAW(1,"+i +");' align=middle>";
results = results + "<INPUT id='chk"+i+"' type=checkbox></TD>";
results = results + "<TD style="WIDTH: 20%" onclick='chkAW(1,"+i +");' align=middle>"; results = results + jsonStrObj.data[i].EMP_NAME+"</TD>";
results = results + "<TD style="WIDTH: 45%" onclick='chkAW(1,"+i +");' align=middle>"; results = results + jsonStrObj.data[i].DEPT_NAME+"</TD>";
results = results + "<TD style="WIDTH: 25%" onclick='chkAW(1,"+i +");' align=middle>"; results = results + jsonStrObj.data[i].POS_NAME+"</TD>";
results = results + "<TD style="DISPLAY: none; WIDTH: 0%" align=middle>"; results = results + jsonStrObj.data [i].DEPT_ID+"</TD>";
results = results + "<TD style="DISPLAY: none; WIDTH: 0%" align=middle>"; results = results + jsonStrObj.data [i].OFFICE_PHONE+"</TD></TR><DIV></DIV>";
} $('content1').innerHTML = results; }

이런식으로 JSON 형식으로 넘어온 데이터를 HTML모양에 넣고
미리 만들어둔 content1이라는 DIV에 innerHTML로 넣어주면
화면의 가운데에 테이블로 들어가집니다.

그럼 이제 남은 처리는
오른쪽 화살표를 클릭했을때 처리와
왼쪽 화살표 클릭했을때 처리인데요.

이부분의 처리는
사용자정의객체와
Array를 이용해서 처리했어요.

일단 사용자정의 객체를 정의합니다.

function Person(){
this.EMP_ID = "";
this.EMP_NAME = "";
this.DEPT_NAME = "";
this.POS_NAME = "";
this.DEPT_ID = "";
this.OFFICE_PHONE = "";
}

그 다음은 오른쪽 화살표 클릭시 처리함수

function imgRight_onclick() {            
try{
for(var i = 0; i < rowCount; i++)
{
var tempVal = "chk" + i;
var tempObj = eval(document.getElementById(tempVal)); 
               
if(tempObj.checked) {
var tempPersonObj = new Person();
tempPersonObj.EMP_ID = jsonStrObj.data[i].EMP_ID;
tempPersonObj.EMP_NAME = jsonStrObj.data[i].EMP_NAME;
tempPersonObj.DEPT_NAME = jsonStrObj.data[i].DEPT_NAME;
tempPersonObj.POS_NAME = jsonStrObj.data[i].POS_NAME;
tempPersonObj.DEPT_ID = jsonStrObj.data[i].DEPT_ID;
tempPersonObj.OFFICE_PHONE = jsonStrObj.data[i].OFFICE_PHONE;
array1.push(tempPersonObj);
}
}
inputData();
}catch(e){alert(e.message);}
return false;
}


checkbox 객체를 받아서 체크여부를 확인한뒤
체크가 되어 있을경우에
person객체에 담고
그 객체를 array1에 push합니다.

그 다음에 inputData를 호출해줍니다.(inputData가 하는일은 아까와 같이 HTML형식으로 DIV에 넣어주는거에요)

그리고 왼쪽화살표 클릭시 array에서 빼버리는건

function imgLeft_onclick() {

    for(var i = array1.length-1; i > -1; i--)
    {                
    
    var tempVal = "chk" + i+"_2";
    var tempObj = eval(document.getElementById(tempVal)); 
                
    if(tempObj.checked) {
        array1.splice(i,1);
    }
}
inputData();

}


체크된 녀석들(없앨 녀석들)을 찾아서
arra1에서 splice해주고 다시 inputData로 뿌려줍니다.

위쪽 화살표 클릭시 순서를 바꿔주는건

일단

function ckbCount(value)
{
try{
var check = 0;
var chkValue = 0;
for(var i = 0; i < array1.length; i++)
{
var tempVal = "chk" + i+"_2";
var tempObj = eval(document.getElementById(tempVal));
if(tempObj.checked) {
check = check+1;
chkValue = i;
}
}
           
if(check > 1)
{
alert("한번에 한명씩 옮길수 있습니다.");
return false;
}
else if(check == 0)
{
alert("선택된 사람이 없습니다.");
return false;
}
else
{
if(value == 1) imgUp_onclick(chkValue);
else imgDown_onclick(chkValue);
}
}catch(e){alert(e.message);}  
return false;
}

이녀석을 이용해 유효성여부를 판단하고 위나 아래로 옮겨줍니다.
(인자로 받는 value는 1일경우는 위로/ 2일경우는 아래로 옮기는걸 구분하기 위한 인자입니다)

이건 위로 옮겨주는 함수
function imgUp_onclick(chkValue) {
if(chkValue == 0)alert("더이상 위로 이동할수 없습니다.");
else
{
var arrayTemp = new Array();
tempPerson = new Person();
tempPerson2 = new Person();
arrayTemp = array1.slice(chkValue, chkValue+1);
tempPerson = arrayTemp[0];
arrayTemp = array1.slice(chkValue-1, chkValue);
tempPerson2 = arrayTemp[0];
array1.splice(chkValue-1, 2, tempPerson, tempPerson2);
inputData();
checkBox(chkValue-1);
}
}


이건 아래로
function imgDown_onclick(chkValue) {
if(chkValue == (array1.length-1))alert("더이상 아래로 이동할수 없습니다.");
else
{
var arrayTemp = new Array();
tempPerson = new Person();
tempPerson2 = new Person();
arrayTemp = array1.slice(chkValue, chkValue+1);
tempPerson = arrayTemp[0];
arrayTemp = array1.slice(chkValue+1, chkValue+2);
tempPerson2 = arrayTemp[0];
array1.splice(chkValue, 2, tempPerson2, tempPerson);
inputData();
checkBox(chkValue+1);
}
}
by 피요히코~ 2009. 4. 8. 13:38

위 화면은 팝업으로 열리는 화면인데요.
팝업이 되면 왼쪽에 트리형식으로 회사의 모든 부서가 보여집니다.
거기서 부서를 클릭하면 가운데 화면에. 그 부서 사람들 목록이 보여지고
그 목록에서 선택후 오른쪽 화살표모양을 클릭하면 오른쪽 끝화면으로 선택된 목록이 이동되는 화면이에요.
가운데 목록은 부서를 선택할때 마다 그 부서 사람들만 보여지고
오른쪽끝 화면은 가운데 화면에서 추가한 사람들 목록이 계속 쌓이게 되죠.
오른쪽끝 화면에서 선택후 왼쪽 화살표를 클릭하면 목록에서 지워지구요
OK버튼을 클릭하면 그 사람들 목록을 부모창에 던저줍니다.

그리고 위아래 화살표를 누르면 오른쪽끝 화면에서 사람들의 순서를 바꿔줍니다.

처음에 이 작업들을 다 서버쪽에서 처리를 하고 다시 보여주는 형식으로 했었는데.
속도가 너무 안나오더라구요
(살짝 살짝 딜레이가 느껴지는게.. ㅠㅠ)

그래서 찾은(과장님이 가르쳐준) 방법이 JSON을 이용해서 데이터를 처리하는 방법인데요.
이 방법을 사용하면 처음에 부서를 선택했을때만 한번 DB에서 데이터를 가져온후에
나머지 처리는 다 스크립트에서 처리해 줍니다.
확실히 속도는 빨라지더라구요.

방법은 어렵지 않아요.
부모창을 P, 자식창(위의 화면)을 C, 파일처리를 위한 창을 F라고 하면

P에서 C를 팝업시킨 후에
C에서 부서를 클릭하면 F페이지를 호출해서 DB접속후 결과 DataSet을 JSON형식으로 C에 돌려주면
그걸 가지고 C에서 처리를 해주는 겁니다.

자세한건 다음글에서~
by 피요히코~ 2009. 4. 8. 13:35
GridView에서 특정 컬럼에 있는 값들을 인자로 해서 특정 스크립트를 호출해줄때.

RowDataBound이벤트에서
(e.Row.RowType == DataControlRowType.DataRow) 일때

e.Row.Attributes.Add("OnClick", "popView(this)");
e.Row.Attributes.Add("arg1", e.Row.Cells[1].Text);
e.Row.Attributes.Add("arg2", e.Row.Cells[8].Text);
e.Row.Attributes.Add("arg3", e.Row.Cells[9].Text);
e.Row.Attributes.Add("OnClick", "popView(this)");

이렇게 해주고.
(arg1에는 두번째컬럼의 Text값이, arg2에는 아홉번째 컬럼의 Text값이, arg3에는 열번째 컬럼의 Text값이 들어갑니다)
aspx쪽에서 스크립트에서
function popView(arg)
{
     var value1 = arg.arg1;
     var value2 = arg.arg2;
     var value3 = arg.arg3;
}

이렇게 사용하면 됩니다.

Repeater에서는 같은 방법을 사용할수 없어서(못해서.ㅠㅠ)

aspx페이지에서 직접
<ItemTemplate>
<tr style="height: 25px;" onclick="popView('<%# Eval("FILE_CODE")%>' )">
<td ....
</tr>
</ItemTemplate>

이런식으로 넣어줬습니다. 위에서 처럼 배열(?)처럼 넣지는 못했구요.
그냥 repeater의 datasource에서의 특정 컬럼값을 넣어줬지요...
(물론 이렇게 밖에 하는걸 못찾아서... ㅠㅠ)

요즘은 Gridview는 잘 안쓴다고 하던데..

전 아직도 이렇게 쓰네요. 으헝헝


by 피요히코~ 2009. 4. 7. 16:03

function getParameter(qs) {
          var value = '';
          var address = unescape(location.href);
          var param= (address.slice(address .indexOf('?') + 1, address .length)).split('&');

          for (var i = 0; i < param.length; i++) {
              var name = param[i].split('=')[0];

              if (name.toUpperCase() == qs.toUpperCase()) {
                  value = param[i].split('=')[1];
                  break;
              }
          }
          return value ;
}

빨간 부분이 핵심~

by 피요히코~ 2009. 4. 6. 16:42