'2016/08'에 해당되는 글 5건

Programming/.NET

WCF는 분산 응용프로그램을 만드는 하나의 수단으로써 사용될 수 있습니다. 분산 응용프로그램이라는 용어자체에 신경쓸 필요는 없습니다.

 

간단히 말해 A프로그램에서 B라는 프로그램으로 데이터를 던지면 B라는 프로그램은 받은 데이터로 특정 처리를 수행하고 그 결과를 다시 A에 반환합니다. 그러면 A프로그램은 B가 던져준 결과를 받아 사용자에게 표시합니다. 이런식으로 동작하는 구조가 분산응용프로그램의 개념이 될 수 있습니다.

 

ASP.NET에서도 WCF 웹서비스를 만들고 다른 프로그램에서 이를 활용할 수 있는데, 그 과정을 간단히 살펴볼까 합니다.

 

프로젝트에서 Add -> New Item 을 선택해 WCF Service를 선택합니다.

 

 

프로젝트에는 해당 이름으로 만들어진 cs파일이 하나 생성될 것입니다. 이 파일을 열어보면 아마도 다음과 같거나 비슷할 것입니다.

 

// NOTE: You can use the "Rename" command on the "Refactor" menu to change the interface name

"IService" in both code and config file together.
[ServiceContract]
public interface IService
{
    [OperationContract]
    void DoWork();
}

 

우선 제일 먼저 인터페이스를 구성해야 합니다. 인터페이스는 외부에서 WCF서비스에 접근할때 호출할 수 있는 메소드를 구성하는 곳입니다.

 

public interface IService
{
    [OperationContract]
    int plus(int i, int j);
}

 

기존 DoWork 인터페이스를 무시하고 새로운 plus라는 인터페이스를 생성하였습니다. 또한 위와 같이 외부에 노출하고자 하는 인터페이스는 반드시 OperationContract 특성을 포함해야 합니다.

 

위에서 처럼 인터페이스를 만들고 나면 실제 이 인터페이스의 동작을 구현할 클래스를 다음과 같이 생성해야 합니다.

 

public class plusService : IService
{
    public int plus(int i, int j)
    {
        return i + j;
    }
}

 

이 클래스는 WCF 서비스파일인 svc파일에 구현되어야 하며 이전에 만들어진 인터페이스를 상속받아 야 합니다. 예제에서는 두개의 인자값을 받아 이들 값을 더하여 반환하도록 하였습니다.

 

이것으로 WCF서비스가 완성되었습니다. 해당 서비스가 제대로 동작하는지 확인하려면 웹브라우저에서 프로젝트의 서비스명.svc 파일에 대한 URL을 입력해 해당 서비스페이지를 호출해 보면 됩니다.

 

 

만약 위와 같은 화면이 나오지 않고 404관련 오류가 난다면 서버에서 WCF에 관한 필수항목이 설치되어 있는지 확인해 보시기 바랍니다.(HTTP Activation, TCP Port Sharing)

 

 

이제 해당 서비스의 plus메소드를 호출하여 실제 데이터처리를 수행해 보겠습니다.

 

우선 간단한 응용프로그램 프로젝트를 신규로 생성해 위에서 만든 WCF서비스를 참조해야 합니다. 이를 위해 프로젝트에서 마우스오른쪽을 클릭해 Add -> Service Refernce 항목을 클릭하십시오.

 

 

Add Service Reference 대화상자에서 위에서 만든 WCF서비스의 URL을 입력하고 Go 버튼을 눌러 서비스내역을 확인한 뒤 OK버튼을 눌러줍니다.

 

이로써 서비스참조가 완료되었습니다. 이제 참조한 서비스의 개체를 통해 두 숫자의 합을 구해보도록 하겠습니다.

 

ServiceReference.ServiceClient sc = new ServiceReference.ServiceClient();
int sum = sc.plus(100, 200);

 

XML웹서비스와 매우 비슷한 과정을 통해 WCF서비스를 사용할 수 있음을 알 수 있습니다.

 

만약 위에서 처럼 int나 string형식의 단순타입이 아닌 커스텀화된 복잡한 데이터타입을 전달해야 하는 경우 서비스를 계약(Contract)화 할 수 있습니다.

 

[DataContract]
public class Wellcome
{
    [DataMember]
    public string name;

    [DataMember]
    public string place;
}

 

필요한 데이터형은 [DataContract] 특성을 붙여서 작성하고 내부 클래스에 노출되어야할 필드에는 [DataMember]특성을 붙여야 합니다.

 

[ServiceContract]
public interface IService
{
    [OperationContract]
    string hi(Wellcome w);
}

 

인터페이스에는 위와같이 데이터용으로 전달될 Wellcome형식을 지정하고 반환형식도 적절하게 수정하도록 합니다.

 

public class Service : IService
{
    public string hi(Wellcome w)
    {

        return w.name + "님 " + w.place + "에 오신걸 환영합니다.";
    }
}

 

svc역시 수정된 인터페이스에 맞에 처리로직을 변경해줘야 합니다.

 

ServiceReference.Wellcome w = new ServiceReference.Wellcome();
w.name = "홍길동";
w.place = "서울";

ServiceReference.ServiceClient sc = new ServiceReference.ServiceClient();
string message = sc.hi(w);

 

