'2017/03'에 해당되는 글 6건

Programming/.NET

사용자가 웹서비스에 로그인을 했을때 해당 사용자의 이름을 표시하는 컨트롤입니다.

 

<asp:LoginName ID="LoginName1" runat="server" />

 

만약 로그인이름에 특정 메세지내용을 추가하고 싶다면 FormatString속성을 사용합니다.

 

<asp:LoginName ID="LoginName1" runat="server" FormatString="{0}님 반갑습니다." />

 

{0}안에는 자동으로 사용자이름이 매핑됩니다.

 

아예 아무런 내용도 표시하고 싶지않다면 그냥 FormatString속성을 공백으로 놔두면 됩니다.

0 0
Programming/.NET

HTTP는 비연결 프로토콜입니다. 클라이언트(정확하게는 웹 브라우저)가 서버에 특정 처리를 요청하고 나면 서버에서 그에 맞는 응답을 해주는 것으로 끝납니다. 연결이 계속해서 유지되어야 하는 FTP와는 다른것입니다.

 

이러한 HTTP통신 방식으로 인해 클라이언트가 어떤 데이터를 서버에 요청을 할때마다 서버는 어떻게 해서든 이 사용자가 누구인가 혹은 어떤 데이터를 다루고자 하는가를 구분해야할 필요가 있습니다. 이럴 때 세션(Session)이 사용될 수 있습니다. 다만 세션은 사용자를 구분하기 위한 유일한 방법이 아닙니다. 그저 사용자를 구분하는 방법중 '하나'에 해당할 뿐입니다.

 

세션은 쿠키와 비교될 수 있습니다. 쿠키는 클라이언트에 저장되는 반면 세션은 서버에서 저장되고 관리됩니다. 쿠키보다 훨씬 보안적으로 우수하지만(쿠키는 원한다면 얼마든지 사용자에 의해 변조될 수 있습니다.) 세션은 서버의 자원을 할당해야 한다는 측면에서 성능상으로 단점이 존재합니다.

 

 1. InProc

 

세션은 기본적으로 InProc모드로 관리됩니다. In-Process라는 것으로 HttpRuntime 개체(프로세스)의 내부 캐시에 세션을 저장하고 관리합니다. 이 때문에 실행속도가 가장 빠른 모드이지만 세션을 계속 참조상태에 유지하고 있고 이에대한 가비지 컬렉션은 별도로 이루어지는게 없어서 메모리를 계속 점유하고 있다는 단점이 존재합니다. 물론 그렇다 하더라도 메모리 점유는 만료시간이 20분이 경과하거나 별도의 구성파일에 지정된 시간이 지나면 자동으로 만료되므로 평생 세션을 저장해두지는 않습니다.

 

참고로 InProc모드에서의 세션은 dll이 빌드되어 새로 배포되거나 Web.config와 같은 구성파일의 변경등과 같은 이유로 프로세스가 다시 시작하면 기존 세션은 모두 손실됩니다.

 

ASP.NET에서 세션은 다음과 같이 읽고 쓸 수 있습니다.

 

Session["aaa"] = "aaabbb";
Response.Write(Session["aaa"].ToString());

 

세션은 ASP.NET의 모든 페이지에서 위와 같은 방법으로 엑세스할 수 있습니다. 만일 "aaa"라는 인덱스의 세션을 사용하는 특정페이지가 호출된다면 이 요청이 완료될때까지 같은 세션을 사용하는 다른 페이지는 대기상태에 들어가게 됩니다.(사용하는 세션의 인덱스가 다르면 영향이 없습니다.)

 

필요하다면 특정 페이지마다 EnableSessionState 속성을 조정함으로서 세션접근에 대한 권한을 조정할 수 있습니다.

 

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs"

 Inherits="web_form_test.Default" EnableSessionState="True"  %>

 

True값은 세션에 대한 읽기/쓰기 권한을 모두 부여합니다. 같은 세션을 사용하는 다른 페이지에서는 세션이 잠기게 됩니다.

 

False값은 세션에 대한 권한을 주지 않습니다. 만약 False설정이된 페이지에서는 세션이 접근할 수 없습니다.

 

ReadOnly는 세션에 대해 오로지 읽기권한만을 부여합니다. 이 경우에는 세션잠금이 설정되지 않기 때문에 다른 페이지에서 같은 세션의 값을 읽을 수 있습니다. 하지만 세션에 쓰기가 시도되는 경우 모든 읽기또한 차단됩니다.

 

재미있는 점은 EnableSessionState가 False로 설정된 페이지는 설정이 없는 페이지요청보다 우선적으로 처리하게 된다는 것입니다. 따라서 계획적으로 잘만 설정된다면 성능적으로 이익을 볼 수 있습니다. 극단적으로 Web.config를 아래와 같이 처리하면

 

<sessionState mode="Off"></sessionState>

 

웹애플리케이션 전체에 대해 세션사용을 고려하지 않게 되므로 성능면에서 훨씬 이득이지만 세션은 사용할 수 없습니다.

 

 2. Out-of-Process

 

Out-of-Process는 세션을 aspnet_state.exe라는 프로세스에 저장하는 방식입니다. 다른 물리적 서버에 해당 프로세스를 띄어놓고 세션을 관리하는 형태(세션을 처리하는 서버를 별도로 두는것)이지만 원한다면 로컬에 프로세스를 실행하는것 또한 가능합니다. aspnet_state.exe는 자동으로 시작되는 프로세스가 아니므로 서비스를 수동으로 시작해 줘야 합니다.

 

net start aspnet_state

 

위와 같은 명령줄 대신 Services 관리자에서 시작할 수도 있습니다.

 

 

이 프로세스는 TCP통신을 하는데 기본포트가 42424입니다. 이 설정은 아래 레지스트리경로에서 바꿀 수 있습니다.

 

[HKEY_LOCAL_MACHINE]\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\Port

 

세션관리를 Out-of-Process로 하기로 했다면 Web.config에서 세션설정을 바꿔줍니다.

 

<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424">

</sessionState>

 

mode를 StateServer로 설정하여 Out-of-Process 사용을 명시하고 stateConnectionString을 통해서 연결될 서버의 IP와 Port를 설정합니다. 예제에서는 로컬에서 사용할 것이므로 127.0.0.1:42424로 설정하였습니다. 다른 서버라면 그에 맞는 IP를 지정해 주시면 됩니다.

 

이 방식은 일단 이름에 걸맞게 프로세스를 벗어난 세션관리형태의 방식입니다. 그러니까 ASP.NET애플리케이션(코드)은 w3wp.exe프로세스에서 동작하는데 세션관리는 aspnet_state.exe 프로세스에 관리되므로 코드에서 세션을 참조할 수 있는 형태가 아닙니다.

 

그래서 세션에 단순한 문자열을 담는 경우는 상관없지만 클래스나 구조체등을 초기화 하고 세션에 담으려 하면 오류가 발생합니다. 코드의 동작과 세션관리가 다른 프로세스로 분리되어 있기 때문입니다. 이들 프로세스간 통신을 수행해서 세션처리를 정상적으로 처리하려면 사용하려는 클래스에 [Serializable] 특성을 선언해야 합니다.

 

[Serializable]
public class testClass
{
    public string myname;
}

 

클래스를 위와같이 작성하고

 

testClass tc = new testClass();
protected void Page_Load(object sender, EventArgs e)
{
    tc.myname = "cliel";
    Session["aaa"] = tc;
}

protected void Button1_Click(object sender, EventArgs e)
{
    Response.Write((Session["aaa"] as testClass).myname);
}

 

클래스를 세션에 담으면 정상적으로 코드가 수행될 것입니다. 다만 클래스(개체)를 [Serializable]특성을 사용해 직렬화 하면 직렬화되는 과정에서 크기가 다소 커질 수 있습니다. 그 만큼 aspnet_state.exe 프로세스는 관리해야 하는 세션의 크기가 커질 수 있다는 뜻인데 sessionState 요소의 compressionEnabled속성을 true로 하면 개체를 압축해서 저장하므로 크기에 대한 부담이 다소 줄어들 수 있습니다.

 

<sessionState mode="StateServer" stateConnectionString="tcpip=127.0.0.1:42424"

 compressionEnabled="true"></sessionState>

 