서비스를 호출하는 클라이언트에서는 서비스에서 정의한 Wellcome형식의 개체를 생성해 필요한 값을 정의하고 해당 개체를 인자로 전달하여 WCF서비스를 호출하면 됩니다.

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] TreeView  (0) 2016.09.13
[ASP.NET] WCF - 2  (0) 2016.09.07
[ASP.NET] WCF - 1  (0) 2016.08.31
[C#] Stream  (0) 2016.08.24
[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
WCF
0 0
Programming/.NET

Stream은 추상클래스로서 프로그램에서 필요로하는 데이터의 입출력이 발생하면 그에 맞는 파생 클래스를 사용하여 데이터의 입출력을 처리할 수 있습니다. 아래는 Stream에서 파생되어 자주사용되는 클래스의 목록입니다.

 

 System.IO.FileStream

 파일관련 입출력에 사용됩니다.

 System.IO.MemoryStream

 스트림의 저장소를 메모리로하는 입출력에 사용됩니다.

 System.IO.UnmanagedMemoryStream

 MemoryStream와 같으나 비관리 메모리 접근을 지원합니다.

 System.IO.BufferedStream

 다른 데이터 입출력에서 버퍼처리를 추가하는데 사용됩니다.

 System.Net.Sockets.NetworkStream

 소켓통신을 통한 데이터 처리에 사용됩니다.

 System.Security.Cryptography.CryptoStream

 데이터를 암호화하여 입출력 처리하는데 사용됩니다.

 System.IO.Compression.GZipStream

 GZip형식의 데이터 압축을 지원합니다.

 System.IO.Compression.DeflateStream

 Deflate 알고리즘을 통한 데이터 압축을 지원합니다.

 System.Net.Security.NegotiateStream

 협정 보안프로토콜을 통한 클라이언트 인증과 서버의 선택적 인증을 지원합니다.

 System.Net.Security.SslStream

 SSL (Secure Socket Layer) 통신을 통한 서버의 인증과 선택적 클라이언트 인증을 지원합니다.

 

위 표에서 보듯 파일을 다루기 위한 기본 클래스는 System.IO.FileStream 클래스입니다. 이 클래스를 토대로 간단한 텍스트파일을 읽으려면 다음과 같이 예제를 작성할 수 있습니다.

 

System.IO.FileStream fs = new System.IO.FileStream(@"C:\test.txt", System.IO.FileMode.Open);

byte[] b = new byte[fs.Length];

fs.Read(b, 0, (int)fs.Length);
fs.Close();

string s = ASCIIEncoding.Default.GetString(b);

 

우선 스트림 데이터를 담기위한 바이트 배열이 필요한데 이때 바이트배열은 스트림의 length속성을 통해 스크림의 길이만큼 확보하도록 하고 이 배열을 Read메소드에 전달하여 읽어들인 데이터를 해당 배열에 저장하도록 합니다.

 

FileStream에서는 첫번째 매개변수로 파일명과 파일의 위치를 전달하고 두번째 매개변수로 FileMode의 Open 열거형 값을 전달해 파일열기를 지시합니다.

 

또한 스크림을 통해 데이터를 읽어오는데 성공하면 Close 메소드를 통해 해당 스트림을 명시적으로 닫아줘야 합니다. 아니면 다음과 같이 using문을 사용해도 동일한 결과를 얻을 수 있습니다.

 

using (System.IO.FileStream fs = new System.IO.FileStream(@"C:\test.txt", System.IO.FileMode.Open)) {
        byte[] b = new byte[fs.Length];
 
        fs.Read(b, 0, (int)fs.Length);
 
        string s = ASCIIEncoding.Default.GetString(b);
}

 

참고로 MSDN등의 문서상으로는 되도록 using문 사용을 권고하고 있습니다. using은 using문이 닫히는 시점에서 자동적으로 Dispose 메소드를 호출하는데 FileStream에서 Dispose 메소드가 호출되면 Close메소드로 같이 자동으로 호출됩니다.

 

using (System.IO.FileStream fs = new System.IO.FileStream(@"C:\test.txt", System.IO.FileMode.Append, System.IO.FileAccess.Write, System.IO.FileShare.Read, 

8, System.IO.FileOptions.None)) {
    byte[] b = System.Text.Encoding.ASCII.GetBytes("Hi");

    fs.Write(b, 0, b.Length);
    fs.Flush();
} 

 

위 예제는 기존 파일에 특정 내용을 추가하는 동작을 수행합니다. 우선 FileStream 클래스를 사용할때 매개변수부터 달라졌는데 FileMode와 더불어 FileAccess, FileShare, FileOptions 열거형이 추가되었습니다.

 

기존 FileMode는 파일의 생성및 추가, 열기등을 제어하고 FileAccess는 파일에 대한 읽기, 쓰기를 제어합니다. FileShare는 특정 파일을 다룰때 해당 파일에 접근하여 처리할 수 있는 작업을 제한하고 FileOpetions는 파일에 대한 임의, 순차접근, 암호화, 비동기쓰기등을 지원합니다.

 

결국 FileMode.Append는 파일에 대한 추가와 함께 FileAccess.Write로 쓰기작업을, 파일이 처리되는 동안 FileShare.Read로 읽기만을 허용하도록 하는 것입니다.

 

파일에 데이터를 쓰는 경우 특정 문자열에 대한 바이트 배열을 System.Text.Encoding.ASCII.GetBytes메소드로 가져와 바이트배열을 초기화 하고 Wirte 메소드로 해당 배열에 있는 데이터를 버퍼에 작성하도록 합니다. 그래서 Flush메소드로 버퍼링된 데이터를 원하는 파일에 실질적으로 기록될 수 있도록 해야 합니다.

 

다만 파일에 대한 FileStream클래스의 Close메소드를 명시적으로 호출하는 경우 Flush메소드는 자동적으로 호출됨으로 스트림에 대한 닫기와 Flush는 같이 수행할 필요가 없습니다.(예제에는 Flsuh호출이 있지만 이는 빠져도 무관합니다.)

 

참고로 MemoryStream은 FileStream과 목적하는 저장소만 다를 뿐 처리방식은 완전히 동일하므로 위 예제에서 FileStream을 MemoryStream으로 바꾸고 FileStream 클래스를 호출할때의 매개변수만 제거하면 메모리를 스트림으로 하는 동작이 완벽하게 구현됩니다.

 

Stream 클래스는 파일에 대한 작업과 함께 네트워크 통신을 위한 스트림 데이터 처리용으로도 많이 사용됩니다. 네트워크 통신을 위한 스트림 클래스는 System.Net.Sockets.NetworkStream 입니다.

 

우선 간단히 NetworkStream으로 TCP/IP를 통해 데이터를 받아오는 부분을 살펴보겠습니다.

 

int buffer = 1024;

byte[] read_byte = new byte[buffer];

System.Net.Sockets.TcpClient client = new System.Net.Sockets.TcpClient("cliel.com", 1212);
System.Net.Sockets.NetworkStream ns = client.GetStream();

int size = ns.Read(read_byte, 0, buffer);
string response = System.Text.Encoding.ASCII.GetString(read_byte, 0, size);

MessageBox.Show(response);

 

우선 받아올 만큼의 바이트배열을 생성하고 TcpClient 클래스로 서버쪽에의 데이터를 받아오도록 합니다. 예제에서는 cliel.com 으로 서버를 지정했지만 IP로도 가능하며 두번째 매개변수에 통신할 포트를 지정합니다.

 

원하는 서버로의 포트를 통해 데이터를 받아오면 TcpClient클래스의 GetStream메소드를 통해 데이터 스트림을 받아와 NetworkStream클래스의 Read메소드로 받아온 데이터를 바이트배열에 담고, 이 후 인코딩으로 바이트이 들어간 스트림값을 가져오면 됩니다.

 

받대로 데이터를 쓰는 경우는 Read메소드 대신 Write메소드를 호출합니다.

 

byte[] write_byte = ASCIIEncoding.Default.GetBytes("me" + Environment.NewLine);
ns.Write(write_byte, 0, write_byte.Length);

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] WCF - 2  (0) 2016.09.07
[ASP.NET] WCF - 1  (0) 2016.08.31
[C#] Stream  (0) 2016.08.24
[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
[ASP.NET] 서버 컨트롤 - 1 (기본생성)  (0) 2016.08.01
0 0
Programming/.NET

 1. 개인화 일반

 

일반적으로 웹사이트에서는 사용자의 이름이나 별명, 기타 정보를 관리하기 위해 쿠키나 세션을 많이 사용합니다. 그런데 쿠키는 클라이언트상에서 변경이 가능하므로 보안을 위해서는 쿠키를 암호화 해야 하며 세션은 서버에 저장되는 것으로 비교적 보안에 대한 부담은 적으나 서버의 리소스를 일정부분 점유한다는 측면에서 성능이슈에 관한 논의가 종종 나오곤 합니다.

 

ASP.NET에서는 기존의 쿠키나 세션과 같은 방법이 아닌 사용자 정보관리를 위한 개인화시스템을 제공합니다. 물론 쿠키, 세션등을 사용할 수 있지만 개인화를 사용하면 좀더 안정적이고 편리하게 사용자 정보를 관리할 수 있습니다.

 

우선 가장 기본적인 개인화를 구현해 보도록 하겠습니다. 예를 들어 사용자에 관한 이름, 전화번호, 주소정보를 관리할 필요가 있다면 web.config의 <system.web>하위에 다음과 같이 필요한 속성을 추가시켜 줍니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <add name="Name" allowAnonymous="true" />
    <add name="Phone" allowAnonymous="true" />
    <add name="Address" allowAnonymous="true" />
  </properties>
</profile>

 

위 예제에서는 필요한 각 속성을 정의한것 이외에 추가적으로 anonymousIdentification요소와 각 add요소의 allowAnonymous속성에 true로 된것을 확인할 수 있습니다. 이것은 익명사용자를 위한 속성접근을 허가한 것으로 만약 이 요소를 제외한다면 윈도우인증을 받은 사용자만이 속성에 접근할 수 있게 됩니다. 개인화는 윈도우인증이 아닌 경우 다른 인증(이를 테면 Form인증과 같은)이나 혹은 인증받지 않은 사용자는 모두 익명으로 간주합니다.

 

Profile 요소에는 automaticSaveEnabled 속성을 추가할 수도 있는데 이 속성은 기본값이 true로서 개인화 속성에 값을 대입하면 자동으로 해당 값을 저장합니다. 이 속성을 false로 설정하면 ProfileBase 객체의 Save 메소드를 직접호출해야 개인화 속성값이 저장됩니다.

 

위에서 추가한 속성에 접근이 가능한지를 테스트해보기 위해 aspx에 버튼하나를 배치하고 버튼의 클릭이벤트에 다음과 같이 코드를 작성합니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    HttpContext.Current.Profile["Name"] = "cliel";
    HttpContext.Current.Profile["Phone"] = "000-1234-5678";
    HttpContext.Current.Profile["Address"] = "대구 광역시";

    Response.Write(string.Format("당신의 이름은 {0}입니다.", HttpContext.Current.Profile["Name"]));
}

 

보시는 바와같이 개인화는 아주 간단히 구현될 수 있습니다. 참고로 개인화공급자를 따로 수정하지 않으면 데이터를 저장하는 기본은 내부 mdf (SQL Server Express)입니다.

 

웹 프로젝트를 웹사이트(Web Site)로 생성하면 Profile 사용법이 좀더 달라질 수 있습니다. Web.config에 위 예제처럼 개인화 속성을 추가하고 나면 다음과 같이 Profile객체를 바로 호출해 원하는 속성을 사용할 수 있습니다. 웹사이트 프로젝트에서는 Web.Config를 수정하면 자동 컴파일되기 때문에 가능한 일입니다.

 

protected void Page_Load(object sender, EventArgs e)
{
    Profile.Name = "홍길동";
}

 

 2. 익명사용자 처리

 

여기 잠깐 익명화를 얘기하자면 anonymousIdentification 요소가 enabled="true"로 설정되는 경우 ASP.NET에서는 비인증 사용자 즉, 익명사용자를 식별하기 위한 고유의 식별값을 사용하게 됩니다. 식별값은 사용자의 컴퓨터에 .ASPXANONYMOUS라는 이름으로 쿠키에 저장되며 ASP.NET에 요청이 발생하면 그때마다 해당 식별값을 전송합니다.

 

만약 익명사용자를 위한 쿠키값을 바꾸어야 한다면 다음과 같이 web.config를 설정할 수 있으며

 

<anonymousIdentification enabled="true" cookieName="anonymous" />

 

cookieTimeout 속성을 사용해 쿠키가 저장되는 시간을 설정할 수도 있습니다.

 

<anonymousIdentification enabled="true" cookieName="anonymous" cookieTimeout="1440" />

 

참고로 cookieTimeout 시간은 기본이 100,000분(70일)이며 1440분은 하루정도의 시간입니다. 하지만 이 설정은 사용자의 웹브라우저설정을 우선할 수 없습니다. 만약 사용자가 쿠키를 고의적으로 삭제하거나 웹브라우저의 설정이 수시로 쿠키를 삭제하도록 되어 있다면 cookieTimeout은 제 기능을 발휘할 수 없을 것입니다.

 

<anonymousIdentification enabled="true" cookieName="anonymous" cookieTimeout="1440" 

cookieless="UseUri" />

 

cookieless는 쿠키대신 사용자를 식별할 다른 방법을 제시하는 것입니다. 여기에 사용할 수 있는 값으로는 UseUri(URL을 식별자로 사용함), UseCookies(기본값:쿠키를 식별자로 사용함), AutoDetect(UseCookies와 UseUri를 자동설정/만약 사용자가 쿠키를 사용하지 않도록 되어 있다면 UseUri가 설정됨/판단을 위한 처리가 별도로 필요하므로 처리가 다소 느릴 수 있음), UseDeviceProfile(브라우저나 디바이스별로 필요한 식별자를 설정)등이 있습니다.

 

URL을 식별자로 한다면 좀 의아할 수도 있는데 실제 이렇게 설정해놓고 웹프로그램을 실행해 보면 임의의 URL을 생성해 관리함을 알 수 있습니다.

 

참고로 프로그램에서 익명사용자의 식별값을 판단하려면 Request의 AnonymousID속성을 사용합니다.

 

Request.AnonymousID

 

이 값은 GUID로 중복되지 않는 값인데 익명 사용자가 생성되면 자동으로 할당됩니다. 만일 이 생성값을 임의로 바꾸려 한다면 익명사용자가 생성될때의 이벤트를 가로채서 식별값을 설정하면 됩니다.

 

public void AnonymousIdentification_Creating(object sender, AnonymousIdentificationEventArgs args)
{
    args.AnonymousID = "익명사용자";
}.

 

웹프로그램에서 익명사용자에게 로그인과 같은 인증된 사용자로 전환할 수 있는 통로를 제공하면 익명사용자는 언제든 인증된 사용자로 바뀔 수 있습니다. 때문에 필요에 따라서는 익명 사용자의 개인화속성값을 그대로 가져와 인증된 상태에서의 해당 속성값을 갱신해야 하는 경우가 있습니다.

 

ASP.NET에서는 익명사용자가 인증된 사용자로 전환될때의 이벤트를 제공하며 해당 이벤트를 통해 개인화 속성값을 갱신하는 방법을 취할 수 있습니다.

 

public void Profile_MigrateAnonymous(object sender, ProfileMigrateEventArgs e)
{
    ProfileCommon pc = Profile.GetProfile(e.AnonymousID);
    Profile.Name = pc.Name;

    Response.Write(User.Identity.Name + "님의 이름은 " + Profile.Name + "입니다.");
}

 

익명사용자가 인증사용자로 전환되는 경우 Profile_MigrateAnonymous이벤트가 실행되며 이벤트 안에서 e.AnonymousID값을 통해 익명사용자의 개인속성값을 가져와 이 값을 현재인증사용자의 개인속성에 저장합니다.

 

참고로 위 이벤트는 Global.asax안에 정의되어 있어야 하며 ProfieCommon이나 Profile객체이용을 위해서는 웹 프로젝트가 웹사이트 프로젝트로 생성되어 있어야 합니다.

 

 3. 개인화 속성 그룹화

 

개인화를 사용하는 경우 사용자그룹별로 다른 데이터가 관리될 수 있습니다. 이런 경우를 대비해 개인화도 그룹별화하는 것이 가능합니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="SecurityCode" allowAnonymous="true" />
    </group>
  </properties>
</profile>

 

개인화 속성을 userDetail과 adminDetail로 나누었습니다. Name이라는 같은 속성이 존재하지만 그룹이 다르므로 오류는 발생하지 않을 것입니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    System.Web.Profile.ProfileGroupBase pgb_d = HttpContext.Current.Profile.GetProfileGroup("userDetail");
    pgb_d["Name"] = "cliel";

    System.Web.Profile.ProfileGroupBase pgb_a = HttpContext.Current.Profile.GetProfileGroup("adminDetail");
    pgb_a["Name"] = "administrator";

    Response.Write(string.Format("일반사용자의 이름은 {0}이며 관리자의 이름은 {1}입니다.", pgb_d["Name"].ToString(), pgb_a["Name"].ToString()));
}.

 

그룹지어진 속성에 접근하는 경우 Profile의 GetProfileGroup메소드를 사용해 특정 그룹에 해당하는 속성접근 ProfileGroupBase객체를 가져와야 합니다. 이렇게 가져온 객체를 통해 필요한 속성에 접근하는 것입니다.

 

 4. 데이터 타입 지정

 

개인화 속성은 따로 타입을 지정하지 않으면 기본이 String형입니다. 위에서 선언한 모든 속성도 별도의 타입을 지정하지 않았으므로 값의 형태는 String형이 됩니다.

 

데이터 형식 지정을 알아보기 위해 일반 사용자의 방문일자 저장을 위한 DateTime형의 속성을 하나더 추가해 보도록 하겠습니다.

 

<anonymousIdentification enabled="true" />
<profile>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
      <add name="Date_Visit" allowAnonymous="true" type="System.DateTime" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="SecurityCode" allowAnonymous="true" />
    </group>
  </properties>
</profile>

 

속성의 데이터 타입은 닷넷 데이터타입형식으로 정의할 수 있습니다.

 

protected void Button1_Click(object sender, EventArgs e)
{
    System.Web.Profile.ProfileGroupBase pgb_d = HttpContext.Current.Profile.GetProfileGroup("userDetail");
    pgb_d["Name"] = "cliel";
    pgb_d["Date_Visit"] = DateTime.Now;

    Response.Write(string.Format("{0}님은 반갑습니다. 방문하신 오늘은 {1}입니다.", pgb_d["Name"].ToString(), ((DateTime)pgb_d["Date_Visit"]).ToString("yyyy-MM-dd")));
}

 

특정 속성의 값을 가져오는 경우 특정 데이터타입을 다루는 경우라면 해당 데이터형식으로의 변환이 필요합니다. 속성은 기본적으로 object형식입니다.

 

물론 닷넷 데이터형식 이외에도 개발자가 따로 정의하는 별도의 데이터형식을 지정할 수도 있습니다. 예를 들어 관리자의 나이와 금전데이터를 다루는(좀 어거지지만) 클래스가 만들어 이 클래스형식 자체를 개인화속성으로 다루어야 하는 경우를 살펴보겠습니다.

 

우선 해당 클래스를 프로젝트의 App_Code폴더에 mycls라는 이름으로 다음과 같이 생성합니다.

 

[Serializable]
public class mycls
{
    public int age
    {
        get;
        set;
    }

    public double money
    {
        get;
        set;
    }
}

 

mycls 클래스안에는 age와 money속성 2개가 존재하며 각각 나이와 금액데이터를 저장할 것입니다. 클래스에는 [Serializable]이라는 특성이 선언되어 있는데 클래스 자체를 MDF DB내부에 바이너리 형태로 저장할 것이므로 위 특성이 필요합니다.(App_Code 안에 들어간 클래스파일은 Build Action이 Compile로 지정되어 있어야 합니다.)

 

이제 위에서 작성한 클래스를 web.config에 속성으로 선언합니다.

 

<group name="adminDetail">
  <add name="Name" allowAnonymous="true" />
  <add name="SecurityCode" allowAnonymous="true" />
  <add name="MYcls" type="web_form_test.App_Code.mycls" serializeAs="Binary" allowAnonymous="true" />
</group>

 

mycls 클래스는 web_form_test.App_Cde 네임스페이스에 속해 있으므로 type속성을 지정할때는 이를 정확히 지정해 줘야 합니다. 추가된 serializeAs 속성에는 Binary로 지정되어 있는데 속성을 저장하는 저장소에 직렬화 형태로 데이터를 저장하기 위함입니다. 이 밖에 다음과 같은 값을 지정할 수 있으니 참고하시기 바랍니다.

 

● Binary : 개체를 바이너리 형태로 직렬화 하고 저장합니다.

● ProviderSpecific : 개체의 저장형태를 특정 공급자에 의존하여 어떤형식으로 어떻게 저장할지를 공급자에 전적으로 맡기게 됩니다.

● String : 기본설정입니다. 문자열로 개체를 저장합니다.

● XML : 개체를 XML형태로 저장합니다.

 

클래스 형태의 데이터를 속성화 한다고 해서 클래스를 사용하는 방법이 달라지지는 않습니다. 속성을 통해 개체를 클래스형태로 변환해 읽어오면 해당 클래스의 개체를 그대로 사용할 수 있게 됩니다.

 

System.Web.Profile.ProfileGroupBase pgb = HttpContext.Current.Profile.GetProfileGroup("adminDetail");
mycls m = new mycls();
m.age = 30;
m.money = 3.40;

pgb["MYcls"] = m;

mycls m2 = pgb["MYcls"] as mycls;

Response.Write(string.Format("나이는 {0}세이고 잔액은 {1:G}원입니다.", m2.age.ToString(), m2.money));
 

 

 5. 기본값 설정

 

개인화 속성을 지정했는데 아무런 값도 입력되지 않은 경우에 대비해 다음과 같이 지정하면 기본적으로 저장될 값을 설정할 수 있습니다.

 

<add name="Name" allowAnonymous="true" defaultValue="none" />.

 

Name이 아무런 값도 입력되지 않으면 "none"이라는 문자열이 대신 저장될 것입니다.

 

 6. 읽기 전용

 

특정 속성을 읽기만 하고 저장할 수 없도록 하려면 readOnly 속성을 true로 설정합니다.

 

<add name="Name" allowAnonymous="true" readOnly="true" />

 

 7. 공급자 변경

 

개인화 속성에 값을 저장하면 해당 값은 기본적으로 내부 App_Data폴더에 mdf파일을 생성하고 저장하게 됩니다. 이 기본설정은 필요한 테이블이나 프로시저등을 알아서 생성해 모두 처리하지만 내부 MDF대신 외부 MSSQL의 DB서버를 개인화저장소로 사용하기로 했다면 필요한 설정을 수동으로 잡아줘야 합니다.

 

이런 작업과정을 거치는 방법은 2가지 정도가 있는데 우선 첫번째는 Visual Studio의 명령프롬프트창에서 aspnet_regsql.exe 명령을 통해 DB설정을 수행하는 것입니다.

 

아니면 두번째 방법으로 InstallPersonalization.sql 스크립트 파일을 이용해 설정과정을 처리할 수 있는데 이 파일은 C:\Windows\Microsoft.NET\Framework64\v4.0.xxxxx 폴더안에 있니다. 만약 이 DB설정을 취소하고 원래대로 되돌리려면 UninstallPersonalization.sql 스크립트를 실행하면 됩니다.

 

위 2가지중 하나의 방법을 사용해 설정을 거치고 나면 공급자를 변경해 실제 DB연결정보를 제공해 줘야 합니다.

 

<profile>
  <providers>
    <clear/>
    <add name="AspNetSqlProfileProvider" connectionStringName="sqlprovider" 

applicationName="/" type="System.Web.Profile.SqlProfileProvider, System.Web, Version=4.0.0.0, 

Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
  </providers>
  <properties>
    <group name="userDetail">
      <add name="Name" allowAnonymous="true" />
      <add name="Phone" allowAnonymous="true" />
      <add name="Address" allowAnonymous="true" />
      <add name="Date_Visit" allowAnonymous="true" type="System.DateTime" />
    </group>
    <group name="adminDetail">
      <add name="Name" allowAnonymous="true" readOnly="true" />
      <add name="SecurityCode" allowAnonymous="true" />
      <add name="MYcls" type="web_form_test.App_Code.mycls" serializeAs="Binary" allowAnonymous="true" />
    </group>
  </properties>
</profile>.

 

providers 요소 하위에<clear />요소로 우선 기존 공급자 정의를 제거하고 AspNetSqlProfileProvider 이름으로 공급자를 정의하였습니다. 여기서 중요한건 connectionStringName속성인데 예제에서는 sqlprovider로 설정되어 있습니다. 따라서 같은 이름의 연결정보가 다음과 같이 web.config에 정의되어 있어야 합니다.

 

<connectionStrings>
    <add name="sqlprovider" connectionString="Data Source=localhost;Initial Catalog=aspnetdb;

User ID=sa;Password=12345;"/>
 </connectionStrings>

 

필요하다면 속성에 따라 공급자를 나눌 수도 있습니다. 예를 들어 userDetail 그룹은 Local MDF에 adminDetail그룹은 외부 SQL Server에 저장하고자 한다면 각 개인화 속성에서 provider속성을 이용해 저장하고자 하는 저장소의 공급자를 지정하면 됩니다.

 

<add name="Name" allowAnonymous="true" provider="AspNetSqlProfileProvider" />

 

 8. ProfileManager

 

개인화 기능은 사용자의 데이터를 저장하고 사용하는데 편리함을 제공하지만 데이터자체를 관리해주지는 않습니다. 예를들면 익명사용자로 저장된 오래된 데이터를 삭제하거나 인증된 사용자가 사이트를 탈퇴하는 과정등으로 인해 더이상 정보를 저장할 필요가 없는 경우 등이 있을 수 있는데 개인화기능 자체는 이런 형태의 데이터관리기능을 제공하지 않습니다.

 

데이터 관리자체는 직접 해줘야 하지만 ProfileManager 클래스를 이용하면 이런 작업을 좀더 쉽게 구현할 수 있습니다. 클래스자체에 대한 사용방법은 어렵지 않으며 일련의 속성과 메소드를 알고 이를 필요에 따라 적절히 호출해서 사용하면 됩니다.

 

 ApplicationName

 개인화 속성을 저장할때 사용할 애플리케이션 이름을 설정하거나 가져옵니다.

 AutomaticSaveEnable

 개인화 속성을 자동으로 저장할지에 대한 여부를 설정합니다.

 Enabled

 개인화 속성의 사용 여부를 설정합니다.

 Provider

 개인화 속성을 저장하는 공급자를 확인합니다.

 Providers

 개인화 속성을 저장하는데 사용가능한 공급자를 확인합니다.

▶ 속성

 

 DeleteInactiveProfiles

 지정시간 이후로 사용되지 않은 개인화 속성데이터를 삭제합니다.

 DeleteProfile

 지정한 사용자의 개인화 속성데이터를 삭제합니다.

 DeleteProfiles

 DeleteProfile와 같으나 여러 사용자를 컬렉션으로 지정할 수 있습니다.

 FindInactiveProfilesByUserName

 특정 사용자의 개인화 데이터를 검색하되 지정된 시간 이후로 사용되지 않는 것만 검색합니다.

 FindProfilesByUserName

 특정 사용자의 개인화 데이터를 검색합니다.

 GetAllInactiveProfiles

 지정된 시간 이후로 사용되지 않는 모든 개인화 데이터를 검색합니다.

 GetNumberOfInactiveProfiles

 지정된 시간 이후로 사용되지 않는 모든 개인화 데이터의 갯수를 확인합니다.

 GetAllProfiles

 모든 개인화 데이터를 검색합니다.

 GetNumberOfProfiles

 모든 개인화 데이터 갯수를 확인합니다.

▶ 메소드

 

ProfileInfoCollection pic = ProfileManager.FindProfilesByUserName(ProfileAuthenticationOption.All, "guest");

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] WCF - 1  (0) 2016.08.31
[C#] Stream  (0) 2016.08.24
[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
[ASP.NET] 서버 컨트롤 - 1 (기본생성)  (0) 2016.08.01
[ASP.NET] ListView  (0) 2016.07.27
0 0
Programming/.NET

서버 컨트롤에 특정 내용을 표시(렌더링)하는건 RenderContents 메소드를 재정의 함으로서 가능합니다.

 

protected override void RenderContents(HtmlTextWriter output)
{
    output.Write(Text);
}

 

RenderContents 메소드에는 HtmlTextWriter형의 매개변수값을 받는데 이 클래스는 컨트롤이 HTML을 생성하는데 사용됩니다.

 

protected override void RenderContents(HtmlTextWriter output)
{
    output.RenderBeginTag(HtmlTextWriterTag.B);
    output.Write(Text);
    output.RenderEndTag();
}

 

때문에 실제 HTML을 표시하기 위한 다양한 메소드가 존재함을 알 수 있습니다. 예제에서는 RenderBeginTag메소드를 통해 HtmlTextWriterTag의 B열거형값으로 B태그를 표시하고 마지막으로 RenderEndTag메소드로 B태그를 닫도록 하고 있습니다. RenderEndTag는 바로 직전에 사용한 태그에 대한 닫기태그를 자동으로 생성합니다. 대부분의 HTML요소는 이러한 작업과정을 통해 출력할 수 있으며 일일이 태그를 직접 작성하지 않아도 됩니다.

 

RenderBeginTag메소드는 보통 HTML 4.0구문을 사용하도록 되어 있지만 만약 클라이언트 브라우저가 4.0이하 하위버전만을 사용할 수 있는 브라우저라면 3.2버전에 맞는 구문을 자동으로 내보내는 기능을 가지고 있습니다.

 

output.RenderBeginTag(HtmlTextWriterTag.Div);
output.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
output.Write(Text);
output.RenderEndTag();

 

HTML요소에 속성을 추가하려면 AddAttribute메소드를 사용해 HtmlTextWriterAttribute열거형으로 어떤 속성을 추가할지 지정하고 그 값을 AddAttribute의 두번째 매개변수로 전달합니다.

 

예제에서는 ID속성에 '_div'값을 주었는데 직접 값을 입력하는대신 UniqueID와 ClientID를 사용할 수 있습니다. 단순하게 ID는 직접 값을 지정해 ID를 정하지만 UniqueID는 이 속성이 호출될때 마다 '상위컨테이너컨트롤ID:Ctl번호'형식의 고유 ID를 생성합니다.

 

ClientID는 페이지나 컨트롤의 ClientIDMode 속성에 따라 동작방식이 달라지는데 AutoID라면 UniqueID와 동일하며 Static이면 상위컨테이너컨트롤ID값을 사용하지 않도록 합니다. Predictable은 Static와 반대인데 상위컨테이너컨트롤ID값을 사용하지만 'Ctl번호'형식은 사용하지 않습니다. 다만 상위컨테이너컨트롤에 ClientIDRowSuffix속성으로 고유한 값을 가져갈 수 있도록 지정할 수 있습니다. 마지막으로 Inherit은 상위컨테이너컨트롤ID와 동일하게 ID를 유지하도록 합니다.

 

단순한 HTMl요소를 렌더링하는 것이외에 스타일에 대한 렌더링도 제어가 가능합니다. 만약 컨트롤에 다음과 같이 스타일이 지정된 경우

 

<cc1:WebCustomControl1 runat="server" Text="aaa" BackColor="Red"></cc1:WebCustomControl1>

 

BackColor="Red"라는 스타일을 RednerContents메소드에서 생성되는 특정 HTML요소에 적용하고자 하는 경우 해당 요소를 렌더링하기전 AddAtrributesToRender메소드를 호출하면 됩니다.

 

this.AddAttributesToRender(output);
output.RenderBeginTag(HtmlTextWriterTag.Div);
output.AddAttribute(HtmlTextWriterAttribute.Id, UniqueID);
output.Write(Text);
output.RenderEndTag();

 

예제는 Div 요소를 렌더링하기전 AddAttributesToRender 메소드를 호출하였는데 이렇게 되면 background-color: red; 라는 스타일은 Div와 그 하위 span에 모두 적용될 것입니다. 참고로 코드를 통해 스타일자체를 추가하려면 AddStyleAtribute메소드를 사용해야 합니다.

 

output.AddStyleAttribute(HtmlTextWriterStyle.Color, "Yellow");
this.AddAttributesToRender(output);

 

AddStyleAttribute메소드를 통해 'Yellow'색상의 스타일을 컨트롤에 추가하고 다시 AddAttributesToRender메소드를 기존의 스타일과 AddStyleAttribte메소드를 통해 추가한 스타일을 적용하도록 합니다.

'Programming > .NET' 카테고리의 다른 글

[C#] Stream  (0) 2016.08.24
[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
[ASP.NET] 서버 컨트롤 - 1 (기본생성)  (0) 2016.08.01
[ASP.NET] ListView  (0) 2016.07.27
[ASP.NET] 사용자 정의 컨트롤  (0) 2016.07.21
0 0
Programming/.NET

Visual Studio (2015)에서 서버 컨트롤(Server Control)을 생성하려면 프로젝트에서 Add -> New Item을 클릭해 Add New Item 대화상자에서 Web -> Web Form 카테고리에 있는 Web Form Server Control을 선택하면 됩니다.

 

만약 웹 프로젝트가 웹사이트 프로젝트로 생성된것이 아니라면 되도록 서버컨트롤은 아이템을 추가하는 방식이 아닌 새로운 프로젝트로 생성하여 컨트롤을 제작하시기 바랍니다.

 

 

 

생성된 WebCustomControl 클래스를 보면 WebControl 클래스로 부터 파생된 것을 알 수 있는데

 

public class WebCustomControl1 : WebControl

 

WebControl 클래스는 파생되는 클래스에 대해 기본적인 HTML렌더링및 스타일요소를 지원할 수 있도록 합니다. 반면 컨트롤은 ScriptControl클래스로 부터도 파생될 수 있는데 ScriptControl은 WebControl뿐만 아니라 여러 script 라이브러리를 포함시켜 컨트롤을 제작할 수 있게끔 하는 개발영역을 포함하고 있습니다.

 

위와 같은 방법으로 생성된 서버 컨트롤을 페이지가 추가하려면 Register지시자로 서버 컨트롤이 속한 네임스페이스를 등록하고

 

<%@ Register Namespace="web_form_test.App_Code" TagPrefix="cc1" %>

 

Page의 원하는 지점에 TagPrefix로 지정한 접두사로 해당 컨트롤을 생성합니다.

 

<form id="form1" runat="server">
<div>
    <cc1:WebCustomControl1 runat="server" Text="aaa"></cc1:WebCustomControl1>
</div>
</form>

 

위와 같이 Text속성에 aaa라는 값을 지정할 수 있는 이유는 컨트롤에 Text 속성이 존재하며 RenderContents 메소드에 의해 Text값이 출력되었기 때문입니다.

 

사실 RenderContents 메소드는 WebControl의 Render 메소드에서 호출되는데 Render 메소드에서는 하나의 내용을 표시하기 위해 RenderBeginTag, RenderContents, RenderEndTag 세개의 메소드를 순서대로 호출합니다.

 

RenderBeginTag와 RenderEndTag메소드는 RenderContents전후에 배치되어 '<span>'과 같은 내용을 출력내용에 포함시키는데 이 때문에 위 예제의 결과에서 aaa내용 자체를 HTML로 열어 보면 '<span>aaa</span>'과 같이 출력되는 것을 확인할 수 있습니다.

 

이 과정자체는 웹호환성을 최대한 확보하기 위해 구현된 것인데 때로는 이러한 처리가 불편할 수 있습니다. 만약 이 과정이 문제가 되어 해결해야 한다면 Render 메소드를 직접 재정의 해야 합니다.

 

protected override void Render(HtmlTextWriter writer)
{
    this.RenderContents(writer);
}

 

컨트롤의 클래스에 보면 해당 클래스에 적용된 특성을 볼 수 있는데 보통 다음과 같은 형식입니다.

 

[DefaultProperty("Text")]
[ToolboxData("<{0}:WebCustomControl1 runat=server></{0}:WebCustomControl1>")]

 

이 특성들은 컨트롤의 동작이나 도구상자에서 어떻게 표시될지를 지정하는 것이며 보통 다음과 같은 특성들을 사용합니다.

 

 Designer

 해당 컨트롤이 Visual Studio의 디자인모드에서 표시될때 해당 컨트롤에 대한 렌더링을 담당하는 클래스를 지정합니다.

 TypeConverter

 변환하고자 하는 타입을 지정합니다.

 DefaultEvent

 더블클릭을 통해 기본적으로 생성될 이벤트를 지정합니다.

 DefaultProperty

 기본속성을 지정합니다.

 ControlBuilder

 커스텀컨트롤을 구현하기 위한 클래스를 지정합니다.

 ParseChildren

 컨트롤의 태그내부의 XML요소가 속성이나 자식컨트롤로 취급될 수 있는지의 여부를 지정합니다.

 TagPrefix

 사용할 수 있는 접두사를 지정합니다.

 

이번에는 클래스가 아닌 속성을 보겠습니다. 컨트롤의 속성에는 기본으로 Text속성이 지정되어 이 속성에도 다음과 같은 형식의 특성이 존재하며

 

[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]

 

아래 특성을 추가적으로 정의할 수 있습니다.

 

 Bindable

 해당 속성의 바인딩여부를 지정합니다.

 Browsble

 해당 속성이 속성창에 표시될지 여부를 지정합니다.

 Category

 해당 속성이 속한 속성범주를 지정합니다.

 Description

 해당 속성에 대한 설명을 작성합니다.

 EditorBrowsable

 해당 속성이 수정가능한지 여부를 지정합니다.

 DefaultValue

 해당 속성의 기본값을 지정합니다.

 NotifyParentProperty

 해당 속성값 수정시 부모 속성이 알릴지 여부를 지정합니다.

 PersistanceMode

 해당 속성이 페이지상에 유지될지를 지정합니다.

 Editor

 해당 속성값을 변경하기 위한 UI편집기를 지정합니다.

 Localizable

 해당 속성의 지역화 여부를 설정합니다.

 Themable

 해당 속성의 테마적용 여부를 지정합니다.

 

'Programming > .NET' 카테고리의 다른 글

[ASP.NET] 개인화(Personalization)  (0) 2016.08.16
[ASP.NET] 서버 컨트롤 - 2 (렌더링)  (0) 2016.08.09
[ASP.NET] 서버 컨트롤 - 1 (기본생성)  (0) 2016.08.01
[ASP.NET] ListView  (0) 2016.07.27
[ASP.NET] 사용자 정의 컨트롤  (0) 2016.07.21
[ASP.NET] 가장 (impersonation)  (0) 2016.07.12
0 0
1
블로그 이미지

클리엘