하지만 실제 개체를 사용하려면 어떻게 해서든 압축된걸 푸는 과정이 필요하므로 InProc보다는 성능에서 불리할 수 있습니다.

 

 3. SQL 서버 세션

 

세션은 필요하다면 SQL 서버에서 저장하고 관리할 수도 있습니다. 이 방식은 이전에 말씀드린 방식에 비해 가장 느리지만 반면 가장 안전하게 동작하는 방식입니다. 심지어는 IIS전체가 재시작되는 경우라 하더라도 서버에 세션정보가 저장되므로 사용자와의 세션은 계속 유지될 수 있습니다.

 

SQL서버를 통해서 세션을 관리하려면 특정 DB안에 세션저장을 위한 구성이 추가되어야 합니다. 이 작업은 aspnet_regsql.exe 를 통해서 구현할 수 있습니다.

 

아래는 세션관리를 위한 aspnet_regsql.exe 실행 예시입니다.

 

aspnet_regsql.exe -S localhost -U sa -P 1234 -ssadd -sstype p

 

위와 같이 명령줄을 입력하면 해당 서버에 ASPState DB를 자동으로 생성하고 세션저장을 위한 구성을 완료하게 됩니다.

 

참고로 -ssadd는 지정된 서버에 세션상태저장을 위한 구성을 추가하는 옵션이며 반대로 -ssremove는 추가된 구성을 제거하도록 하는 옵션입니다.

 

-sstype으로 지정된 p는 데이터와 프로시저를 ASPState DB에 저장하도록 합니다. 물론 DB도 알아서 만들어 주므로 일단 편리함은 최고입니다. p외에 t라는 옵션도 있는데 이 옵션은 세션을 tempdb에 저장하고 프로시저는 ASPState에 생성하도록 합니다. 이는 세선을 임시테이블에 저장하는 형태다 보니 SQL서버가 다시 시작되면 세션데이터는 사라진다는 특징이 있습니다.

 

만일 ASPState DB에 세션저장과 프로시저가 생성되는걸 원하지 않는다면 c옵션으로 직접 세션이 저장되고 프로시저가 생성되는 DB를 지정해 줄 수도 있습니다.

 

 

 

aspnet_regsql.exe를 실행시켜 위와 같이 정상적으로 처리되었다면 이제 web.config를 수정하여 세션을 SQL Server에 저장하도록 해주면 됩니다.

 

<sessionState mode="SQLServer" sqlConnectionString="data source=127.0.0.1;user

 id=sa;password=12345"></sessionState>

 

참고로 ASPState DB가 아닌 다른 이름의 DB를 사용한다면 위 Web.config설정에서 database=mydb형식으로 내용을 추가해 줘야 합니다.

0 0
Programming/.NET

EntityFramework(엔티티프레임워크)를 간단하게 설명하면 기존의 애플리케이션이 DB데이터와 통신하기 위해 쿼리등을 통하여 데이터를 조회하고 저장하는 방식에서 발전해 DB의 각 테이블을 각각의 객체개념으로 매핑하여 객체의 내부요소(데이터)를 조회하거나 저장처리할 수 있도록 하는 개념입니다.

 

데이터를 객체화하여 다룰 수 있다는 것은 Visual Studio에서의 코딩이 가능하다는 것을 의미하고 이것은 인텔리센스기능지원이나 디버깅등에서의 작업능률 향상을 의미하기도 합니다.

 

엔티티프레임워크를 사용해 보기 전에 우선 대상이될 DB서버에 tmp라는 이름의 데이터베이스를 생성하고 user_list와 user_address라는 테이블을 만듭니다. 물론 테스트를 위해서는 적절한 데이터도 입력이 되어야 할것입니다.

 

 

다음으로 해당 테이블을 대상으로 엔티티 데이터모델을 생성하면 되는데 이를 위해 Visual Studio에서 Add New Item 대화상자를 열고 ADO.NET Entity Data Model 을 선택합니다. 예제에서 이름은 MyModel로 하였습니다.

 

 

다음 화면에서 EF Designer from database를 선택합니다.

 

 

다음버튼을 누른 후 New Connection 버튼을 눌러 DB연결을 설정합니다.

 

 

연결설정에서 적절한 서버와 계정을 입력하고 database로는 위에서 생성한 tmp을 선택합니다. 설정이 완료되면 'OK'버튼을 누릅니다.

 

 

설정이 완료되면 이전 화면에서의 콤보박스에 연결항목이 나타날 것입니다. 참고로 선택된 'Yes, include the sensitive data in the connection string' 항목은 비번과 같은 민감한 데이터를 연결문자열에 표시하도록 한 것입니다. 보안성이 요구되면 'No'항목을 선택하고 코드단에서 보안에 필요한 내용을 직접 처리해야 합니다.

 

 

다음 버튼을 누르면 해당 DB에서 선택가능한 항목(테이블, 프로시저등)이 표시됩니다. 모델링할 대상을 선택하고 '끝내기'버튼을 누르십시오.

 

 

위와 같은 단계를 거치고 나면 edmx 파일이 생성될 것입니다. 이것만으로 사용준비가 완료된것입니다. 이제 빈페이지 하나를 생성하고 실제 만들어진 Entity객체를 통해 데이터를 가져와 보겠습니다.

 

<body>

    <form id="form1" runat="server">
    <div>

        <asp:GridView ID="GridView1" runat="server"></asp:GridView>
    </div>
    </form>
</body>

 

우선 페이지에 GridView 컨트롤을 배치하고

 

protected void Page_Load(object sender, EventArgs e)
{
    tmpEntities te = new tmpEntities();

    GridView1.DataSource = te.user_list.ToList();
    GridView1.DataBind();
}

 

엔티티 데이터모델 객체를 통해 user_list 테이블에 있는 데이터를 모두 가져오도록 하였습니다. 이 데이터모델은 web.config(응용프로그램 이라면 App.config)에 있는 연결문자열정보를 통해 DB서버에 연결되어 데이터를 가져오게 됩니다.

 

예제에서는 user_list 테이블의 모든 데이터를 가져와 GridView에 뿌렸는데 edmx에서 테이블을 상속하는 방법으로 특정 데이터를 분리된 테이블로 구분할 수 있습니다. 예를 들어 user_age인 값이 30인것과 40인것을 구별하여 테이블을 분리해 관리할 수 있는 것입니다.

 

edmx를 열어 마우스 우클릭을 하고 Add New -> Entity항목을 차례로 선택합니다.

 

 

Base_type을 user_list로 선택하여 지금 생성하려는 Entity가 기존 user_list에서 상속받도록 합니다. 이름은 entity_user_list로 하였습니다.

 

해당 절차를 마치고 나면 다음과 같은 화면이 보여질 것입니다.

 

 

user_list 개체를 선택해 마우스 우클릭을 하여 'Table Mapping'항목을 선택합니다.

 

 

Mapping Detail에서 위 화면과 같이 Maps to user_list 하위에 When user_age를 생성하고 값을 30으로 입력합니다. 이렇게 되면 이제 user_age가 30인 것은 user_list 객체가 됩니다.

 

 

조금전 생성한 entity_user_list에도 같은 작업을 수행하는데 이번에는 값을 40으로 입력합니다. 이제 user_age가 40인 것은 entity_user_list가 됩니다.

 

tmpEntities te = new tmpEntities();

var user_list = (from age in te.user_list
                where age is entity_user_list
                select new { age.user_name, age.user_phone }).ToList();

GridView1.DataSource = user_list;
GridView1.DataBind();

 

 

코드를 수정하여 user_list에서 user_age가 entity_user_list와 같은 것으로만 데이터를 가져오도록 하였습니다. 새로운 entity는 위와 같이 작업이 가능합니다.

 

Entity모델링은 테이블뿐만 아니라 프로시저(Procedure)를 대상으로 할 수도 있습니다. 이를 테스트해 보기 위해 다음과 같은 임의의 프로시저를 하나 생성합니다.

 

-----------------------------------------

CREATE PROCEDURE GET_USER_LIST
AS
BEGIN
 SET NOCOUNT ON;

 SELECT *
 FROM user_list;
END
GO

-----------------------------------------

 

그런 후 edmx에서 마우스 우클릭하여 'Update Model from Database'를 선택하고 방금 추가한 GET_USER_LIST 프로시저 항목을 체크한 뒤 '완료'버튼을 누릅니다.

 

 

하지만 edmx에는 아무것도 나오지 않는데 대신 마우스 우클릭하여 'Model Browser'를 선택하면 해당 해당 View에서 추가된 프로시저 항목을 볼 수 있습니다.

 

 

따라서 저장프로시저는 테이블과 달리 변경가능한 Entity로 제공되지 않습니다. 그러나 코드에서 불러와 작업하는데는 아무런 영향이 없습니다.

 

tmpEntities te = new tmpEntities();

var user_list = te.GET_USER_LIST();

GridView1.DataSource = user_list;
GridView1.DataBind();

 

 

코드에서 일일이 Entity모델을 다루는 것조차 귀찮다면 아예 테이블이나 프로시저를 DataSource객체로 만들어 디자인단에서 컨트롤에 바로 전달할 수도 있습니다.

 

이렇게 하려면 우선 aspx 파일에서 GridView 컨트롤 밑에 EntityDataSource컨트롤을 배치합니다.

 

<form id="form1" runat="server">
<div>
    <asp:GridView ID="GridView1" runat="server"></asp:GridView>
    <asp:EntityDataSource ID="EntityDataSource1" runat="server"></asp:EntityDataSource>
</div>
</form>

 

페이지를 디자인화면으로 전환해 EntityDataSource 컨트롤의 스마트태그를 클릭하여 'Configure Data Source'를 선택합니다.

 

 

Named Connection에 기존에 추가한 데이터모델인 tmpEntities를 선택하고 DefaultContainerName에도 같은걸 선택한 후 'Next'버튼을 누릅니다.

 

 

 

EntitySetName에 데이터소르로 가져올 모델을 선택합니다. 필요에 따라 Choose the proerties in the query result 부분에 표시할 열을 추가하거나 데이터의 삽입, 삭제, 업데이트를 위한 활성화여부를 지정할 수 있습니다.

 

이제 EntityDataSource를 설정을 모두 마쳤습니다. 다음으로 aspx페이지에서 GridView컨트롤의 DataSourceID속성을 EntityDataSource ID로 설정하면 GridView와 EntityDataSource와의 연결이 이루어지게 됩니다.

 

<form id="form1" runat="server">
<div>
    <asp:GridView ID="GridView1" runat="server" DataSourceID="EntityDataSource1">

</asp:GridView>
    <asp:EntityDataSource ID="EntityDataSource1" runat="server" 

ConnectionString="name=tmpEntities" DefaultContainerName="tmpEntities" 

EnableFlattening="False" EntitySetName="user_list">

</asp:EntityDataSource>
</div>
</form>

 

참고로 EntityDataSource를 설정할때 마법사기능은 2016년6월 현재 EntityFramework 5.0에서만 가능합니다. 따라서 이보다 높은 버전을 사용하는 경우 속성을 직접 추가하는 방법으로 EntityDataSource컨트롤을 설정해야 합니다.

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

[ASP.NET] LoginName  (0) 2017.03.28
[ASP.NET] 세션(Session)  (0) 2017.03.21
[ASP.NET] EntityFramework(엔티티프레임워크)  (0) 2017.03.14
[ASP.NET] 설정파일 - 2  (0) 2017.03.06
[ASP.NET] 서버 컨트롤 - 8 (디자인)  (0) 2017.03.03
[ASP.NET] 서버 컨트롤 - 7 (형변환)  (0) 2017.02.22
0 0
OS/Windows Server

보통 서버환경에서 서버나 프로그램에 관한 모니터링에 관리 도구에 있는 성능카운터를 활용합니다.

 

 

 

서버에 ASP.NET등으로 웹 프로그램을 운용한다면 다음과 같이 ASP.NET에 적용되는 성능카운터등을 확인할 수 있습니다.

 

 

 Application Restarts

 서버가 동작하는 동안 프로그램이 재시작된 횟수

 Application Running

 현재 동작중인 프로그램 수

 Audit Failure Events Raised

 프로그램 감사 실패 횟수

 Audit Success Events Raised

 프로그램 감사 성공 횟수

 Error Events Raised

 프로그램이 발생시킨 오류 이벤트 횟수

 Infrastructure Error Events Raised

 HTTP 오류 이벤트 횟수

 Request Error Events Raised

 프로그램이 발생시킨 런타임 이벤트 횟수

 Request Execution Time

 가장 최근 요청을 처리하는데 걸린 시간 (1/1000초)

 Request Waite Time

 큐에서 가장 최근요청이 대기한 시간(1/1000초)

 Requests Current

 모든 요청 수, 해당 카운터는 processModel에 정의된 requestQueueLimit 값을 기준으로 초과되면 요청이 거부됨

 Requests Disconnected

 연결이 끊어지거나 사용자가 종료한 요청 수

 Requests Queued

 큐에 대기중인 요청 수

 Requests Rejected

 큐가 가득찬 상태에서 거부된 요청 수

 State Server Sessions Abandoned

 명시적으로 중단된 세션 수

 State Server Sessions Active

 현재 활성화된 세션 수

 State Server Sessions Timed Out

 시간 초과된 세션 수

 State Server Sessions Total

 총 세션 수

 Worker Process Restarts

 작업자 프로세스를 다시 시작한 횟수

 Worker Processes Running

 실행중인 작업자 프로세스 수

 

0 0
Programming/.NET

ASP.NET에서는 machine.config나 web.config파일에 대해 프로그래밍으로 직접 설정내용을 읽거나 추가/수정이 가능한 API를 제공하고 있습니다. 이들 API들은 System.Configuration 네임스페이스 아래에 있으며 사용할 수 있는 클래스로는 다음과 같은 것들이 있습니다.

 

 AppSettingsSection

 <appSettings> 요소

 ConnectionStringsSettings

 <connectionStrings> 요소

 ProtectedConfigurationSection

 <protectedConfiguration> 요소

 ProtectedDataSection

 <protectedData> 요소

 AuthenticationSection

 <authentication> 요소

 AuthorizationSection

 <authorization> 요소

 CompilationSection

 <compilation> 요소

 CustomErrorsSection

 <customErros> 요소

 FormsAuthenticationConfiguration

 <forms> 요소

 GlobalizationSection

 <globalization> 요소

 HttpHandlersSection

 <httpHandlers> 요소

 HttpModulesSection

 <httpModules> 요소

 HttpRuntimeSection

 <httpRuntime> 요소

 MachineKeySection

 <machineKey> 요소

 MembershipSection

 <membership> 요소

 PagesSection

 <pages> 요소

 ProcessModelSection

 <processModel> 요소

 WebPartsSection

 <webParts> 요소

 

위 클래스들을 사용하면 각 이름에 맞는 설정구성에 대해 접근및 추가, 삭제등을 수행할 수 있습니다.  예를 들어 연결정보가 설정된 ConnectionStrings 요소의 값들을 모두 가져오려면 다음과 같이 처리할 수 있으며

 

foreach (ConnectionStringSettings con in System.Web.Configuration.WebConfigurationManager.ConnectionStrings)
    Response.Write(con.ConnectionString + "<br />");

 

반면 연결정보에 설정내용을 추가하기 위해서는 아래 절차를 거치면 됩니다.

 

ConnectionStringSettings css = new ConnectionStringSettings("mssqldb", "Data Source=localhost;Initial Catalog=testdb;User ID=sa;Password=12345;Persist 

Security Info=True;");

Configuration con = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration(Request.ApplicationPath);
con.ConnectionStrings.ConnectionStrings.Add(css);
con.Save();

 

참고로 Web.config대신 machine.config를 열려면 System.Configuration.ConfigurationManager의 OpenMachineConfiguration메소드를 사용해야 합니다.

 

Configuration c = System.Configuration.ConfigurationManager.OpenMachineConfiguration();
foreach (string con in c.SectionGroups)
    Response.Write(con);

 

만일 로컬이 아닌 원격지 서버의 설정파일정보를 가져와야 한다면 OpenWebConfiguration메소드를 확장하여 원격서버를 지정하십시오.

 

Configuration c = System.Web.Configuration.WebConfigurationManager.OpenWebConfiguration("/", "test.server.co.kr");
ConfigurationSection cs = c.GetSection("connectionStrings");

 

설정파일의 설정내용은 기본적으로 사람이 읽을 수 있는 형태로 저장되고 관리되었습니다. 때문에 아이디와 비밀번호같은 민감정보는 별도로 암호화하여 관리할 수 있는 방법이 필요한데 이와 관련해 ASP.NET에서는 aspnet_regiis.exe 도구를 제공하고 있습니다.

 

예들 들어 web.config파일안에 설정된 연결문자열 정보를 보면 문자열 내부에 User ID와 Password로 비밀번호가 그대로 노출됨을 알 수 있습니다. 물론 그렇다고 해서 외부의 사용자가 해당 파일을 열어볼 수 있는것은 아니지만 직접 파일을 열어보는 경우까지도 보호가 필요하다면 aspnet_regiis를 다음과 같이 활용할 수 있습니다.

 

aspnet_regiis.exe -pef "connectionStrings" "C:\interup\testweb"

 

connectionStrings는 실제 암호화를 적용할 설정요소를 의미하며 뒤이어 오는 PATH는 web.config가 존재하는 폴더입니다.

 

암호화를 수행하고 나면 다음과 비슷한 결과를 볼 수 있습니다.

 

<connectionStrings configProtectionProvider="RsaProtectedConfigurationProvider">
  <EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
    xmlns="http://www.w3.org/2001/04/xmlenc#">
    <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
    <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
      <EncryptedKey xmlns="http://www.w3.org/2001/04/xmlenc#">
        <EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <KeyName>Rsa Key</KeyName>
        </KeyInfo>
        <CipherData>
          <CipherValue>nhv88Uv72+z+</CipherValue>
        </CipherData>
      </EncryptedKey>
    </KeyInfo>
    <CipherData>
      <CipherValue>/p9unppHlaCtFaAbtYQJFIjdqL7izI/3g9ZRp4SN93V</CipherValue>
    </CipherData>
  </EncryptedData>
</connectionStrings>

 

 

설정값을 가져올때 이렇게 암호화된 내용을 어떻게 복호화하여 가져올 수 있는지에 대해서는 고민할 필요가 없습니다. 이미 해본것처럼 API를 통해 설정정보를 가져오기만 하면 자동으로 복호화를 수행한 결과를 가져올 것입니다.

 

반대로 복호화를 수행하려면 -pdf 옵션을 사용합니다.

0 0
Programming/.NET

특정 페이지에 ListBox와 같은 컨트롤을 배치하고 Design화면을 보면 다음과 같이 컨트롤을 디자인 할 수 있는 화면을 볼 수 있습니다.

 

컨트롤을 직접 작성하는 경우 이와 같은 기능을 구현하기 위해서는 우선 컨트롤을 직접 디자인할 수 있도록 하는 컨트롤디자이너를 생성해야 합니다.

 

public class WebCustomControl1ControlDesigner : CompositeControlDesigner

 

컨트롤 디자이너는 CompositeControlDesigner 추상클래스를 상속받도록 합니다. 우선 컨트롤 디자이너는 클래스형태만 만들어둡니다.

 

[Designer(typeof(WebCustomControl1ControlDesigner))]
[ToolboxData("<{0}:WebCustomControl1 runat=\"server\" width=\"100%\"></{0}:WebCustomControl1>")]
public class WebCustomControl1 : CompositeControl

 

이제 컨트롤 디자이너가 들어갈 컨테이너 컨트롤을 작성합니다. 이 컨트롤은 CompositeControl 클래스를 상속받습니다.

 

Designer 특성은 해당 컨테이너에 들어갈 디자이너 컨트롤을 지정하며 ToolboxData는 사용자가 해당 컨트롤을 페이지에 배치할때 표시될 내요을 지정합니다. {0}은 접두사가 붙는 부분입니다.

 

[PersistenceMode(PersistenceMode.InnerProperty), DefaultValue(null)]
public virtual ITemplate View
{
    get;
    set;
}

protected override void CreateChildControls()
{
    Controls.Clear();

    ITemplate template = View;

    Panel p = new Panel();
    Controls.Add(p);

    if (template != null)
        template.InstantiateIn(p);
}

 

컨테이너 컨트롤인 WebCustomControl1 클래스 에는 화면에 표시될 ITemplate 내부 속성을 추가하고 디자이너 컨트롤을 생성할 CreateChildControls 메소드를 재정의합니다. 여기까지 하면 컨테이너 컨트롤의 내부를 모두 작성한 것입니다.

 

private WebCustomControl1 myControl;

 

이제 디자이너 컨트롤인 WebCustomControl1ControlDesigner 클래스를 작성합니다. 디자이너 컨트롤에서는 컨테이너 컨트롤에 직접 접근할 필요가 있으므로 WebCustomControl1 형식의 컨트롤변수를 생성합니다.

 

public override void Initialize(IComponent component)
{
    base.Initialize(component);
    myControl = (WebCustomControl1)component;
}

 

초기화 메소드를 재정의하여 위에서 선언한 myControl에 컨테이너 컨트롤을 담아두도록 합니다.

 

public override string GetDesignTimeHtml(DesignerRegionCollection regions)
{
    return DesignHtml();
}

 

컨트롤이 화면에 배치되면 GetDesignTimeHtml 메소드가 자동으로 호출되는데 디자인타임에 표시할 내용을 직접 작성할 것이므로 해당 메소드를 재정의합니다.

 

protected virtual string DesignHtml()
{
    StringBuilder sb = new StringBuilder();

    sb.Append(BeginDesignHtml());
    sb.Append(ContentDesignHtml());
    sb.Append(EndDesignHtml());

    return sb.ToString();
}

protected virtual String BeginDesignHtml()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("<table border='10'>");
    sb.Append("<tr>");
    sb.Append("<td>");

    return sb.ToString();
}

protected virtual String EndDesignHtml()
{
    return "</tr></td></table>";
}

protected virtual String ContentDesignHtml()
{
    StringBuilder sb = new StringBuilder();
    sb.Append("디자인 화면");

    return sb.ToString();
}

 

GetDesignTimeHtml 메소드에서는 DesignHtml 이라는 메소드를 반환하는데 이때 DesignHtml 메소드가 진짜 디자인타임에 표시할 HTML을 생성하는 메소드입니다. 이 메소드는 BeginDesignHtml, ContentDesignHtml, EndDesignHtml 메소드를 차례로 호출하여 HTML 문자열을 얻는데 각각의 Html메소드를 보시면 실제 가져올 HTML의 내용을 구현하고 있습니다.

 

public override string GetEditableDesignerRegionContent(EditableDesignerRegion region)
{
    IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));

    if (host != null)
    {
        ITemplate template = myControl.View;

        if (template != null)
            return ControlPersister.PersistTemplate(template, host);
    }

    return String.Empty;
}

public override void SetEditableDesignerRegionContent(EditableDesignerRegion region, string content)
{
    if (content == null) {
        myControl.View = null;
        return;
    }

    IDesignerHost host = (IDesignerHost)Component.Site.GetService(typeof(IDesignerHost));

    if (host != null) {
        ITemplate template = ControlParser.ParseTemplate(host, content);

        if (template != null)
            myControl.View = template;
    }
}

 

재정의한 GetEditableDesignerRegionContent 메소드와 SetEditableDesignerRegionContent 메소드는 각각 상황에 따라 필요한 HTML을 가져오거나 설정하기 위한 메소드입니다.

 

이제 컨트롤을 빌드 후 필요한 페이지에서 컨트롤을 끌어다 놓으면 디자인타임에 표시할 HTMl을 확인할 수 있습니다.

 

 

컨트롤을 작성할 시에 사용자로 부터 입력될 값은 속성을 통해 받을 수 있는데 이 속성의 특성에 따라 전용 편집기를 호출하여 속성값의 입력을 좀더 비주얼적으로 처리할 수 있습니다.

 

public string Url
{
    get
    {
        String s = (String)ViewState["Url"];
        return ((s == null) ? String.Empty : s);
    }

    set
    {
        ViewState["Url"] = value;
    }
}

 

예를 들어 위와 같이 Url 입력이 필요한 속성을 정의하였다면

 

[Editor(typeof(UrlEditor), typeof(UITypeEditor))]

 

해당 속성의 특성을 위와 같이 정의하여 Url입력에 필요한 입력상자를 호출할 수 있도록 처리할 수 있습니다.

0 0
1
블로그 이미지

클리엘