천객만래 [千客萬來] (It has an interminable succession of visitors)

'ASP.NET'에 해당되는 글 103건

  1. 2016.11.23 [asp.net] The compiler failed with error code 128
  2. 2016.01.25 insert 시 null값에 관한 질문입니다
  3. 2016.01.25 ADO.NET: 데이터베이스 트랜잭션 사용 (asp.net)
  4. 2015.06.01 [개발/asp.net] UserControl 템플릿을 이용한 공통 UI 렌더링
  5. 2015.03.31 [개발/mysql] MySQL 5 C# sample code using ObjectDataSources
  6. 2015.03.17 [개발/ASP.NET] ASP.NET Life Cycle
  7. 2015.03.03 [개발/C#/ASP.NET] 하드웨어 유일키 생성
  8. 2015.03.03 [개발/ASP.NET/C#] 하드웨어 유일키 얻기 2
  9. 2015.03.03 [개발/asp] ASP용 이미지 리사이즈 프로그램 DLL과 소스프로그램
  10. 2015.02.24 [개발/ASP] Creating GridView Columns Dynamically (Part 1)
  11. 2015.02.24 [개발/ASP] Creating GridView Columns Dynamically (Part 1, 2) 소스코드
  12. 2015.02.24 [개발/ASP] Creating GridView Columns Dynamically (Part 2)
  13. 2015.02.03 [개발] 에러메시지 : Unable to start debugging on the web server
  14. 2015.01.29 [개발/웹] 웹에서의 비동기 호출 : 고전적인 방식(FRAME 이용)
  15. 2015.01.26 [ASP.NET] .NET Framework으로 웹 차트 및 그래프를 동적으로 생성
  16. 2015.01.22 [ASP.NET] [GDI+] LineChart 그래프를 만들어보자. (ASP.NET using C#)
  17. 2013.03.26 [개발/VS] 비주얼스튜디오2005 단축키 모음
  18. 2010.12.10 [개발/asp.net] 금액, 숫자를 문자로 바꾸기
  19. 2010.12.10 [개발/asp.net] 사용자의 인터넷익스플로러 창 모두 닫기
  20. 2010.12.10 [개발/asp.net] 파일이름으로 응용 프로그램 시작하기

[asp.net] The compiler failed with error code 128



Server Error in '/net' Application.
--------------------------------------------------------------------------------

Compilation Error
Description: An error occurred during the compilation of a resource required to service this request. Please review the following specific error details and modify your source code appropriately. 

Compiler Error Message: The compiler failed with error code 128.

Show Detailed Compiler Output:

C:\WINNT\system32> "C:\WINNT\Microsoft.NET\Framework\v2.0.50727\csc.exe" /t:library /utf8output /R:"C:\WINNT\assembly\GAC_32\System.Data\2.0.0.0__b77a5c561934e089\System.Data.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System.Web.Services\2.0.0.0__b03f5f7f11d50a3a\System.Web.Services.dll" /R:"C:\WINNT\assembly\GAC_32\System.Web\2.0.0.0__b03f5f7f11d50a3a\System.Web.dll" /R:"C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\net\25abbb5f\59ac6f1f\assembly\dl3\d9f2321a\8c67f30e_f8a3c601\App_Web_sl75aj7z.DLL" /R:"C:\WINNT\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System.Configuration\2.0.0.0__b03f5f7f11d50a3a\System.Configuration.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System.Drawing\2.0.0.0__b03f5f7f11d50a3a\System.Drawing.dll" /R:"C:\WINNT\assembly\GAC_MSIL\System.Web.Mobile\2.0.0.0__b03f5f7f11d50a3a\System.Web.Mobile.dll" /R:"C:\WINNT\assembly\GAC_32\System.EnterpriseServices\2.0.0.0__b03f5f7f11d50a3a\System.EnterpriseServices.dll" /out:"C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\net\25abbb5f\59ac6f1f\App_Web_default.aspx.cdcab7d2.d9t21czt.dll" /D:DEBUG /debug+ /optimize- /w:4 /nowarn:1659;1699  "C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\net\25abbb5f\59ac6f1f\App_Web_default.aspx.cdcab7d2.d9t21czt.0.cs" "C:\WINNT\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\net\25abbb5f\59ac6f1f\App_Web_default.aspx.cdcab7d2.d9t21czt.1.cs"



-------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:2.0.50727.42; ASP.NET Version:2.0.50727.42 

CAUSE
This problem occurs when a third-party component is running in the W3wp.exe process that has attached a console to the process. The Vbc.exe compiler process and the Csc.exe compiler process then inherit this console. If the console uses a windowstation that does not contain a desktop named DEFAULT, this may cause the compiler processes, or any other process that is spawned from the W3wp.exe process that depends on the User32.dll file, not to start. 

RESOLUTION
To resolve this problem, apply the hotfix in the following Microsoft Knowledge Base article:
839229  Multiple Web-based programs or Component Object Model-based programs stop responding on a computer that is running Windows Server 2003 or Windows 2000 
Note This hotfix is also included in Microsoft Windows Server 2003 Service Pack 1 (SP1).

CAUSE
This problem occurs because the worker process that tries to start the Microsoft ASP.NET compiler process is running under the Network Service identity or under an account that is not in the Administrators group. When the ASP.NET compiler process tries to start Vbc.exe or Csc.exe, the process initialization routine fails. This failure occurs because a dependent DLL fails during its initialization routine. If any of the DLLs for a process return a failure in their initialization routine, the operating system stops the process startup and returns an error code of 128 (ERROR_WAIT_NO_CHILDREN).

RESOLUTION
To resolve this problem, use either of the following methods. Use the method that fits your situation the best. 

Method 1: Prevent the World Wide Web Publishing Service from interacting with the desktop
You can prevent the World Wide Web Publishing Service from interacting with the desktop. This is the preferred method. 

Note By default, the World Wide Web Publishing Service is not configured to interact with the desktop. 

To do this, follow these steps: 
1. Click Start, click Run, type cmd, and then click OK. 
2. At the command prompt, type control admintools, and then press ENTER. 
3. Double-click Services. 
4. In the Services pane, locate World Wide Web Publishing Service. 
5. Right-click World Wide Web Publishing Service, and then click Properties. 
6. Click the Log On tab. 
7. Click to clear the Allow service to interact with desktop check box. 
8. Click OK. 

Method 2: Change the application pool identity to the Local System identity
Warning This workaround may make your computer or your network more vulnerable to attack by malicious users or by malicious software such as viruses. We do not recommend this workaround but are providing this information so that you can implement this workaround at your own discretion. Use this workaround at your own risk.

You can change the application pool identity to the Local System identity. 

Important You should only use this method if the following conditions are true: 
• The ASP.NET Web application must interact with the desktop. 
• You understand the security implications of changing the application pool identity to the Local System identity. For more information about the Local System account and the Network Service account, see the "Applications as NT Services" section at the following Microsoft Developer Network (MSDN) Web site: 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnentsrv/html/netenterpriseandcomplus.asp
To do this, follow these steps: 
1. Click Start, click Run, type cmd, and then click OK. 
2. At the command prompt, type control admintools, and then press ENTER. 
3. Double-click Internet Information Services (IIS) Manager. 
4. Expand the computer name, expand Application Pools, right-click the name of the application pool that you want to modify, and then click Properties. 
5. Click the Identity tab. 
6. Click Predefined, and then click Local System. 
7. Click OK. 

Method3:ran the the aspnet_regiis.exe and it solved my problem

C:\WINNT\Microsoft.NET\Framework\version\aspnet_regiis.exe -i 


MORE INFORMATION
ASP.NET does not try to compile a page after an error is encountered during the compilation process. The error is cached until the process is recycled, or until the page or one of its dependencies is modified. When the worker process is tied to the console windowstation (Winsta0), the World Wide Web Publishing Service adds the security identifier (SID) for the IIS_WPG group to the access control list (ACL) for the Winsta0 object. Then, the World Wide Web Publishing Service starts the W3wp.exe process.

When a user logs on to or off a console session, the Winlogon process rebuilds the ACL for the Winsta0 object and removes the IIS_WPG SID from the ACL. Any child processes that are started by the worker process (W3wp.exe) may not start. These processes include the Csc.exe and Vbc.exe processes. 

When a service is not configured to interact with the desktop, the process uses a non-interactive windowstation that is unaffected by a user logging on to the console.

Note You can log on to the console in Windows Server 2003 by any one of the following methods: 
• Log on to the computer interactively. 
• Use the Remote Desktop client application. For example, type mstsc.exe /console at a command prompt.  
• Use a third-party application that accesses the console session.


Posted by SB패밀리

insert 시 null값에 관한 질문입니다




[질문] insert 시 null값에 관한 질문입니다.. 좀 알려주세요..ㅡ.ㅡ;;


input 폼에서 데이타를 받아서 insert.aspx.cs에서 저장 프로시저를 이용해 데이타를 저장하려고 하는데..

input 폼중 radio 에서 하나로 선택을 하지 않으면 nullException 어쩌구 하면서 에러가 발생합니다..

이값이 null 이 될수도 있는데.. ""(값이 없이) 저장을 하려면 어떻게 해야 하나요?? 

if(rb_Ma.SelectedItem.Value==null)
{
  Cmd.Parameters["@ma"].Value="";
}
else
{
  Cmd.Parameters["@ma"].Value=rb_Ma.SelectedItem.Value;
}

혹시나 해서 이처럼 해 보았는데.. 역시나 에러가 발생하는군요..
이것은 "" 으로 저장을 하려면 어떻게 해야 하는지 좀 알려주시면 감사하겟습니다..

디비에서 데이타 형은 char(1) 입니다..

그리고 하나만 더.. ^^;;

Cmd.Parameters.Add("@email",SqlDbType.NVarChar,100);
Cmd.Parameters["@email"].Value=tb_Email.Text;

이메일을 받아서 저장을 하면 데이타 타입이 맞지 않다면서 에러가 발생하고 있습니다..
(tb_Email 에 aaa@aaa.com 으로 입력시..)

그래서 다른 문자를 입력(aaa.aaa.com) 으로 해 보았더니 정상적으로 입력이 되더군요..

저장 프로시저를 이용해 저장할때 그 데이타에 @ 가 오면 저장이 안 되나요??
아닌것 같은데..

이것도 좀 알려주시면 감사하겠습니다..^^;;
그럼 좋은 하루 보내시기 바랍니다..




[답변]


Cmd.Parameters["@ma"].Value=DbNull.Value; 일케 해보세요





Posted by SB패밀리

ADO.NET: 데이터베이스 트랜잭션 사용

출처: 인터넷



ADO.NET: 데이터베이스 트랜잭션 사용

데이터베이스 트랜잭션은 데이터베이스에 대한 데이터 커밋을 제어하는 데 사용됩니다. 예를 들어, 표준 계좌 프로시저의 경우에는 입출금 계좌에서 동시에 입출금이 발생해야 합니다. 하지만 정전이나 네트워크 오류 등으로 인해 컴퓨터가 중단될 경우, 한 레코드만 업데이트되거나 추가될 가능성이 있습니다. 이러한 상황을 방지하기 위해 트랜잭션이 사용됩니다. ADO.NET의 트랜잭션은 ADO에서처럼 데이터베이스 수준에서 처리되므로 데이터베이스에서 트랜잭션을 지원해야 합니다.

트랜잭션에 대한 세 가지 기본 명령에는 BeginTransactionCommit 및 Rollback이 있습니다. BeginTransaction은 트랜잭션 시작을 표시합니다. BeginTransaction과 다음 명령인 Rollback 또는 Commit 사이에 발생되는 모든 것은 트랜잭션의 일부로 간주됩니다. 다음 코드 예제에서는 트랜잭션을 사용하는 방법을 보여 줍니다.

 

 

 

SqlConnection myConnection = new SqlConnection("server=(local)\\VSdotNET;Trusted_Connection=yes;database=northwind");
    SqlCommand myCommand = new SqlCommand();
  

  SqlTransaction myTrans;
    
    // Open the connection.
    myConnection.Open();
    
    // Assign the connection property.
    myCommand.Connection  = myConnection;
    
    // Begin the transaction.
    myTrans = myConnection.BeginTransaction();
    
    // Assign transaction object for a pending local transaction
    myCommand.Transaction = myTrans;
    
    try
    {
      // Restore database to near its original condition so sample will work correctly.
      myCommand.CommandText = "DELETE FROM Region WHERE (RegionID = 100) OR (RegionID = 101)";
      myCommand.ExecuteNonQuery();
    
      // Insert the first record.
      myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (100, 'MidWestern')";
      myCommand.ExecuteNonQuery();
    
      // Insert the second record.
      myCommand.CommandText = "Insert into Region (RegionID, RegionDescription) VALUES (101, 'MidEastern')";
      myCommand.ExecuteNonQuery();
    
      myTrans.Commit();
      Console.WriteLine("Both Records are written to the database!");
    }
    catch(Exception e)
    {
      myTrans.Rollback();
      Console.WriteLine(e.ToString());
      Console.WriteLine("Neither record is written to the database!");
    }
    finally
    {
      myConnection.Close();
    }

Posted by SB패밀리

출처: http://www.taeyo.pe.kr/lecture/NET/UcTemplate.asp

강좌 최초 작성일 : 2006년 11월 14일
   강좌 최종 수정일 : 2006년 11월 15일

   강좌 읽음 수 : 4359 회

   작성자 : Taeyo(김 태영)
   편집자 : Taeyo(김 태영)

   강좌 제목 : UserControl 템플릿을 이용한 공통 UI 렌더링 

강좌 전 태오의 잡담>

이제 2006년의 크리스마스도 한달 정도밖에 남지 않았네요.
여러분들은 크리스마스에 무엇을 하실 생각이신가요?
무엇을 계획하던 한 해를 잘 정리하면서~ 즐겁게 보내시기 바랍니다.


공통적으로 자주 사용하는 UI 영역을 필요로 할 경우 여러분은 주로 어떻게 작업을 해 오셨나요? 대부분의 경우는 그 영역을 User Control이나 Custom Control로 제작해서 사용해 오셨을 것입니다. "나는 둘 다 아니었다!!"라고 자신하시는 분은 좋았어!! 패스!! -_-+

대개의 경우는 User Control을 이용했을텐데요. 이는 User Control의 개발이 상당히 쉽기 때문일 것입니다. Custom Control의 경우는 개발에 적지 않은 내공과 시간이 요구되기에 쉽사리 덤벼들 수 없지만, User Control은 기존에 존재하는 컨트롤들을 복합적으로 묶어서 쉽게 출력 영역을 꾸밀 수 있으니까요.

이번 강좌에서 하고자 하는 이야기는 바로 이러한 User Control을 사용함에 있어서, UI 개발자들이 좀 더 손쉽게 이를 다룰 수 있게, 그리고 이를 일종의 템플릿처럼 이용할 수 있게 하는 작은 기반을 만드는 방법에 대한 것입니다. 반드시 필요한 작업은 아닐 수 있지만, 일단 작성해두면 전반적인 개발이 편리해진다고나 할까요? 개발 생산성 및 유지 보수성이 좋아지는 방안이라고 보시면 될 듯 합니다.

제가 업무 프로젝트에서 하는 역할이 주로 아키텍처를 잡는다거나, 공통 모듈을 설계 및 가이드 한다거나, 개발자들의 개발 생산성을 높이기 위한 프레임워크 작업을 한다거나 하는 작업이다보니 이러한 쪽에 대한 관심이 본의 아니게 생길 수 밖에 없더군요(실은, 업체의 개발표준팀에서 그런 것들을 요구해 오거든요. 이런 게 있으면 편할 것 같은데 만들어 주세요. 이것 좀 자동화할 수 있는 도구가 있었으면 좋겠어요. 등등 -_-+).

아! 그러니깐, 정확히 이번 강좌가 어떤 내용을 다루는지 감이 잘 오지 않으신다구요? 그렇다면, 좀 더 구체적으로 말씀을 드려야 할 듯 하네요. 이번 강좌의 주 내용은 화면에 공통적으로 사용되는 출력 영력을 User Control로 만들고 이를 동적으로 손쉽게 페이지에 끼워넣을 수 있게 하려 합니다.

"설마, Page.LoadControl() 메서드를 이용해서 페이지에 동적으로 User Control을 넣자는 이야기를 하려는 것은 아니겠죠?" 라고 하시는 분들이 계시는데요. 다행히도 그 이야기는 아닙니다(엄밀히 말하면, 일부는 맞기도 합니다만 -_-). Page.LoadControl() 메서드를 이용해서 페이지에 동적으로 User Control을 추가하는 것은 User Control의 출력 데이터가 정적인 경우에 한해 부합할 것입니다. 만일, User Control이 Repeater나 DataList 등의 컨트롤로 구성되어 있고(예를 들면, 공지사항 목록 같은), 데이터 바인딩이 된 상태로 Page에 추가되어야 한다면 어떻게 할까요?

"뭡니까? 장난하십니까? 그럼 User Control안에서(예를 들면, Control의 Page_Load 이벤트) 데이터 바인딩 작업을 하면 되잖아요"라고 이야기하시는 분들 계십니다. 핫!!! 맞는 말씀입니다. 그런 방법이 있었군요. 음… 그렇네요.. 흠… 그렇구나…

그렇습니다. 일반적으로는 그렇게들 작업을 하셨을 것입니다. 물론, 공지사항 목록의 출력 같은 경우는 공통적으로 여기 저기에서 자주 사용되기에 분명 User Control(혹은 별도의 컨트롤)로 만들어서 사용하는 것이 이로울 것입니다. 그리고, 그 경우 대부분 데이터 액세스 하는 코드가 .ascx 파일 안에 담기게 되곤 하죠. N-Tier 작업을 많이 해보신 분들이라면 Business Logic 레이어와 Presentation 레이어를 명확하게 구분하여 작업을 하셨을 것입니다. 그렇기에 물론, 이와 같은 경우라 해도, ascx 파일 안에 데이터를 직접적으로 액세스 하는 코드는 작성하지 않을 것입니다. 다만, 비즈니스 로직 컴포넌트(BLC)나 데이터 액세스 컴포넌트(DAC)를 호출하여 얻어온 결과를 바인딩 하는 코드 정도만이 놓여져 있겠죠? 요는 어쨌든 그러한 코드가 있기는 있어야만 한다는 것입니다. 그렇기에, 그 User Control은 오로지 공지사항을 출력하기 위한 "공지사항 용 User Control"이란 이름을 갖게 될 것입니다. 왜냐하면, 그러한 목적으로 User Control을 꾸민 것이니까요.

하지만, User Control을 작성하다 보면, 출력하는 데이터만 다를 뿐이지, 그 출력 유형이 매우 유사한 경우를 많이 접하게 됩니다. 바로 여기서 한 가지 아이디어가 뾰료롱 생겨납니다. User Control을 템플릿처럼 사용할 수는 없을까? 즉, 공지사항 데이터던 주소 목록 데이터던 데이터를 던져주면 목록을 출력하는 User Control을 만들어두면 개발 생산성이 더 나아지지 않을까? 하는 생각이 들 수 있다는 것이죠. 바로 그것이 이번 강좌에서 이야기하고자 하는 내용입니다.

전용 User Control(공지사항용 컨트롤, 공통 데이터 출력용 컨트롤 등 특정 데이터를 출력하기 위해 작성한 컨트롤)을 작성하는 것이 나쁘다는 이야기는 아닙니다. 그는 매우 일반적인 방법이니까요. 다만, 상황에 따라서는 이를 좀 더 생산성이 높은 방향으로 바꿔보는 것도 나쁘지 않다는 생각입니다(생산성은 좋아지는 반면, 성능적으로는 약간의 희생이 따를 수 있습니다). 즉, 별도의 컨트롤러 클래스가 있어서 그가 동적으로 User Control에 데이터를 채우고 바인딩을 하도록 하자는 것이죠. 이런 식으로 구성하게 되면, ascx는 단지 출력을 위한 코드만을 담게되어 매우 간결해지며, ascx를 일종의 화면 템플릿 격으로 사용할 수 있게 됩니다.

예를 들면, 다음은 제가 작성해 본 공지사항 User Control(View.ascx)의 소스 코드 전체입니다.

View.ascx

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="View.ascx.cs" Inherits="Template_View" %>
<asp:DataList ID="DataList1" runat="server">
    <ItemTemplate>
        <%# Eval("title") %>
    </ItemTemplate>
</asp:DataList>

View.ascx.cs

public partial class Template_View : System.Web.UI.UserControl
{
    private object _data;
    public object Data
    {
        get { return _data; }
        set { _data = value; }
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        DataList1.DataSource = Data;
        DataList1.DataBind();
    }
}

보시다시피, User Control에는 데이터 바인딩 코드 외에는 아무것도 존재하지 않습니다. 바인딩을 위한 데이터를 가져오는 코드도 존재하지 않습니다. 이는 외부 컨트롤러 클래스가 동적으로 데이터를 밀어넣도록 할 것이기 때문입니다.

이 방식의 장점은 화면 개발자가 User Control의 HTML 구역에만 집중해서 작업을 할 수 있다는 것입니다. 내부적으로 데이터가 어떻게 바인딩되는지 어쩌는지 전혀 관심을 갖지 않아도 됩니다. 화면의 디자인만을 생각하면 되기에 이 User Control을 일종의 템플릿처럼 이를 사용할 수 있다는 것이죠. 주어지는 데이터가 어떤 것이냐에 따라 공지사항을 출력할 수도 있고, 다른 목록 데이터들을 출력할 수도 있습니다.

결과적으로, 이는 동일한 결과를 얻기 위한 또 다른 방식(개발 생산성을 높이는 방식)입니다. 하지만, 그렇다고 이 방식이 꼭 옳다고 말할 수는 없습니다. 제가 진행하는 프로젝트에서는 이를 이용하여 개발성 향상과 유지 보수성의 향상이 있었습니다만, 여러분의 상황에서는 오히려 번잡스럽고 어렵게 느껴질 수도 있습니다. 그러니, 끝까지 잘 살펴보시고 판단하시기 바랍니다. 그러나, 이를 여러분의 업무에 적용하지는 않는다 하더라도, 컨셉 정도는 느껴보시기를 권해 봅니다.

사실, 이 컨셉은 ASP.NET의 대부인 Scott Guthrie의 블로그에 올라온 "Cool UI Templating Technique to use with ASP.NET AJAX for non-UpdatePanel scenarios"란 글에서 힌트를 얻어 작성한 것입니다. 해서, 사실 이 컨셉은 Ajax 애플리케이션을 제작할 경우에 더 적절하다고 보여집니다.

 http://weblogs.asp.net/scottgu/archive/2006/10/22/Tip_2F00_Trick_3A00_-Cool-UI-Templating-Technique-to-use-with-ASP.NET-AJAX-for-non_2D00_UpdatePanel-scenarios.aspx

자. 그렇다면, 전체적인 구현 설계를 살펴보고, 실제 구현을 한번 해보도록 하겠습니다.



TitlesManager란 클래스는 pubs 데이터베이스의 titles 테이블에서 책 데이터(DataTable)를 가져오는 역할을 수행하며, ViewManager를 이용하여 얻어온 데이터를 User Control에 바인딩한 뒤, 이를 반환하는 메서드를 제공하는 클래스입니다. 설명만으로는 이해가 어려울 수 있지만, 잠시 뒤에 소스 코드를 보시면 이해가 되실 것입니다. 사실, TitlesManager 클래스를 별도로 제작할 필요는 없습니다만(그냥 aspx 페이지에 코드를 넣어도 동작하는 데에는 문제가 없으니), 논리적으로 역할 구분을 하는 것이 설계적으로 좋아보이기에 별도의 클래스로 작성해 보았습니다.

ViewManager의 역할은 이 컨셉에서 매우 중요하지만, 그 내용은 의외로 간단합니다. 특정 ascx 컨트롤의 속성에 동적으로 데이터(TitlesManager가 넘겨주는 책 목록 데이터-DataTable)를 추가한 뒤, 그를 바인딩한 User Control을 반환하는 역할을 제공하는 것입니다. 기본 예제에서는 동적으로 User Control에 데이터를 건네주기 위해서 리플렉션 기술을 이용하고 있지만, 이는 차후 인터페이스를 이용하는 방식으로 바꾸어 성능적인 향상을 꾀할 수도 있을 것입니다.

어렵다구요? 말로만 설명하면 복잡한 감이 없지 않으니 직접 소스를 보면서 이해해 보도록 하시죠. 우선 TitlesManager.cs 클래스부터 살펴보도록 하겠습니다.

TitlesManager.cs

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

/// <summary>
/// TitlesManager의 요약 설명입니다.
/// </summary>
public class TitlesManager
{
    private DataTable GetTitles()
    {
        SqlConnection con = new SqlConnection();
        con.ConnectionString = "server=(local);database=pubs;uid=**;pwd=**";
        string sql = "Select title from Titles";
        SqlCommand cmd = new SqlCommand(sql, con);
        SqlDataAdapter adapter = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();

        adapter.Fill(ds);
        return ds.Tables[0];
    }

    public UserControl GetTitlesRenderControl()
    {
        DataTable titles = this.GetTitles();

        if (titles.Rows.Count > 0)
            return ViewManager.GetViewControl("~/Template/View.ascx", titles);
        else
            return ViewManager.GetViewControl("~/Template/NoView.ascx", null);
    }
}

TitlesManager 클래스는 우선 GetTitles()라는 메서드를 가지고 있습니다. 이는 데이터베이스로부터 책 목록 데이터를 가져와서 그를 DataTable 형식으로 반환하는 메서드입니다. n-Tier 구조로 설계되었다면, 사실상 이 메서드는 TitlesManager 클래스가 아닌 Data Access Component 쪽에 놓여져야 하겠습니다만, 여기서는 데모의 목적으로 코드를 여기에 직접 작성해 보았습니다. 만일, 여러분의 프로젝트에 개발 프레임워크가 도입되어 있고, 이미 Business Logic 계층과 Data Access 계층이 존재한다면 이 메서드는 그 안쪽에 작성되어야 할 것입니다.

TitlesManager 클래스의 핵심 메서드는 사실 GetTitlesRenderControl() 입니다. 이 메서드가 바로 ViewManager 클래스를 사용해서! 동적으로 필요한 User Control을 얻어내는 메서드이니까요. 해서, 소스를 보시면 이는 우선 GetTitles() 메서드를 이용해서 필요한 DataTable을 얻어내고 있으며, 그 가져온 데이터가 존재한다면(한 개 이상의 Row를 가진다면) View.ascx란 템플릿을, 데이터가 존재하지 않는다면 NoView.ascx란 템플릿을 동적으로 얻어와 반환하는 것을 볼 수 있습니다(View.ascx란 템플릿을 사용하는 경우에는 바인딩 데이터를 필요로 하므로, DataTable 개체를 인자로 넘겨주어야 합니다).

대략적인 TitlesManager 클래스의 역할이 이해가 되시나요? 그렇습니다. 별 것 없습니다. 쿼리 결과 데이터가 존재하면 View.ascx를, 데이터가 없으면 NoView.ascx를 얻어오는 ViewManager 클래스의 GetViewControl 메서드를 호출하는 것이 전부이니까요.

그렇기에, 여기서 중요한 것은 무엇보다도 ViewManager.GetViewControl() 라는 것을 여러분은 번쩍! 눈치 채셨을 것입니다. 실제로 ascx 템플릿과 주어진 데이터를 이용해 동적으로 User Control을 생성하는 핵심 역할을 하는 친구가 바로 ViewManager.GetViewControl()이니까요. 그렇다면, 이제 ViewManager 클래스의 코드를 한번 살펴보도록 하겠습니다.

ViewManager.cs

using System;
using System.Web;
using System.Web.UI;
using System.IO;
using System.Reflection;

public class ViewManager
{
    public static UserControl GetViewControl(string path, object data)
    {
        Page page = new Page();
        UserControl viewControl = (UserControl) page.LoadControl(path);

        if (data != null)
        {
            Type viewControlType = viewControl.GetType();
            PropertyInfo prop = viewControlType.GetProperty("Data");

            if (prop != null)
            {
                prop.SetValue(viewControl, data, null);
            }
            else
            {
                throw new Exception(path + "는 Data 속성을 가지고 있지 않습니다");
            }
        }

        return viewControl;
    }
}

ViewManager 클래스의 핵심은 GetViewControl라는 메서드입니다. 이는 주어진 ascx 파일명과 바인딩 데이터를 인자로 받아서 그를 이용해 동적으로 User Control을 생성하는 역할을 합니다. 해서, 처음 두 줄의 코드는 일단 지정된 경로의 ascx 파일을 User Control로 얻어내는 작업을 수행하고 있어요.

Page page = new Page();
UserControl viewControl = (UserControl) page.LoadControl(path);

만일, 이렇게 얻어온 User Control이 정적인 데이터만을 가진다면, 현재의 viewControl 개체를 그대로 반환해도 무관하겠지만, 고작 그런 작업을 하려했다면 굳이 이렇게 복잡하게 ViewManager를 제작할 필요조차 없었을 겁니다. ViewManager가 필요한 이유는 바로 동적으로 User Control의 속성을 설정할 필요가 있기 때문이니까요.

코드는 page.LoadControl() 메서드를 이용해서 UserControl 개체를 얻어오긴 했으나, 문제는 이 상태로는 해당 UserControl이 Data 라는 속성을 갖는지 어떤지 알 수가 없다는 것입니다. UserControl 형식의 .NET 클래스는 Data라는 필드를 기본적으로 가지고 있지 않으니까요.

하지만, 우리가 동적으로 로드하고자 하는 View.ascx 는 분명 Data라는 공개 속성을 가지고 있습니다. 그렇다면, 어떻게 프로그래밍적으로 이 개체의 Data 필드를 접근할 수 있을까요?

우리가 위에서 작성해놓은(위에서 소스를 보여드렸었죠?) View.ascx의 소스를 다시금 살펴보면 그는 Data라는 object 형식의 속성을 가지고 있음을 알 수 있습니다. 그리고, 컨트롤의 Page_Load 이벤트 시에는 그 Data를 가지고 데이터 바인딩을 시도함을 알 수 있죠. 이는 우리끼리 사전 정의해 놓은 규칙입니다. 즉,

"모든 ascx 템플릿들은 Data라는 공개 속성을 가지며, 데이터 바인딩은 그 데이터를 가지고 이루어진다"

가 우리끼리 약속해놓은 규칙이라는 것이죠. 다시 말해서, 우리가 템플릿으로 이용할 모든 ascx들은 Data라는 공개 속성을 가져야만 합니다. 현실적으로 이야기하자면, 이 규칙은 프로젝트의 클래스 설계 표준문서에 기록되어 있어야 할 것이고, 개발자들에게 사전에 숙지시켜야만 하는 부분이어야 할 것입니다.

그렇습니다. 방법은 크게 두 가지가 있습니다. 하나는 Data라는 속성을 갖는 인터페이스를 작성해서 View.ascx 클래스가 그 인터페이스(예를 들면, IcommonUC란 이름으로)를 구현하도록 하고, 다음과 같이 코드를 작성하는 방법이 있겠죠?

Page page = new Page();
ICommonUC viewControl = (ICommonUC)page.LoadControl(path);

사실, 이 방법이 제가 강좌에서 설명하려는 리플렉션 방법보다 훨씬 더 효과적인 방법임에는 틀림이 없습니다. 인터페이스를 사용한다면 위의 GetViewControl() 메서드도 다음과 같이 매우!! 간단해질 수 있을테니까요.

public static UserControl GetViewControlwInterface(string path, object data)
{
    Page page = new Page();
    UserControl ctl = (UserControl)page.LoadControl(path);
    ICommonUC viewControl = ctl as ICommonUC;

    if(viewControl != null)
        viewControl.Data = data;

    return ctl;
}
// 요 부분 코드는 유 경상 수석이 간섭했다는 후문이 돌고 있습니다.

사실, 결과론적으로는 상기와 같이 인터페이스를 사용하는 것을 강력히 추천합니다. 하지만, 이 강좌는 리플렉션을 이용해서 속성을 설정하는 내용을 보여드리고 있습니다. 다시 보여드리자면,

Type viewControlType = viewControl.GetType();
PropertyInfo prop = viewControlType.GetProperty("Data");

if (prop != null)
{
    prop.SetValue(viewControl, data, null);
}

가 바로 그러한 코드이죠. 리플렉션을 이용해서 현재 개체 형식이 Data라는 속성을 갖는지 여부를 검사하고, 만일 해당 속성이 존재한다면 그 속성에 데이터(우리의 경우 책 목록 DataTable)을 밀어넣는 것입니다.

리플렉션을 이용하는 방식은 성능적으로 그다지 좋지 않기에 크게 권장하지는 않습니다만, 제가 참고한 원래의 포스트 글이 이 방식을 사용했기에 저도 이 방식으로 글을 작성했습니다. 개인적으로는 리플렉션보다는 인터페이스를 사용하는 쪽을 권장하고 싶습니다. ^^;

자. 이제 TitlesManager와 ViewManager가 모두 완성되었네요. ViewManager는 다른 곳에서도 두고두고 재사용이 가능한 독립적인 모듈입니다. 만일, 여러분이 책 목록이 아닌 고객 데이터 목록을 다루고 싶다면, CustomerManager와 같은 클래스를 만들고 (코드는 TitlesManager와 유사하겠죠?) 내부적으로 ViewManager를 사용하시면 될 것입니다. ^^

자. 그럼 이제 이를 이용하는 ASPX 페이지를 만들어봐야 겠죠? 저는 default.aspx 페이지에 Label 컨트롤을 하나 올려놓고(굳이 Label일 이유는 없지만), 코드 비하인드에는 다음과 같이 코드를 작성해 보았습니다.

default.aspx.cs

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        UserControl ctl = (new TitlesManager()).GetTitlesRenderControl();
        lblData.Controls.Add(ctl);
    }
}

간단하죠? 다음은 전체 소스가 동작하여 나온 결과화면입니다.(저는 약간의 디자인을 입혀봤습니다. 그래봐야 큰 차이는 없지만 -_-)



나름대로 멋지지 않나요? ㅎㅎ

이것이 이번 강좌에서 전하고 싶었던 내용입니다. 사실, 제대로 이해하려면 전체 소스를 한번 돌려보고 디버깅 잡고, 소스를 따라가면서 확인하는게 더 좋긴 하죠. 해서, 강좌 하단에서는 전체 소스를 다운로드 할 수 있도록 준비해 두었습니다. 전체적으로 돌아가는 방식을 확인하시고 나면 이 방식이 맘에 드시는 분들도 조금 있지 않을까 생각해 봅니다.

그리고, 추가적으로 ViewManager 클래스를 보면 User Control을 직접적으로 반환하지 않고, 그 User Control의 내용을 HTML 문자열로 렌더하여 반환하는 메서드도 들어있는 것을 보실 수 있을 것입니다. ASP.NET 애플리케이션에서는 이 메서드가 그다지 유용하지 않을 수 있지만, AJAX 애플리케이션을 개발한다면 나름대로 쓸만하다고 할 수 있습니다. 그 메서드를 웹 서비스의 메서드로 빼 놓으면, 클라이언트 측에서 손쉽게 목록 데이트 출력을 얻어와 화면에 반영할 수 있을테니까요 ^^;

그리 어려운 내용은 아닌데, 제가 설명을 간결하게 하지 못해서 오히려 여러분을 어렵게 만든 것은 아닌지 걱정됩니다. 하지만, 맘에는 드셨죠?



UcTemplate.zip





Posted by SB패밀리


MySQL 5 C# sample code using ObjectDataSources



Introduction

I created this example because I could not find a simple explanation for using MySQL 5 with ObjectDataSources in ASP.NET 2.0.

Let me say, I am really impressed with MySQL. I was able to install it easily on my Windows XP machine and get it running in about an hour. I am a long time MS SQL user, and was very frustrated with trying to use Oracle and Firebird. I realize, the problem is that I am spoiled from MS SQL Server, but hey I''m busy and I like easy to use tools :)

If you''re getting started with MySQL and ASP.NET, then I recommend these steps:

  1. Go to the MySQL website, download and install “Current Release (recommended).
  2. Download and install: MySQL Administrator (to administer your MySQL server, the first download just installs only the server).
  3. Download and install: Connector/Net 1.0 (you need this to get your ASP.NET pages to talk to your MySQL server).
  4. You can also download: MySQL Query Browser – (a graphical client to work with your MySQL databases and run queries).
  5. Read and follow this guide: A Step-by-Step Guide to Using MySQL with ASP.NET.

Using the code

To install the code:

  1. You must have MySQL 5 up and running.
  2. Install MySQL Connector/Net 1.0.
  3. Create a MySQL 5 database named Test.
  4. Create a table in that database called Message:
    CREATE TABLE test.message (
    
        Entry_ID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
        Name VARCHAR(45),
        Email VARCHAR(45),
        Message VARCHAR(200),
        PRIMARY KEY (Entry_ID)
        )
        AUTO_INCREMENT=32
        CHARACTER SET latin1 COLLATE latin1_swedish_ci;
  5. Create these four MySQL stored procedures in the Test database:
    PROCEDURE `test`.`DeleteMessage`(IN param1 INT)
    BEGIN
    Delete From test.message
    WHERE Entry_ID = param1;
    END
    PROCEDURE `test`.`InsertMessage`(IN param1 VARCHAR(50), IN param2 
        VARCHAR(50), IN param3 VARCHAR(200))
    BEGIN
    INSERT INTO message(Name, Email, Message)
    VALUES(param1,param2,param3);
    END
    PROCEDURE `test`.`ShowAll`()
    BEGIN
    SELECT 
      message.Entry_ID,
      message.Name, 
      message.Email, 
      message.Message
    FROM
      test.message;
    END
    PROCEDURE `test`.`UpdateMessage`(IN paramkey INT, IN param1 VARCHAR(50), 
        IN param2 VARCHAR(50), IN param3 VARCHAR(200))
    BEGIN
    UPDATE    message
    SET              Name = param1, Email = param2, Message = param3
    WHERE     (message.Entry_ID = paramkey);
    END
  6. Unzip "MySQL" and configure IIS to point to it. Make sure you configure the web server to use ASP.NET 2.0.
  7. Open "web.config" and change the line:
    <add name="MySQLConnectionString" connectionString="server=localhost; 
       user id=myuser; password=mypass; database=test; pooling=false;" 
       providerName="MySql.Data.MySqlClient"/>

    to connect to your MySQL database.

  8. Browse to the default.aspx page through IIS.

This is the class that uses Generics to supply the data that is consumed by the ObjectDataSource control:

using System;
using System.Collections.Generic;
using System.Data;
using MySql.Data.MySqlClient;
using System.Configuration;
using System.ComponentModel;

[DataObject(true)]
public static class MessagesDB
{
    private static string GetConnectionString()
    {
        return ConfigurationManager.ConnectionStrings
        ["MySQLConnectionString"].ConnectionString;
    }

    [DataObjectMethod(DataObjectMethodType.Select)]
    public static List<MessageItem> GetMessages()
    {
        MySqlCommand cmd = new MySqlCommand("ShowAll", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Connection.Open();
        MySqlDataReader dr = 
           cmd.ExecuteReader(CommandBehavior.CloseConnection);

        List<MessageItem> MessageItemlist = new List<MessageItem>();
        while (dr.Read())
        {
            MessageItem MessageItem = new MessageItem();
            MessageItem.Entry_ID = Convert.ToInt32(dr["Entry_ID"]);
            MessageItem.Message = Convert.ToString(dr["Message"]);
            MessageItem.Name = Convert.ToString(dr["Name"]);
            MessageItem.Email = Convert.ToString(dr["Email"]);
            MessageItemlist.Add(MessageItem);
        }
        dr.Close();
        return MessageItemlist;
    }

    [DataObjectMethod(DataObjectMethodType.Insert)]
    public static void InsertMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("InsertMessage", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Name));
        cmd.Parameters.Add(new MySqlParameter("param2", MessageItem.Email));
        cmd.Parameters.Add(new MySqlParameter("param3", MessageItem.Message));
        cmd.Connection.Open();
        cmd.ExecuteNonQuery();
        cmd.Connection.Close();
    }

    [DataObjectMethod(DataObjectMethodType.Update)]
    public static int UpdateMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("UpdateMessage", 
                           new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("paramkey", MessageItem.Entry_ID));
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Name));
        cmd.Parameters.Add(new MySqlParameter("param2", MessageItem.Email));
        cmd.Parameters.Add(new MySqlParameter("param3", MessageItem.Message));
        cmd.Connection.Open();
        int i = cmd.ExecuteNonQuery();
        cmd.Connection.Close();
        return i;
    }

    [DataObjectMethod(DataObjectMethodType.Delete)]
    public static int DeleteMessage(MessageItem MessageItem)
    {
        MySqlCommand cmd = new MySqlCommand("DeleteMessage", 
                new MySqlConnection(GetConnectionString()));
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add(new MySqlParameter("param1", MessageItem.Entry_ID));
        cmd.Connection.Open();
        int i = cmd.ExecuteNonQuery();
        cmd.Connection.Close();
        return i;
    }

The class above uses the class "MessageItem" to pass the parameters to and from the ObjectDataSource control:

using System;

public class MessageItem
{
    int _Entry_ID;
    string _Message;
    string _Name;
    string _Email;

    public MessageItem()
    {
    }

    public int Entry_ID
    {
        get
        {
        return _Entry_ID;
        }
        set
        {
        _Entry_ID = value;
        }
    }

    public string Message
    {
        get
        {
            return _Message;
        }
        set
        {
            _Message = value;
        }
    }

    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name = value;
        }
    }

    public string Email
    {
        get
        {
            return _Email;
        }
        set
        {
            _Email = value;
        }
    }
}

This is the .aspx file that contains the ObjectDataSource control as well as a GridView for editing data and a DetailsView for inserting a record:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
   TypeName="MessagesDB" OldValuesParameterFormatString="original_{0}" 
   SelectMethod="GetMessages" DataObjectTypeName="MessageItem" 
   DeleteMethod="DeleteMessage" InsertMethod="InsertMessage" 
   UpdateMethod="UpdateMessage">
</asp:ObjectDataSource>
<br />
<asp:GridView ID="GridView1" runat="server" 
      AutoGenerateColumns="False" 
      DataSourceID="ObjectDataSource1" 
      DataKeyNames="Entry_ID">
 <Columns>
   <asp:BoundField DataField="Entry_ID" HeaderText="Entry_ID" 
           SortExpression="Entry_ID" Visible="False" />
   <asp:CommandField ShowEditButton="True" />
   <asp:CommandField ShowDeleteButton="True" />
   <asp:BoundField DataField="Name" 
         HeaderText="Name" SortExpression="Name" />
   <asp:BoundField DataField="Email" 
         HeaderText="Email" SortExpression="Email" />
   <asp:BoundField DataField="Message" 
         HeaderText="Message" SortExpression="Message" />
 </Columns>
</asp:GridView>
<br />
<strong><span style="text-decoration: underline">
      Insert New Record:</span></strong><br />

<asp:DetailsView ID="DetailsView1" runat="server" 
    AutoGenerateRows="False" BorderStyle="None"
    CellSpacing="5" DataSourceID="ObjectDataSource1" 
    DefaultMode="Insert" GridLines="None"
    Height="50px" Width="300px">
  <Fields>
    <asp:BoundField DataField="Name" HeaderText="Name" />
    <asp:BoundField DataField="Email" HeaderText="Email" />
    <asp:BoundField DataField="Message" HeaderText="Message" />
    <asp:CommandField ButtonType="Button" 
         ShowInsertButton="True" ShowCancelButton="False" />
  </Fields>
</asp:DetailsView>

Note

The assembly "MySql.Data.dll" is in the "/bin" directory so the "MySql.Data.MySqlClient" will work.

I hope this helps!



MySQL_CS_samplesource.zip



Posted by SB패밀리

오래 전 회사에서 옆 직원의 책상에 붙여진 ASP.NET Life Cycle 을 보게 되었습니다.

그냥 무턱대고 개발만 했지, 진정으로 중요한 부분을 간과하고 넘어간게 아닌가 하는 생각이 들어서 유심히 바라보게 되었습니다.

 

Life Cycle을 보는 순간 답답하더군요. 모르는게 많구나....

물론 개발할 때 꼭 필요하지 않을 수 있지만, 아는게 좋겠죠?

 

여기저기 찾아본 결과 제가 봤던 건 ASP.NET Life Cycle 이 아니라 컨트롤의 실행 주기라고 하더군요. (같은건가? ;;;)

사용자 정의 서버컨트롤인가? 이거 만들때 유용하게 쓸 수 있습니다.

 

Control Execution Lifecycle

내용은 이렇습니다.

총 11 단계로 구성되어 있고 재정의할 메서드 들이 나와있습니다.

아래 표는 컨트롤 실행 주기의 각 단계에 대한 상위 수준 개요입니다.

 

단계재정의할 메서드 또는 이벤트
초기화Init 이벤트(OnInit 메서드)
뷰 상태 로드LoadViewState 메서드
게시 테이터 처리LoadPostData 메서드
(IpostBackDataHandler가 구현된 경우)
로드Load 이벤트
(OnLoad 메서드)
게시 변경 알림 보내기RaisePostDataChangedEvent 메서드
(IpostBackDataHandler가 구현된 경우)
게시 이벤트 처리RaisePostBackEvent 메서드
(IpostBackEventHandler가 구현된 경우)
사전 렌더링PreRender 이벤트
(OnPreRender 메서드)
상태 저장SaveViewState 메서드
렌더링Render 메서드
삭제Dispose 메서드
언로드UnLoad 이벤트(On UnLoad 메서드)


참고   EventName 이벤트를 재정의하려면, OnEventName 메서드를 재정의하고 기본 OnEventName을 호출합니다.

 

위의 내용은 아마도 MS에 나와 있는 내용 같습니다.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconcontrolexecutionlifecycle.asp

 

 

아래는 검색하다보니 한 영문 사이트에 나와 있는 걸 옮겨 놨습니다.

같은 이야기 같은데 설명만 조금 다른것 같습니다.

 

ASP.NET Page Life Cycle

 

1. Object Initialization (페이지 초기화)
   OnInit Method : Controls are initialized based on their declaration.
2. Load ViewState Data (뷰상태의 로딩-Postback)
   When load viewstate is fired, controls are populated with the appropriate view state data.
3. Load PostData Processes Postback Data (포스트백 데이터의 로딩-Postback)
   Unique IDs for each controls
4. Object Load (페이지의 로딩)
   The OnLoad event is an idal location to place logic.
5. Raise PostBack Change Events (상태변경과 관련된 이벤트 발생-Postback)
6. Process Client-Side PostBack Event (포스트백 이벤트 발생-Postback)
   Postback event handling
   The RaisePostDataChanged and RaisePostBackEvent events are defined by the IPostBackDataHandler interface.
7. Prerender the objects (렌더링 준비)
8. ViewState saved (뷰상태저장)
9.Render to HTML 페이지 렌더링
10. Disposal (페이지 자원의 해제-리소스 해제)
11. UnLoad (페이지의 언로드-메모리에서 언로드)

 

 

첨부된 소스는 간단하게 확인 할 수 있도록 만들어 봤는데, 제대로 만든 코드인지 모르겠네요. ^^;

어떻게 실행되는지 참고 하세요.

 

첨부된 그림은 한 인터넷 사이트에서 발견했습니다.

설명이 필요할 것 같은데, 읽어보기 귀찮아서 그냥 그림만 가져왔는데, 난해하군요..ㅎㅎ

 

http://hydrate.typepad.com/leo/2004/08/the_aspnet_v20_.html




 

Posted by SB패밀리

하드웨어 유일키 생성



using System;
using System.Management;
using System.Security.Cryptography;
using System.Security;
using System.Collections;
using System.Text;
namespace Security
{
    /// <summary>
    /// Generates a 16 byte Unique Identification code of a computer
    /// Example: 4876-8DB5-EE85-69D3-FE52-8CF7-395D-2EA9
    /// </summary>
    public class FingerPrint  
    {
        private static string fingerPrint = string.Empty;
        public static string Value()
        {
            if (string.IsNullOrEmpty(fingerPrint))
            {
                fingerPrint = GetHash("CPU >> " + cpuId() + "\nBIOS >> " + 
   biosId() + "\nBASE >> " + baseId()
                            //+"\nDISK >> "+ diskId() + "\nVIDEO >> " + 
   videoId() +"\nMAC >> "+ macId()
                                     );
            }
            return fingerPrint;
        }
        private static string GetHash(string s)
        {
            MD5 sec = new MD5CryptoServiceProvider();
            ASCIIEncoding enc = new ASCIIEncoding();
            byte[] bt = enc.GetBytes(s);
            return GetHexString(sec.ComputeHash(bt));
        }
        private static string GetHexString(byte[] bt)
        {
            string s = string.Empty;
            for (int i = 0; i < bt.Length; i++)
            {
                byte b = bt[i];
                int n, n1, n2;
                n = (int)b;
                n1 = n & 15;
                n2 = (n >> 4) & 15;
                if (n2 > 9)
                    s += ((char)(n2 - 10 + (int)'A')).ToString();
                else
                    s += n2.ToString();
                if (n1 > 9)
                    s += ((char)(n1 - 10 + (int)'A')).ToString();
                else
                    s += n1.ToString();
                if ((i + 1) != bt.Length && (i + 1) % 2 == 0) s += "-";
            }
            return s;
        }
        #region Original Device ID Getting Code
        //Return a hardware identifier
        private static string identifier
  (string wmiClass, string wmiProperty, string wmiMustBeTrue)
        {
            string result = "";
            System.Management.ManagementClass mc = 
  new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                if (mo[wmiMustBeTrue].ToString() == "True")
                {
                    //Only get the first one
                    if (result == "")
                    {
                        try
                        {
                            result = mo[wmiProperty].ToString();
                            break;
                        }
                        catch
                        {
                        }
                    }
                }
            }
            return result;
        }
        //Return a hardware identifier
        private static string identifier(string wmiClass, string wmiProperty)
        {
            string result = "";
            System.Management.ManagementClass mc = 
  new System.Management.ManagementClass(wmiClass);
            System.Management.ManagementObjectCollection moc = mc.GetInstances();
            foreach (System.Management.ManagementObject mo in moc)
            {
                //Only get the first one
                if (result == "")
                {
                    try
                    {
                        result = mo[wmiProperty].ToString();
                        break;
                    }
                    catch
                    {
                    }
                }
            }
            return result;
        }
        private static string cpuId()
        {
            //Uses first CPU identifier available in order of preference
            //Don't get all identifiers, as it is very time consuming
            string retVal = identifier("Win32_Processor", "UniqueId");
            if (retVal == "") //If no UniqueID, use ProcessorID
            {
                retVal = identifier("Win32_Processor", "ProcessorId");
                if (retVal == "") //If no ProcessorId, use Name
                {
                    retVal = identifier("Win32_Processor", "Name");
                    if (retVal == "") //If no Name, use Manufacturer
                    {
                        retVal = identifier("Win32_Processor", "Manufacturer");
                    }
                    //Add clock speed for extra security
                    retVal += identifier("Win32_Processor", "MaxClockSpeed");
                }
            }
            return retVal;
        }
        //BIOS Identifier
        private static string biosId()
        {
            return identifier("Win32_BIOS", "Manufacturer")
            + identifier("Win32_BIOS", "SMBIOSBIOSVersion")
            + identifier("Win32_BIOS", "IdentificationCode")
            + identifier("Win32_BIOS", "SerialNumber")
            + identifier("Win32_BIOS", "ReleaseDate")
            + identifier("Win32_BIOS", "Version");
        }
        //Main physical hard drive ID
        private static string diskId()
        {
            return identifier("Win32_DiskDrive", "Model")
            + identifier("Win32_DiskDrive", "Manufacturer")
            + identifier("Win32_DiskDrive", "Signature")
            + identifier("Win32_DiskDrive", "TotalHeads");
        }
        //Motherboard ID
        private static string baseId()
        {
            return identifier("Win32_BaseBoard", "Model")
            + identifier("Win32_BaseBoard", "Manufacturer")
            + identifier("Win32_BaseBoard", "Name")
            + identifier("Win32_BaseBoard", "SerialNumber");
        }
        //Primary video controller ID
        private static string videoId()
        {
            return identifier("Win32_VideoController", "DriverVersion")
            + identifier("Win32_VideoController", "Name");
        }
        //First enabled network card ID
        private static string macId()
        {
            return identifier("Win32_NetworkAdapterConfiguration", 
    "MACAddress", "IPEnabled");
        }
        #endregion
    }
}

 

 

========================================

결과물


 

CPU >> BFEBFBFF000006FB
BIOS >> Phoenix Technologies, LTD6.00 PGOEM20070919000000.000000+000IntelR - 42302e31
BASE >> Biostar Group기반 보드 
DISK >> ST3320620AS(표준 디스크 드라이브)3720011194255
MAC >> 00:E0:4D:51:45:1C

 

 

 

CPU >> BFEBFBFF000006FB
BIOS >> Phoenix Technologies, LTD6.00 PGOEM20070919000000.000000+000IntelR - 42302e31
BASE >> Biostar Group기반 보드 
암호화 : 129D-6375-4122-54E7-D304-D826-D1E8-684C



Posted by SB패밀리




Contacting a Registration Server to obtain a unique registration key based on unique machine ID

 

Introduction
Sometimes in the industry, it is required to collect some unique machine information and send it to a server for the purpose of creating a unique registration key based on the hardware information. This is required in the case when the software requires a per PC registration. Thus we can collect the machine information of the PC in which the software was installed, and issue a registration key which will be valid only for that machine.

Background 
Using WMI functionality, it is possible to collect machine specific hardware information. 
In .NET, one can use System.Management.ManagementClass for this purpose. (This is explained in this article.)

The problem arises when we try to send this information to the server. Because of the firewall that is present in OSes starting from WinXP, if we try to send data from our application to an external server, the firewall pops up a warning to the user informing her/him that the application is trying to send data and asks the user whether she/he wants to proceed or block the application. (Also this approach will fail if the local network is connected to the Internet through a firewall, which is configured to block anything other than HTTP traffic.)

The solution thus comes in the form of HTTP (i.e. we have to send the data through HTTP).
In .NET, this is easily achieved through System.Net.WebRequest or by using a Web Service. This article uses the WebRequest approach.

Using the Code 
In the class ContactRegistationServer (UserRegistration project), you will notice that we are creating a WebRequest and passing the hardware information through QueryString.

WebResponse registrationKey = null;
String url_string = "http://localhost/Registration/Registration.aspx"
    + "?CPU=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.cpuID)
    + "&BIOS=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.biosID)
    + "&MB=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.baseID)
    + "&DISK=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.diskID)
    + "&MAC=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.macID)
    + "&VIDEO=" + System.Web.HttpUtility.UrlEncode(hardwareInfo.videoID);
try
{
    WebRequest requestRegistration = WebRequest.Create(url_string);
    registrationKey = requestRegistration.GetResponse();
}
catch (Exception ex)
{
    System.Windows.Forms.MessageBox.Show("Failed connecting to server");
    return;
}
On the server (Refer project 'TestPage' Registration.aspx.cs), the QueryString received from the client is retrieved and a unique registration key is produced and returned to the user.

//Call the Foolproof Registration Key algorithm :)
TheFoolProofRegistrationKey regKey = new TheFoolProofRegistrationKey();
String key = regKey.getRegistrationKey(Request.QueryString["CPU"]);
Response.Write(key);
Notes: If You Decide to Download and Run the Program
If you decide to download and try the application, please make sure to create a virtual folder of the name "Registration" on your local Web server. This is required as the WebRequest is using the following URL: http://localhost/Registration/Registration.aspx (or else copy the files to a folder by the name Registration under the server root folder).

Just for the use of a novice, I have attached a few screen shots on how to add the virtual directory on IIS.


And finally you should have something as follows:

Points of Interest 
For testing purposes, I also tried to connect to the server from a different PC: (e.g.: http://10.10.42.135/Registration/Registration.aspx) and it still worked - the firewall did not complain:). 
I did not try to connect to a server outside our network, but I guess that should also work...

 

To collect machine specific information, use the code in this article.









Posted by SB패밀리

ASP용 이미지 리사이즈 프로그램 DLL과 소스프로그램





이미지사이즈.zip


Posted by SB패밀리

Creating GridView Columns Dynamically (Part 1)





http://www.dotnetbips.com/articles/56fadcb9-ee8b-4170-a6ad-cd4f38222bcb.aspx

Creating GridView Columns Dynamically (Part 1)

Introduction

Many months back I wrote three articles - Creating DataGrid ProgrammaticallyCreating DataGrid Templated Columns Dynamically - Part I and Creating DataGrid Templated Columns Dynamically - Part II. Even today these are amongst top viewed articles. This indicates how commonly developers need to create grid controls dynamically. Beginning with this article I am starting a series that will show you how to create data bound controls such as GridView and DetailsView programmatically. To begin with Part 1 shows how to add bound fields and command fields to a GridView. The GridView thus created is fully functional with paging, sorting and editing features.

Creating a sample web site

To begin with create new web site in Visual Studio. Drag and drop a GridView control and an SqlDataSource control on the default web form. Do not set any property of either controls at design time. We will be doing that via code.

Now key in the following code in the Page_Load event handler.

protected void Page_Load(object sender, EventArgs e)
{
SqlDataSource1.ConnectionString = 
@"data source=.;initial catalog=northwind;integrated security=true";
SqlDataSource1.SelectCommand = 
"select employeeID,FirstName,LastName from employees";
SqlDataSource1.UpdateCommand = 
"update employees set firstname=@FirstName,lastname=@LastName 
where employeeid=@EmployeeID";
SqlDataSource1.UpdateParameters.Add("@FirstName", "");
SqlDataSource1.UpdateParameters.Add("@LastName", "");
SqlDataSource1.UpdateParameters.Add("@EmployeeID", "");

if (!IsPostBack)
{
GridView1.DataSourceID = "SqlDataSource1";
GridView1.AutoGenerateColumns = false;
GridView1.DataKeyNames = new string[] { "EmployeeID" };
GridView1.AllowPaging = true;
GridView1.AllowSorting = true;
GridView1.PageSize = 5;

BoundField bf1 = new BoundField();
BoundField bf2 = new BoundField();
BoundField bf3 = new BoundField();

bf1.HeaderText = "Employee ID";
bf1.DataField = "EmployeeID";
bf1.ReadOnly = true;
bf1.SortExpression = "EmployeeID";

bf2.HeaderText = "First Name";
bf2.DataField = "FirstName";
bf2.SortExpression = "FirstName";

bf3.HeaderText = "Last Name";
bf3.DataField = "LastName";
bf3.SortExpression = "LastName";

CommandField cf = new CommandField();
cf.ButtonType = ButtonType.Button;
cf.ShowCancelButton = true;
cf.ShowEditButton = true;

GridView1.Columns.Add(bf1);
GridView1.Columns.Add(bf2);
GridView1.Columns.Add(bf3);
GridView1.Columns.Add(cf);
}
}

The code is dissected in the following sections

Configuring the SQL data source control

The code sets the ConnectionString property SQL data source control to required database connection string. In our example we will be using Employees table of Northwind database. Then SelectCommand and UpdateCommand properties are set to corresponding SELECT and UPDATE queries. The UPDATE query is important. Note that the names of the parameters specified in UPDATE statement are matching the table column names. The UPDATE statement contains three parameters - @FirstName, @LastName and @EmployeeID. These parameters are then added to the UpdateParameters collection.

Configuring the GridView control

The GridView control uses SqlDataSource1 as its data source. This is indicated by setting the DataSourceID property of GridView. Further some properties of GridView are set. Note that you need to set these properties only once and hence they come inside the "if" condition. The AutoGenerateColumns property indicates whether to generate GridView columns automatically. We set this property to false as we wish to add them via code. The DataKeyNames property is a string array specifying the primary key columns. The AllowPagng and AllowSorting properties enable paging and sorting feature respectively. The PageSize property sets the page size to 5.

Creating Bound Fields

The GridView control can contain many types of columns such as BoundField, HyperLinkField and TemplateField. In this example we will be using BoundField columns. We need three bound fields for EmployeeID, FirstName and LastName respectively. A bound field is represented by a class called BoundField. The HeaderText property of BoundField class indicates the column heading. The DataField property indicates the name of the table column that you wish to display in the bound field. The SortExpression property governs if that bound field will be sortable or not. If you set the SortExpression property to a column name then the bound field will be sortable based on that column. Since EmployeeID bound field represents primary key we set its ReadOnly property to true. This way it won't be editable.

In order to provide editing feature you need to add a CommandField column to the GridView. The ButtonType property of CommandField class indicates the type of button to render. Possible values are Button, LinkButton and ImageButton. The ShowCancelButton and ShowEditButton properties decide if the Edit and Cancel buttons will be displayed.

Once we create the columns they need to be added to the Columns collection of GridView.

That's it! If you run the web form then it should look as shown below:



You can now test GridView features such as paging sorting and editing.






Posted by SB패밀리

Creating GridView Columns Dynamically (Part 1, 2) 소스코드



Introduction

Few months back I wrote article on how to create DataGrid programatically. The article explained how to created a DataGrid with bound columns on the fly. Many readers asked whether we can do similar thing with templated columns. This two part article explains just that. There are actually two ways to create DataGrid templated columns dynamically - using LoadTemplate method and implementing ITemplate interface. In Part - I, we will discuss how to use the first method i.e. using LoadTemplate.

What are templates anyway?

ASP.NET list controls like DataGrid, DataList and Repeater allow flexibility in changing look and feel via the use of what is called as 'Templates'. As the name suggests template is a blue print of look and feel for data displayed in certain areas of the control. For example, HeaderTemplate represents blue print of the header of the control. Similarly, ItemTemplate represents individual item or row of the DataGrid. These sectons are represented by markup like <ItemTemplate> and <HeaderTemplate>.

LoadTemplate method

If you see the class hierarchy of Page class it looks like this:
System.Object
   System.Web.UI.Control
      System.Web.UI.TemplateControl
         System.Web.UI.Page
The System.Web.UI.TemplateControl class contains a method called LoadTemplate that can be used to dynamially load temlates for templated controls. The signature of LoadTemplate is like this:
public ITemplate LoadTemplate
(string virtualPath);
The method takes virtual path of a user control file i.e. .ascx file.

Creating user control file for template markup

You should store markup of the template in .ascx file. Remember that the markup should not contain actual tags like <ItemTemplate>. Typically this file will not be having any other markup. Note that one such file represents markup for one kind of template.

Example of using LoadTemplate method

We will now develop an example in which we will create a DataGrid on the fly with a single template column. The template column simply contains a Label control but you can add any other controls as well. Our example will need to follow steps given below:
  • Create a new ASP.NET web application
  • Create a new web form
  • Create a user control file (.ascx) for template markup
  • Write code to add a DataGrid to the form
  • Load the template from the .ascxfile
  • Bind the DataGrid with some datasource
Out of above steps first two are common to any web application and we will not discuss them here. So, let us start by creating a user control file for our template.

User control file for our example

You may add a new web user control (.ascx) to your project. Add following markup to the file:
<%@ Control Language="C#" %>
<asp:label ID="label1" Runat="server" 
text='<%# Databinder.Eval
(((DataGridItem)Container).DataItem,"lastname")%>'>
</asp:label>
Note that this markup looks same as if we would have used it in design mode. Here, we are binding a label control with the lastname field from the DataMember.

Adding DataGrid to the form

Add following code to the Page_Load event of the web form
string connstr = 
@"Integrated Security=SSPI;User ID=sa;Initial 
Catalog=Northwind;Data Source=MyServer\NetSDK";
SqlConnection cnn=new SqlConnection(connstr);
SqlDataAdapter da=
new SqlDataAdapter("select * from employees", cnn);
DataSet ds=new DataSet();
da.Fill(ds, "employees");
ITemplate temp= Page.LoadTemplate("webusercontrol1.ascx");
TemplateColumn tc=new TemplateColumn();
tc.HeaderText = "Last Name";
tc.ItemTemplate = temp;
DataGrid1.Columns.Add(tc);
DataGrid1.DataSource = ds;
DataGrid1.DataMember = "employees";
DataGrid1.DataBind();
Most of the code will be familiar to you except code related to ITemplate. We have loaded our template using LoadTemplate method. We then create a TemplateColumn and set its ItemTemplate to it. Even though we have used ItemTemplate, it can be any other type of template also like EditItemTemplate. We then add this new column to the DataGrid. Note that our DataGrid instance DataGrid1 is declared at class level and hence not visible in the code shown above.

After running your application you should get a DataGrid with single templated column titled 'Last Name'.

Summary

In this article we saw how to add a templated column to a DataGrid on the fly using LoadTemplate method. This method can be used if you want to use same DataGrid with say few columns changing at run time. In the next part we will see how to create templated columns via implementing ITemplate interface. Till then keep coding!


Bipin Joshi is software consultant, trainer and author having 20+ years of experience in software development. He conducts professional courses in ASP.NET MVC, jQuery, HTML5 and Design Patterns in Thane. He is a published author and has authored or co-authored books for Apress and Wrox press. To know more about him click here. To know more about his training programs go here.

Get connected : Twitter  Facebook  Google+  LinkedIn



gridviewdyncolumns.zip



Creating GridView Columns Dynamically Part 1

http://www.binaryintellect.net/articles/331ed95f-d49f-4664-a9f7-768d6e11beb0.aspx

Creating GridView Columns Dynamically Part 2

http://www.binaryintellect.net/articles/0b4f8e1c-39e6-4070-abc0-7a970e7553bc.aspx


download source code


Posted by SB패밀리

Creating GridView Columns Dynamically (Part 2)



 

 







http://www.dotnetbips.com/articles/0b4f8e1c-39e6-4070-abc0-7a970e7553bc.aspx

Creating GridView Columns Dynamically (Part 2)

Introduction

In Part 1 you learned to create Bound Fields and Command Fields dynamically. Often your grid layout is beyond the capabilities of in-built column types and you need to use Template Fields. For example, let's say you are creating a product catalog. Certainly normal tabular layout is not suitable here as you want to display each record in a highly customized format. Template fields can come handy in such situations. In this article I am going to illustrate how template fields can be added dynamically. You will learn two techniques of doing so:

  • Using LoadTemplate() method
  • By creating a custom template class

Adding Template Fields Using LoadTemplate() Method

In order to work with this example you need to create new web site in Visual Studio. Drag and drop a GridView on the default page. Also drag and drop an SqlDataSource control. We will be setting various properties of these controls via code. In the first method of adding template fields we will be using LoadTemplate() method. The LoadTemplate() method is available to all template controls including the Page. It accepts virtual path of a file and loads the template specified therein. The return value of LoadTemplate() is an object that implements ITemplate interface.

In our example we will create the template in a User Control. To do so, add a new Web User Control to the web site and name it as ItemTemplate.ascx. Key in the following markup to it.

<%@ Control Language="C#" AutoEventWireup="true" 
CodeFile="ItemTemplate.ascx.cs" Inherits="ItemTemplate" %>
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("EmployeeID") %>'>
</asp:Label>
<asp:Label ID="Label2" runat="server"
Text='<%# Eval("FirstName") %>'>
</asp:Label>
<asp:Label ID="Label3" runat="server"
Text='<%# Eval("LastName") %>'>
</asp:Label>

Notice above markup carefully. It contains three Label controls. The Text property of each Label is bound with EmployeeID, FirstName and LastName columns of Employees table respectively. The Eval() expression is one way data binding expression of ASP.NET and accepts the name of the column to bind. This user control will act as our ItemTemplate later.

Now open the code behind file of the default web form and key in the following code in Page_Load event handler.

protected void Page_Load(object sender, EventArgs e)
{
SqlDataSource1.ConnectionString =
@"data source=.;initial catalog=northwind;integrated security=true";
SqlDataSource1.SelectCommand =
"select employeeID,FirstName,LastName from employees";
if (!IsPostBack)
{
GridView1.DataSourceID = "SqlDataSource1";
GridView1.AutoGenerateColumns = false;
TemplateField tf1 = new TemplateField();
tf1.ItemTemplate=LoadTemplate("ItemTemplate.ascx");
GridView1.Columns.Add(tf1);
}
}

The code points the ConnectionString property of SQL data source control to Northwind database. The SelectCommand property specifies a SELECT statement that fetches EmployeeID, FirstName and LastName columns of Employees table. Next, it sets DataSourceID property of GridView control to the ID of SQL Data Source control. Also, AutoGenerateColumns property is set to false as we will be adding columns programmatically. Next few lines are important. The code then creates an instance of TemplateField class. The TemplateField class represents a template column of GridView class. The ItemTemplate property of TemplateField class is then set to the return value of LoadTemplate() method. The LoadTemplate() method accepts a virtual path of the file containing template to be loaded (ItemTemplate.ascx in our case). The TemplateField is then added to the Columns collection of GridView control.

Run the web form and your browser should display something as shown below:

Notice how the template specified in the user control is applied. Also, notice that header is shown blank because we did not specified HeaderTemplate. You can either specify it or turn the header off.

Adding Template Field Using Custom Template Class

Now that you know how to use LoadTemplate() method let's move to another possibility. You learnt in the last example that LoadTemplate() method returns an object that implements ITemplate interface. You yourself can create such a class and use it directly in your code instead of using LoadTemplate() method.

To begin with add a new class named MyTemplate to App_Code folder. Key in the following code to MyTemplate class.

public class MyTemplate:ITemplate
{
    private string colname;
 public MyTemplate(string colname)
 {
        this.colname = colname;
 }
    public void InstantiateIn(Control container)
    {
        LiteralControl l = new LiteralControl();
        l.DataBinding += new EventHandler(this.OnDataBinding);
        container.Controls.Add(l);
    }
    public void OnDataBinding(object sender, EventArgs e)
    {
        LiteralControl l = (LiteralControl)sender;
        GridViewRow container = (GridViewRow)l.NamingContainer;
        l.Text = ((DataRowView)container.DataItem)[colname].ToString();
    }
}

The code creates a class called MyTemplate that implements ITemplate interface. The ITemplate interface contains a single method - InstantiateIn() - that you must implement. The code then declares a string variable to hold a column name to be displayed. The column name is set in the constructor of the class. Then InstantiateIn() method is implemented. The method receives an object of type Control that represents container or parent control. Inside we create a LiteralControl and attach an event handler (OnDataBinding) to its DataBinding event. This event is raised when the container control calls DataBind() method on itself. The LiteralControl is then added to the Controls collection of the container control.

The OnDataBinding() event handler does the job of data binding the LiteralControl with the required data. It then gets a reference to the row in which the control is being added using NamingContainer property. Finally, Text property of LiteralControl is set to the value of database column as specified in the constructor. This completes our custom template class.

Now add a new web form to the same web site. Drag and drop a GridView and SqlDataSource control as before. Add the following code in the Page_Load event handler of the form.

protected void Page_Load(object sender, EventArgs e)
{
SqlDataSource1.ConnectionString =
@"data source=.;initial catalog= northwind;integratedsecurity=true";
SqlDataSource1.SelectCommand =
"select employeeID,FirstName,LastName from employees";
if (!IsPostBack)
{
GridView1.DataSourceID = "SqlDataSource1";
GridView1.AutoGenerateColumns = false;
TemplateField tf1 = new TemplateField();
MyTemplate t1 = new MyTemplate("FirstName");
tf1.HeaderText = "First Name";
tf1.ItemTemplate = t1;
TemplateField tf2 = new TemplateField();
MyTemplate t2 = new MyTemplate("LastName");
tf2.HeaderText = "Last Name";
tf2.ItemTemplate = t2;
GridView1.Columns.Add(tf1);
GridView1.Columns.Add(tf2);
}
}

The code sets the properties of SqlDataSource and GridView as before. Notice the code marked in bold letters. The code creates an instance of TemplateField class as before. This time the ItemTemplate property of TemplateField is set to a new instance of MyTemplate class. The column names - FirstName and LastName - are passed in the constructor. Finally, the template fields are added to the Columns collection of GridView class.

The following screen shot shows a sample run of the above web form.

That's it! Happy coding.



Posted by SB패밀리

에러메시지 : Unable to start debugging on the web server







Unable to start debugging on the web server. The server does not support debugging of ASP.NET or ATL Server applications

 

이런 에러 메시지가 나타는 경우 다음과 같이 해결해 보자.

 

비주얼스튜디오에서 실행시 나는 에러로

 

이 에러는 보통 ASP.NET 파일 익스텐션 (.aspx)에 관한 정보가 인터넷 인포메이션 서비스에 제대로 등록이 되어 있지 않은 경우에 발생합니다.

 

한번 확인해 볼까요?

 

Control Panel -> Internet Information Services 에서 디버깅할 디렉토리 찾아 주세요. 오른쪽 클릭해서 프라퍼티 윈도우 열어 주세요.

 

그림 1

 

Virtual Directory 탭으로 가서, Applicatioin Settings 에 있는 Configuration 버튼을 꾸욱 눌러주세요

 

그림 2

 

.aspx의 Executable path 에 그 정보가 저장 되어 있습니다.
 
C:\WINDOWS\Microsoft.NET\Framework\Version\aspnet_isapi.dll 혹은
C:\WINNT\Microsoft.NET\Framework\Version\aspnet_isapi.dll
 
여기서 버전은 본인이 어떤 버전을 깔았는지에 따라 다릅니다.
 
이런 엔트리가 없거나 패스가 다르다면 프로그램 인스톨 시에 뭔가 문제가 있었던 거에요.
 
어떻게 해결할 까요?
 
Start -> Run 에서 cmd 타입합니다. 커맨드 프람프트에서 cd 이용하여
C:\WINDOWS\Microsoft.NET\Framework\Version\ 나
C:\WINNT\Microsoft.NET\Framework\Version\
로 이동해 주세요.  버전은 컴터마다 달라요~. 내 컴터에 있는 버전으로 해 주세요.
 
이동이 다 되었으면...
 
aspnet_regiis -i
 
타입하고 엔터키 눌러서 실행해 주세요.


Posted by SB패밀리

웹에서의 비동기 호출 : 고전적인 방식(FRAME 이용)


http://www.taeyo.pe.kr/lecture/NET/scriptCallback01.asp

강좌 최초 작성일 : 2005년 12월 02일
 i_bullet_03.gif  강좌 최종 수정일 : 2005년 12월 05일

 i_bullet_03.gif  강좌 읽음 수 : 13258 회

 i_bullet_03.gif  작성자 : Taeyo(김 태영)
 i_bullet_03.gif  편집자 : Taeyo(김 태영)

 i_bullet_03.gif  강좌 제목 : 웹에서의 비동기 호출 : 고전적인 방식(FRAME 이용)

강좌 전 태오의 잡담>

다양한 행사가 있다보니 강좌가 많이 늦어졌습니다. 수많은 세미나에 Ready 2005 행사까지...
정신이 없었던 2005년도 가을이네요... 이제 성큼 겨울도 발 앞에 다가와 있습니다. 모두들 한해 마무리 잘 하세여~


이번 강좌에서는 고급 웹 프로그래밍을 위해서 알아두면 매우 좋은 주제인, 스크립트 콜백(Script Callback)이라는 기법에 대해서 알아보도록 하겠습니다. 웹 페이지에서의 비 동기 호출을 가능하게 하는 것이 바로 스크립트 콜백이라는 기법이라 할 수 있는데요. 전혀 새로운 개념이라고 볼 수는 없고요. 기존 ASP 시절부터 이미 편법 식으로 구현해서 사용하고 있던 것이 깔끔하게 정리된 것이라 할 수 있습니다. 물론, IFRAME을 이용했던 ASP 시절의 편법은 완전한 비 동기 호출이라고 볼 수는 없습니다만, 결과적으로는 비동기적으로 구동되는 것처럼 보이기에 저는 그 또한 비 동기 호출방식의 범주에 넣어서 이야기 드리고 있습니다.

핫?? 지난 강좌에서 언급했던 HttpModule 구현 및 적용의 실제 구현사례 강좌는 어디가고 지금 비동기 호출이라는 주제로 마치 춘삼월 새내기의 풋풋한 화장품 냄새마냥 깝죽거리는 것이냐구요??? -_-+++ (넵. 메가작가 스탈의 개그를 한번 써본 것 맞습니다)

그게 말입니다. 인생에는 가끔 기다림도 필요한 것입니다. 그렇지 않습니까??? -_-;;;
엇? 저기 UFO닷!!!! 저기저기!!! (지금이닷!! 냅다 ㅌㅌ)

그렇다면, 이야기를 더 진행하기에 앞서 도대체 스크립트 콜백 즉, 큰 의미로서 비 동기 호출이라는 것이 무엇인지 먼저 살포시 알아보고 넘어가도록 하겠습니다.

스크립트 콜백(Script Callback)이라는 것은 다음과 같습니다.

- 일종의 클라이언트 대 서버의 비 동기 통신
- 웹 페이지를 갱신하지 않고, 서버의 모듈을 실행하여 그 결과를 페이지에 반영하는 기법.
   (페이지 전체를 [새로 고침] 할 필요가 없으며, 스크립트를 이용해 페이지의 일부 구역만을 동적으로 변경하는 방식을 사용합니다)
- ASP 시절에 소개되었던 Remote Scripting의 진화된 버전

사실, 웹(Web)이라는 환경 자체는 비 동기 호출이 어려운 구조입니다. 즉, HTTP 요청/응답 패턴은 콜백이 어려운 구조라는 이야기인 것이죠. 콜백을 가능하게 하려면 요청을 보내는 HTTP 채널과 응답을 받는 채널이 페이지와는 별도로 각기 존재해야 하는데, 그렇게 구성하는 것은 간단한 일이 아닙니다(물론, 매우 복잡한 것도 아니긴 하지만요~~ 헤헤, 이랬다가 저랬다가~). 게다가, 비 동기적인 호출은 사용자의 눈에는 보이지 않게 일어나야 할 뿐 더러, 어찌 어찌하여 서버에서 데이터를 받았다 하더라도, 그 응답 결과를 원래의 페이지에 반영해야 하기 위해서는 다시 동적 스크립트 기술을 이용해야 하기에 해야 할 작업량도 상당합니다.

이러한 상당한 작업량은 실제로 고전적인 접근에서는 손 수 다 작성하기도 했었던 것입니다. 갑자기 지난 노가다(?)의 시절을 떠올리니, 손가락이 떨리면서 글이 쓰기 싫어지려 하네요. 에잇~ 안 좋은 추억에서는 어서 빨리 깨어 나야 하겠습니다. ^^ 레드쏜!

웹 프로그래밍 상에서의 비 동기 호출을 위한 다양한 시도는 현재까지도 꾸준하게 이어지고 있습니다. XMLHTTP를 이용한 비동기 호출방식이 소개되었었고, 그리고, 이를 이용하기 편하게 컴포넌트화 시켰던 WebService Htc 기법을 이용한 비 동기 호출도 소개가 되었었죠. 안타깝게도, WebService Htc 기법은 현재는 지원을 더 이상 하지 않고 있습니다만, 이 기법을 이용해서 만들어진 사이트는 여럿 있는 것으로 알고 있습니다(이 기법은 지금도 이용할 수 있기는 합니다. 단지, 문제 발생시 MS로부터 지원을 받지 못한다는..., 하긴, 직접 고쳐서 쓰면 되긴 하지만..).

그리고, 이러한 비 동기 호출은 최근 주목받는 단어인 AJAX(Asynchronous JavaScript and XML)라는 것으로까지 발전하고 있죠. MS에서도 Atlas라는 코드명으로 AJAX를 위한 프레임워크를 준비 중이기도 하구요. 즉, 웹 프로그래밍 상에서의 비 동기 호출은 더 이상 중, 고급 개발자들만을 위한 어려운 기술이 아닌, 보편적인 기술로서 받아 들여지고 있다는 이야기일 것입니다.

이 연재 강좌에서는 이 모두를 전부 다룰 예정에 있습니다. "과연? -_-+" 이라고 의심의 눈초리를 보내시는 분들이 매우 많네요. 음.. 그리고 보니, 조금은 무리스럽다고 느껴지기도 하긴 하는데요. 하하. 하지만, 그래도 꿋꿋이 진행을 해 보려 합니다. 되던 안되던, 안될 것을 미리 걱정해서 시작조차 안하고 싶지는 않거든요 ^^

이번 연재 강좌는 웹 상의 비 동기 호출에 대한 기존, 현재, 미래 방식을 모두 알아보는 식으로 꾸며보려 합니다. 특히, 이번 강좌에서는 ASP나 ASP.NET 페이지 혹은 다른 동적 웹 페이지(php, jsp)에서도 사용할 수 있는 오래된 비 동기 호출 편법(?)을 먼저 소개하도록 하고요. 이어지는 강좌에서는 다음의 것들을 소개해 보려 합니다.

1. 고전 편법(Hidden IFRAME)을 이용한 비동기 호출 (이번 강좌)
2. XMLHTTP를 이용한 비동기 호출
3. WebService Htc를 이용한 비동기 호출(더이상 지원되지 않는 기술이기에 다루지 않을 수도 있습니다)
4. ASP.NET 2.0 스크립트 콜백
5. AJAX를 이용한 비동기 호출

그럼 이제 시작해 볼까요?

고전 편법(Hidden IFRAME)을 이용한 비동기 호출

기존에는 비 동기식(!) 호출을 구현하기 위해서 프레임을 사용하곤 했는데요. 사용자 몰래 서버로 Request/Response를 수행하기 위해 눈에 보이지 않게 설정한 별도의 프레임(Hidden)을 주로 이용하곤 했습니다. 예를 들면, 다음 그림과 같이 말이죠.



이 그림은 기존 동적 페이지 기술에 비 동기식 호출 기능을 적용하는 방법을 보여주고 있습니다(이 외에도 많은 방법이 있을 수 있지만, 주로 이 방법들을 많이 이용했습니다).

그림을 간단하게 설명하자면, 하단에 눈에 안 보이게 설정된 IFRAME을 통해서 사용자의 눈에 보이지 않게 서버로부터 필요한 데이터를 가져와서, 그 데이터를 스크립트를 통해서 원래의 부모 페이지에 반영하는 방식입니다

예제는 직급별 직원목록을 나열하는 예를 사용하고 있는데요. 일단, 페이지는 두 개의 DropDown 컨트롤을 포함하는 구조로 구성되어 있습니다. 첫 번째 DropDown(직급목록)에는 직급의 목록이 기본적으로 출력되며, 두 번째 DropDown(직원목록)의 경우는 첫 번째 DropDown에서 선택된 직급에 해당하는 직원들의 이름이 출력됩니다. 즉, 매번 직급목록 DropDown이 변경될 때마다, 동적으로 그 직급에 해당하는 직원들의 목록을 가져와서 두 번째 DropDown(직원목록)에 로드 하겠다는 것이죠. 물론, 처리 로직이 어려울 것은 전혀 없습니다. 이런 류의 데이터 조회는 매우 흔하게 하는 작업 중 하나이니까요. 중요한 것은 이번 예제에서는 그러한 처리를 페이지의 새로 고침 없어, 비 동기적인 방식으로 수행한다는 것입니다. 그것이 바로 포인트이죠.

즉, 첫 번째 DropDown(직급목록)에서 선택이 바뀔 경우에는, 해당 직급에 따라 직원들의 목록을 가져오는 asp 페이지(혹은 aspx 페이지)를 하단의 IFRAME에 로드합니다. IFRAME에 asp(혹은 aspx) 페이지가 로드 되면, 그 asp(혹은 aspx) 페이지는 가져온 결과를 클라이언트 스크립트를 통해서 부모 페이지의 두 번째 DropDown(직원목록)에 동적으로 구성해 넣는 것이죠.

이로써, 페이지는 새로 고침이 일어나지 않으면서 동적으로 데이터가 채워지는 형태의 개발이 가능한 것입니다. 물론, 사실상 내부적으로는 별도의 페이지가 로드 되었기에, 새로 고침이 일어난 것이나 별반 차이가 없어 보일 수 있습니다만, 사용자의 측면에서 보면 이것은 매우 효과적입니다. 기존 페이지의 데이터가 사라지는 일도 생기지 않을 뿐 더러, 직급별 데이터를 가져오는 동안 다른 작업도 페이지에서 수행할 수 있으니 말입니다.

그렇다면, 예제 소스를 한번 살펴보도록 하겠습니다. 먼저, 부모 페이지 격에 속하는 메인 페이지를 살펴보도록 할까요? 사실 asp 페이지 소스나 aspx 페이지 소스나 별반 차이가 없을 것이기에, 예제는 aspx 페이지로 진행하도록 하구요. 다운로드 받을 수 있는 소스에는 asp 소스도 같이 넣어드리도록 하겠습니다. ^^

Client.aspx

<%@ Page language="c#" Codebehind="Client.aspx.cs" AutoEventWireup="false" Inherits="CallbackEx.Case_ASP.Client" %>
<HTML>
  <HEAD>
    <LINK href="../Styles.css" type="text/css" rel="stylesheet">
    <script language="javascript">
      function CallScript()
      {
        var title = document.all.title.options[document.all.title.selectedIndex].value;
        CallBackFra.location.href = "Callback.aspx?Title=" + title;
      }
    </script>
  </HEAD>
  <body>
    <form runat="server">
      <asp:DropDownList id="title" runat="server"></asp:DropDownList>
      <select id="Lname" NAME="Lname" disabled>
        <option value="-" selected>직급을 선택해 주세요</option>
      </select>
      <input type="text">
      <p>
        <IFRAME id="CallBackFra" width="400" Height="50"></IFRAME>
      </p>
    </form>
  </body>
</HTML>

위의 소스에서 주의해서 봐야 할 부분은 3군데(파란색 소스) 입니다. 첫 번째 주의 포인트는 DropDown(직급목록)에서 선택이 바뀔 경우에는 호출되는 자바스크립트입니다. 이는 현재 선택된 DropDown(직급목록)의 값을 인자로 하여, IFRAME에 Callback.aspx 페이지를 요청하는 역할을 수행합니다. 즉, 눈에 보이지 않게 비 동기 호출을 시작하는 부분이 되겠네요~

두 번째 주의 포인트는 DropDown(직급목록)을 위한 서버 컨트롤입니다. 코드 비하인드에서는 Page_Load 시에 이 DropDown 컨트롤을 직급 데이터로 채우게 됩니다. 해서, 페이지가 처음 뜰 때, DropDown(직급목록) 컨트롤에는 직급 데이터가 모두 채워져서 나오게 됩니다. 이 부분과 관련된 코드는 잠시 뒤에 보여드리겠습니다.

세 번째 주의 포인트는 바로 IFRAME 입니다. 이 프레임이 바로 비 동기 호출의 별도 채널역할을 하게 됩니다. 현재는 IFRAME이 눈에 보여지고 있습니다만, 개발이 완료되는 시점에서는 이 부분을 눈에 보이지 않게 처리할 것입니다. 그럼으로써, 완벽하게 사용자를 속일 수 있게 되는 것입니다.

그럼, 이제 코드 비하인드 쪽의 소스를 한번 살펴볼까요?

Client.aspx.cs

    public class Client : System.Web.UI.Page
    {
        //데이터베이스 연결 문자열(이 부분은 자신의 PC에 맞게 변경해 주세요)
        private const string conStr = "server=(local);database=Northwind;uid=sa;pwd=1";
        protected System.Web.UI.WebControls.DropDownList title;

        private void Page_Load(object sender, System.EventArgs e)
        {
            //직급용 DropDown에 클라이언트 스크립트 연결하기
            title.Attributes.Add("onchange", "CallScript()");

            if (!this.IsPostBack)
            {
                //직급 데이터를 직급 DropDown 컨트롤에 바인딩한다
                string sql = "SELECT distinct Title as Title FROM Employees";

                SqlConnection con = new SqlConnection(conStr);
                SqlCommand cmd = new SqlCommand(sql, con);
                con.Open();

                title.DataTextField = "Title";
                title.DataValueField = "Title";

                title.DataSource = cmd.ExecuteReader();
                title.DataBind();

                con.Close();
            }
        }

        .. 중략 ..

역시나, 코드 비하인드 쪽에는 크게 어려운 부분은 없습니다. 주석이 설명하고 있는 대로, 서버에서 직급 데이터를 가져와서 DropDown 컨트롤에 채우는 부분이 주가 되겠네요. ^^

자. 소스가 완료되었으니 현재까지의 작업 결과를 브라우저로 한번 살펴보도록 하겠습니다. 다음과 같은 결과가 브라우저로 나타날 것입니다.



현재는 첫 번째 DropDown 컨트롤에서 선택을 바꾸어도 별다른 변화가 없을 것입니다. 왜냐하면, 실제 선택 변경 시, 비동기 작업이 일어나는 Callback.aspx 페이지가 아직 작성되지 않았기 때문이죠.

자. 그럼 이제 Callback.aspx 페이지로 들어가 볼까요? 이 페이지는 별도의 UI가 존재하지 않습니다. 주 역할이 QueryString으로 넘어오는 직급 데이터를 얻어와서, 그를 가지고 데이터베이스를 조회하고, 해당 직급에 맞는 직원들의 이름을 가져와 동적으로 부모 페이지의 DropDown 컨트롤에 꽂아 넣기만 하면 되니까요~

해서, Callback.aspx 페이지의 HTML 코드는 다음과 같습니다.

Client.aspx.cs

<%@ Page language="c#" Codebehind="Callback.aspx.cs" AutoEventWireup="false" Inherits="CallbackEx.Case_ASP.Callback" %>
<script language="javascript">

    //DropDown에서 기존값들을 모두 제거하는 함수
    function ClearAll()
    {
        var count = parent.document.all.Lname.options.length;
        for(var i = 0; i < count; i++)
            parent.document.all.Lname.options.remove(0);
    }

    //DropDown에서 직원 이름을 추가하는 함수
    function AddOption(value, text)
    {
        var oOption = document.createElement("OPTION");
        oOption.text = text;
        oOption.value = value;
        parent.document.all.Lname.options.add(oOption);
    }

    ClearAll();
    parent.document.all.Lname.disabled = false;

</script>
<HTML>
    <body>
        <form runat="server" ID="Form1">

            // 이하에 실제 데이터를 콤보박스에 채우는 클라이언트 스크립트가 들어와야 한다.
            // 이는 서버에서 동적으로 만들어서 넣어주어야 한다.

        </form>
    </body>
</HTML>

그렇습니다. 코드의 대부분은 클라이언트 스크립트가 차지하고 있고요. UI용 HTML 태그는 거의 없는 것을 볼 수 있습니다.

스크립트를 쪽을 보시면, ClearAll()이라는 함수와 AddOption이라는 클라이언트 스크립트 함수가 우선적으로 보일텐데요. 이들은 주석에서 설명하고 있는 것처럼 각기 DropDown에서 모든 데이터를 제거하는 함수, DropDown에 새 직원명을 추가하는 함수입니다.

ClearAll이라는 함수는 함수 정의구역 밑에서 바로~~~!!! 호출되고 있습니다. 이 함수의 호출로 인해 현재 페이지가 브라우저에 출력될 경우, 부모 페이지에 존재하는 Lname 아이디를 갖는 DropDown은 깨끗이 비워지게 될 것입니다.

이제 DropDown 에서 기존 데이터를 모두 지웠으니, Callback.aspx 페이지가 해 주어야 할 남은 작업은 바로 쿼리 결과로 얻어온 데이터(지정된 직급에 해당하는 직원이름)를 DropDown 컨트롤에 넣어주는 것입니다. 데이터를 조회하여 얻어오는 것은 서버 측의 작업이고, 그 데이터를 부모 페이지의 DropDown 에 넣어주는 것은 클라이언트 작업입니다. 해서, aspx 페이지에서는 데이터베이스 조회 로직을 수행하고 그 조회결과 얻어진 직원명 데이터를 가지고 클라이언트 스크립트 문자열을 만들어서 화면에 출력하기만 하면 됩니다. 그 다음 실제로 DropDown에 데이터를 채우는 작업은 화면에 브라우저에 로드 될 때, 클라이언트 스크립트가 동작해서 데이터를 채우겠죠. ^^

바로 그런 목적으로 작성된 소스가 이것입니다. 짜잔~~~ 짠짠짠~

Callback.aspx.cs

    public class Callback : System.Web.UI.Page
    {
        private const string conStr = "server=(local);database=Northwind;uid=sa;pwd=1";

        private void Page_Load(object sender, System.EventArgs e)
        {
            string title = string.Empty;
            if (Request["title"] != null) title = Request["title"];

            if (!this.IsPostBack)
            {
                string sql = "SELECT EmployeeID, LastName FROM Employees WHERE title = @Title";
                SqlConnection con = new SqlConnection(conStr);
                SqlCommand cmd = new SqlCommand(sql, con);

                cmd.Parameters.Add("@Title", SqlDbType.VarChar, 50);
                cmd.Parameters[0].Value = title;
                con.Open();
                SqlDataReader reader = cmd.ExecuteReader();

                // 조회 결과로 얻은 직원명들 루프를 돌면서 스크립트로 꾸며준다.
                // AddOption('사번', '이름')의 형태로 꾸미도록 한다.
                string script = "<script language=javascript>";
                while(reader.Read())
                {
                    script += string.Format("AddOption('{0}', '{1}');\n", reader[0], reader[1]);
                }
                script += "</script>";

                con.Close();

                // 완성된 스크립트 문자열을 화면에 출력하고 클라이언트 스크립트가 기동되게 한다.
                this.RegisterStartupScript("addScript", script);
            }
        }

        .. 중략 ..

소스에서는 이전에 설명드린 것처럼, 데이터베이스를 조회해서 얻어진 결과를 문자열 결합하고 있습니다. 즉, 직원 이름들을 AddOption(직원코드, 직원명) 형태의 문자열로 만들고 있는 것이죠. 그리고, 다 만들어진 문자열을 페이지에 스크립트로 등록하고 있습니다. 해서, 그 결과 최종 페이지(IFRAME에 로드 되는 페이지)의 HTML 결과물은 다음과 같게 됩니다.

<script language="javascript">
    function ClearAll()
    {
        var count = parent.document.all.Lname.options.length;
        for(var i = 0; i < count; i++)
            parent.document.all.Lname.options.remove(0);
    }

    function AddOption(value, text)
    {
        var oOption = document.createElement("OPTION");
        oOption.text = text;
        oOption.value = value;
        parent.document.all.Lname.options.add(oOption);
    }

    ClearAll();
    parent.document.all.Lname.disabled = false;

</script>
<HTML>
    <body>
        <form name="Form1" method="post" action="Callback.aspx?Title=Sales%20Representative" id="Form1">
            <input type="hidden" name="__VIEWSTATE" value="dDwtNjU0MzcyMTk1Ozs+6rHmHpG6XjWEoknzx+x8U2/561s=" />

<script language=javascript>
    AddOption('1', 'Davolio');
    AddOption('3', 'Leverling');
    AddOption('4', 'Peacock');
    AddOption('6', 'Suyama');
    AddOption('7', 'King');
    AddOption('9', 'Dodsworth');
</script>

        </form>
    </body>
</HTML>

파란색 코드 구역이 서버의 처리로 인해 추가적으로 들어가게 되는 부분이며, 그 부분은 클라이언트 브라우저에서 실행되서, 부모 페이지의 DropDown 컨트롤에 직원이름을 동적으로 추가하게 됩니다.

크게 어렵지는 않은 내용일 것이라 생각됩니다. 단, 이 방식은 Callback.aspx 페이지를 다른 용도로 재 사용할 수는 없다는 단점을 가지고 있는 방식입니다. 즉, 각각의 비동기 처리가 필요한 상황마다 별도의 Callback.aspx 페이지가 만들어져야 한다는 단점을 가진다는 것이죠. 하나의 로직을 위해서, 별도의 aspx 페이지가 여러 개 요구된다는 부분이 이 방식의 단점이라면 단점일 것입니다.

이제 완성된 페이지를 한번 실행해 보도록 하겠습니다. 메인 페이지는 처음 로드 될 경우 다음과 같이 직급만이 DropDown 컨트롤에 나타나는 것을 볼 수 있을 것입니다.



그리고, 첫 번째 DropDown에서 원하는 직급을 선택하는 순간, 메인 페이지는 변경됨 없이, IFRAME 구역이 작업을 처리하여, 그 결과는 메인 페이지의 두 번째 DropDown에 반영하는 것을 보실 수 있을 것입니다.



모든 처리가 완료되었다면, 이제 IFRAME 태그를 다음과 같이 스타일을 지정하여 눈에 보이지 않도록 합니다.

<IFRAME id="CallBackFra" width="400" Height="50" style="display:none"></IFRAME>

그러면, 이제 화면은 깔끔하게 나타나게 될 것이며, 비동기 호출도 매끄럽게 이루어지는 것처럼 보이게 될 것입니다.



어떠세요? 나름대로 맘에 드시나요?

그렇습니다. 그런대로 훌륭한 방법임에는 틀림이 없습니다.

하지만, 이 방식은 손도 많이 갈 뿐더러, 각각의 처리에 대해 많은 asp, aspx 페이지가 요구된다는 단점 및 재사용성의 결여라는 단점이 있는 방식입니다. 해서, 좀 더 개선된 방식들도 시간이 지남에 따라 등장하게 되었습니다.

다음 시간에는 비동기 호출의 두번째 방식 XMLHTTP를 이용하는 방식에 대해서 알아보겠습니다.

 


asp.net비동기호출_callback01.zip


Posted by SB패밀리

지식 근로자들은 원시 숫자들이 그래프 형식으로 표현되었을 때 좀더 데이터를 효율적으로 이해할 수 있습니다. 웹 페이지에서 데이터베이스 정보를 보여줄 때 특히 차이가 납니다. 해당 데이터를 보여줄 때 간단한 차트일지언정 그것을 사용하고, 사용하지 않고의 차이는 분명합니다. 과거에 ASP 의 경우, 데이터 기반의 차트를 동적으로 생성하려면 서드파티 업체에서 만든 이미지 생성 COM 컴포넌트를 구매해야 했습니다. ASP.NET 이 나온 지금, 개발자들은 C# 언어로 .NET Framework에서 제공되는 그리기 관련 클래스를 이용하여 동적 이미지나 차트를 쉽게 생성할 수 있습니다. 
--------------------------------------------------------------------------------

ASP의 놀라운 성공을 이끈 가장 중요한 요소는, 개발자들이 쉽게 데이터중심의 웹 페이지를 개발할 수 있다는 점이었습니다. 특히 인트라넷에서, 데이터를 다루는 웹 페이지의 일반적인 예는 보고서 페이지입니다. 그런 페이지들은 데이터베이스로부터 가져온 데이터를 방문자가 쉽게 이해할 수 있는 방식으로 표현을 해줍니다. ASP 페이지에서 텍스트 기반의 보고서 정보를 출력하는 것은 너무 쉬운 일이지만, 그러한 정보를 그래픽적인 요소까지 곁들여 차트양식으로 보여주는 것은 ASP의 영역을 넘는 전혀 새로운 기능입니다. 
필자가 ASP를 시작한 것은 지난 1998년 1월 이었습니다. 아마도 바로 그날, 한국에선 눈이 왔을지도 모르겠습니다. 주어진 과제는 제가 근무하고 있던 컨설팅 회사를 위해 사내 보고서 시스템을 개발하는 것이었습니다. 하루 업무가 끝날 때 쯤, 각 컨설턴트들은 회사 인트라넷 시스템 개발 착수와 관련해서 의논을 했습니다. 각 컨설팅 그룹의 관리자들은, 개별 컨설턴트와 그룹단위로 지나간 수익을 보여주는 보고서 양식을 원했습니다. 정보를 보여주기 위해, 텍스트 양식으로 된 숫자를 단순히 나열하는 것이 아닌, 다양한 차트와 그래프로 지나간 수익과 앞으로 기대되는 수익을 보고 싶다고 요청했습니다. 
필자가 ASP를 시작한 것은 지난 1998년 1월 이었습니다. 아마도 바로 그날, 한국에선 눈이 왔을지도 모르겠습니다. 주어진 과제는 제가 근무하고 있던 컨설팅 회사를 위해 사내 보고서 시스템을 개발하는 것이었습니다. 하루 업무가 끝날 때 쯤, 각 컨설턴트들은 회사 인트라넷 시스템 개발 착수와 관련해서 의논을 했습니다. 각 컨설팅 그룹의 관리자들은, 개별 컨설턴트와 그룹단위로 지나간 수익을 보여주는 보고서 양식을 원했습니다. 정보를 보여주기 위해, 텍스트 양식으로 된 숫자를 단순히 나열하는 것이 아닌, 다양한 차트와 그래프로 지나간 수익과 앞으로 기대되는 수익을 보고 싶다고 요청했습니다. 
클라이언트에 독립적이기 위해 좀 더 나은 구상은 ASP 페이지에서 GIF 또는 JPG 이미지 파일을 생성해 내서 클라이언트의 브라우저에 파일로 보내주는 것이었습니다. 그러한 작업은 COM 컴포넌트를 사용하지 않고는 ASP 에서 불가능한 작업입니다. 다행히도, ASP 개발자들을 위해 서버측 그래프를 생성해 주는 수많은 서드파티 업체들이 COM 개체를 제공해 주고 있습니다. 필자가 발견한 ASPIn.com(http://www.aspin.com/home/components/graphics/charts (영문))만 해도 16 종류의 컴포넌트에 대한 링크를 제공해 줍니다. 
그러나 ASP.NET의 등장으로, 여러분들은 동적 차트와 그래프를 서드파티 COM 컴포넌트의 도움을 받지 않고도 생성할 수 있습니다. 마이크로소프트의 .NET Framework는 System.Drawing 네임스페이스에서 그래프와 관련된 많은 클래스를 제공해 주고 있습니다. 거기서 제공되는 클래스들을 이용해서 독립 윈도우 기반 응용 프로그램이나 ASP.NET 웹 페이지 모두에서 다양한 포맷으로 된 이미지를 생성하고 편집할 수 있습니다. 클라이언트로부터 요청이 들어왔을 때, 이러한 클래스들을 이용하여 여러분들은 데이터베이스 정보에 기반한 차트를 보여주는 ASP.NET 웹 페이지를 생성할 수 있습니다. 요청에 대한 응답으로 이미지를 보내줄 수가 있는 것입니다. 
완벽한 동적 차트를 목표로 하기 전에, 우선 어떻게 ASP.NET 페이상에서 프로그램적인 방법으로 이미지를 생성할 수 있는지에 대해서 살펴보겠습니다. 

간단한 이미지를 보여주는 코드 작성
.NET Framework에서 제공되는 System.Drawing 네임스페이스는 이미지를 생성/편집하는 데에 필요한 모든 클래스를 포함합니다. 이미지 생성과 관련해서는 2가지 클래스, Bitmap, Graphics 가 제공됩니다. Bitmap 클래스는 캔버스로, Graphics 클래스는 화필로 생각해 볼 수 있습니다. 잠시 후에, 팔레트 생성을 위해 Bitmap 클래스를 어떻게 사용하는 지에 대한 방법과, 그림이 완성되었을 때 Bitmap 클래스에서 제공되는 Save 메서드를 이용해서 파일로 저장 또는 스트림으로 직접 전송하는 것을 둘 다 보여드리겠습니다. Graphics 클래스는 이미지, 도형, 문자열을 그리기 위해 필요한 모든 메서드를 포함합니다. 
캔버스를 생성하기 위해서, 아래와 같이 Bitmap 클래스의 새 인스턴스를 생성하는 것이 필요합니다. 

Bitmap myBitmap = new Bitmap(width, height); 
이제 필자는 캔버스 하나를 가지게 되었고, Graphics 클래스의 인스턴스와 페인트 브러쉬를 생성합니다. 이어서 사용해야 할 캔버스를 지정하기만 하면 됩니다. 이를 위해 Graphics 에서 제공되는 정적 메서드 FromImage를 사용할 수 있습니다. 그 메서드는 단 하나의 Image 인스턴스를 인자로 받아서 Graphics 인스턴스를 반환해 줍니다. (필자의 경우, Bitmap 클래스의 인스턴스를 전달했습니다. 참고로, Bitmap 클래스는 Image 클래스로부터 상속받았습니다.) 

Graphics myGraphics = Graphics.FromImage(myBitmap); 
이젠, 이미지, 도형, 문자열 등을 캔버스 위에 그릴 수 있는 준비가 되었습니다. 잠시 .NET Framework 설명서를 실행시키고 Graphics 클래스를 살펴보십시오. 도형 그리기와 관련된 방대한 분량의 메서드가 제공되는 것을 알 수 있습니다. 그러한 메서드들은 크게 2 가지로 쌍으로 존재하는 것이 눈에 뜨입니다. DrawShape와 FillShape에 대해서 각각 DrawEllipse와 FillEllips가 있습니다. Draw 류는 간단하게 도형의 외곽선을 그려주고, Fill 류는 도형을 그리고 내용 역시 채워줍니다. 예를 들어, 표 1에서 보는 것처럼 468×60 픽셀 규격의 광고 문구를 생성하고 싶다고 하면,표 2와 같은 코드를 사용할 수 있습니다. Page_Load 이벤트 처리기에 구체적인 코드가 구현되어 있습니다. 


표 1 표준 광고 배너

ASP.NET 웹 페이지에서 이미지 보기 
표 2 의 코드에서는 한가지 기능이 빠져 있습니다. 이미지를 저장하는 방법에 관해서입니다. 예제에서의 코드는 "MSDN


ASP.NET_Draw.zip


Posted by SB패밀리






1. Introduction
닷넷은 GDI+의 지원으로 더욱더 강력한 웹페이지를 만들어 낼수 있다고 생각한다. 이번 아티글은 동적으로 저장된 데이터를 가지고 바로 Line으로 표현하는 LineChart를 만들어 보고자 한다. 



2. Code

Line Chart클래스의 클래스이다. 현재 Current페이지의 ContentType 를 Image/jpeg로 설정한후 바로 브라우저에 그래픽을 뿌려지게 된다. 내부의 코드를 따로 설명하지 않아도 주석을 보면 코드를 충분히 이해 할수 있을것이다.

namespace에 using System.Drawing.Imaging;를 선언한다.



class LineChart

{



    public Bitmap b;

    public string Title="Default Title";

    public ArrayList chartValues = new ArrayList();//데이터저장

    public float Xorigin=0, Yorigin=0;

    public float ScaleX, ScaleY;

    public float Xdivs=2, Ydivs=2;



    private int Width, Height;

    private Graphics g;



    //데이터 구조체

    struct datapoint 

    {

        public float x;

        public float y;

        public bool valid;

    }



    //생성자,초기설정

    public LineChart(int myWidth, int myHeight)

    {

        Width = myWidth; Height = myHeight;

        ScaleX = myWidth; ScaleY = myHeight;

        b = new Bitmap(myWidth, myHeight);

        g = Graphics.FromImage(b);

    }



    public void AddValue(int x, int y) //데이터를 저장한다.

    {

        datapoint myPoint;

        myPoint.x=x;

        myPoint.y=y;

        myPoint.valid=true;

        chartValues.Add(myPoint);

    }



    public void Draw() //그리기

    {

        int i;

        float x, y, x0, y0;

        string myLabel;

        Pen YellowPen = new Pen(Color.Yellow,1);

        Brush YellowBrush = new SolidBrush(Color.Yellow);

        Font axesFont = new Font("arial",10);



        //먼저 이미지 사이즈와 초기화 지역을 잡는다.

        HttpContext.Current.Response.ContentType="image/jpeg";

        g.FillRectangle(new

            SolidBrush(Color.Black),0,0,Width,Height);

        int ChartInset = 50;

        int ChartWidth = Width-(2*ChartInset);

        int ChartHeight = Height-(2*ChartInset);

        g.DrawRectangle(new

            Pen(Color.Yellow,1),ChartInset,ChartInset,ChartWidth,ChartHeight);



        //위에서 설정한 Chart제목을 그린다.

        g.DrawString(Title, new Font("arial",14), YellowBrush,Width/3, 10);



        //X축 좌표 그리기

        for(i=0; i<=Xdivs; i++) 

        {

            x=ChartInset+(i*ChartWidth)/Xdivs;

            y=ChartHeight+ChartInset;

            myLabel = (Xorigin + (ScaleX*i/Xdivs)).ToString();

            g.DrawString(myLabel, axesFont, YellowBrush, x-4,

                y+10);

            g.DrawLine(YellowPen, x, y+2, x, y-2);

        }

        //Y축 좌표 그리기

        for(i=0; i<=Ydivs; i++) 

        {

            x=ChartInset;

            y=ChartHeight+ChartInset-(i*ChartHeight/Ydivs);

            myLabel = (Yorigin + (ScaleY*i/Ydivs)).ToString();

            g.DrawString(myLabel, axesFont, YellowBrush, 5, y-6);

            g.DrawLine(YellowPen, x+2, y, x-2, y);

        }



        //시작점을 0,0으로 설정한다.

        g.RotateTransform(180);

        g.TranslateTransform(0,-Height);

        g.TranslateTransform(-ChartInset,ChartInset);

        g.ScaleTransform(-1, 1);



        //데이터를 그래프로 표혀한다.

        datapoint prevPoint = new datapoint();

        prevPoint.valid=false;

        foreach(datapoint myPoint in chartValues) 

        {

            if(prevPoint.valid==true) 

            {

                x0=ChartWidth*(prevPoint.x-Xorigin)/ScaleX;

                y0=ChartHeight*(prevPoint.y-Yorigin)/ScaleY;

                x=ChartWidth*(myPoint.x-Xorigin)/ScaleX;

                y=ChartHeight*(myPoint.y-Yorigin)/ScaleY;

                g.DrawLine(YellowPen,x0,y0,x,y);

                g.FillEllipse(YellowBrush,x0-2,y0-2,4,4);

                g.FillEllipse(YellowBrush,x-2,y-2,4,4);

            }

            prevPoint = myPoint;

        }



        //바지막으로 객체를 저장하여 브라우저에 뿌려준다.

        b.Save(HttpContext.Current.Response.OutputStream, ImageFormat.Jpeg);

    }



    //소멸자

    ~LineChart() 

    {

        g.Dispose();

        b.Dispose();

    }

}



아래는 클래스를 생성하여 적용하는 예제이다. Title과 x,y의 Scale을 설정한다. 그리고 데이터를 ArrayList배열에 추가하면 간단한 차트 그래프가 완성된다. 

private void Page_Load(object sender, System.EventArgs e)

{

    //객체 생성하기

    LineChart c = new LineChart(640, 480);

    

    //차트의 크기를 설정한다.

    c.Title="Hoons Line Chart (ASP.NET GDI+)";

    c.Xorigin=0; c.ScaleX=500; c.Xdivs=5;

    c.Yorigin=0; c.ScaleY=1000; c.Ydivs=5;

    

    //임의의 데이터를 넣는다.

    c.AddValue(50,50);

    c.AddValue(100,100);

    c.AddValue(200,150);

    c.AddValue(450,450);

    

    //메모리에 그려서 브라우저로 전달한다.

    c.Draw();

}

Posted by SB패밀리

비주얼스튜디오2005 단축키 모음

Ctrl-K, Ctrl-H : 바로가기 설정. ( 작업목록 창에서 확인가능 )
Ctrl-K,K : 북마크 설정 / 해제
Ctrl-K,L : 북마크 모두 해제
Ctrl-K,N : 북마크 다음으로 이동
Ctrl-K,P : 북마크 이전으로 이동
Ctrl-K,C : 선택한 블럭을 전부 코멘트
Ctrl-K,U : 선택한 블럭을 전부 언코멘트(코멘트 해제)
Ctrl-F3 : 현재 단어 찾기
  -> F3 : 다음 찾기

Ctrl-F7 : 현 파일만 컴파일
            : 현 프로젝트만 빌드
Ctrl-Shift-B : 전체 프로젝트 빌드
Ctrl-F5 : 프로그램 시작

Ctrl-i : 일치하는 글자 연속적으로 찾기
Ctrl+i 를 누르면 하단에 자세히보면, "증분검색" 이라는 텍스트가 나온다.
그러면 그때 찾기 원하는 단어를 입력할때마다 일치하는 위치로 바로바로
이동한다. (좋은기능)
타이핑은 "증분검색" 이라는 텍스트옆에 커서는 없지만 입력이된다.
입력하는 문자를 수정하려면, backspace로, 그만 찾으려면 엔터.

줄넘버 보여주기 : 도구 > 옵션 > 텍스트편집기 > 모든언어 > 자동줄번호 선택하면 됨.

Ctrl+ - (대시문자), Ctrl+Shift+ -  :
현재 커서를 기억하는 Ctrl+F3(VS6에서), Ctrl+K,K(VS7에서) 와는 달리
사용자가 별도로 입력을 해주는건 없고, 단지 이전에 커서가 있었던곳으로
위 키를 누를 때마다 이동된다. (shift를 이용하면 역순)

Ctrl-F12 : 커서위치 내용의 선언으로 이동( 즉, 대략 헤더파일 프로토타입으로 이동)

F12 : 커서위치 내용의 정의로 이동( 즉, 대략 CPP파일 구현부로 이동)

Shift+Alt+F12 : 빠른기호찾기 ( 이거 찾기보다 좋더군요. 함수나 define등 아무거나에서 사용)

Alt+F12: 기호찾기. (s+a+f12 비교해볼것)

Ctrl-M, Ctrl-L : 소스파일의 함수헤더만 보이기 (구현부는 감추고) (토글 키)
Ctrl-M, Ctrl-M : 현재 커서가 위치한 함수를 접는다/편다. (토글 키)

#include "파일명" 에서 "파일명" 파일로 바로 직접이동
하고 싶을경우 -> Ctrl-Shift-G


<편집>---------------------------------------------------------------------------
Ctrl-F : 찾기 대화상자
Ctrl-H : 바꾸기 대화상자
Ctrl-Shift-F : 파일들에서 찾기 대화상자
Ctrl-Shift-H : 파일들에서 바꾸기 대화상자
Ctrl-G : 해당 줄로 가기 (별로 필요없음)
Ctrl-K,Ctrl-F : 선택된 영역 자동 인덴트 (VS6의 Alt-F8기능)
Ctrl-] :괄호({,}) 쌍 찾기 : 괄호 앞이나 뒤에서 눌러서 닫거나,
여는 괄호이동
Ctrl-Shift-Spacebar : 함수이름편집중 툴팁으로나오는 함수와매개변수설명이 안나올경우, 강제로 나오게

alt-LButton ->Drag : 원하는 영역의 블럭을 세로로 잡기

Ctrl+Shift+R (키보드 레코딩) : 
  가끔 연속된 연속기만으로는 부족한경우가 있다.
  이럴때, 몇번의 키동작으로 레코딩하여, 이것을 반복하고 싶은경우가있다.
  이때 Ctrl+Shift+R 을 누르고, 원하는 동작들을 수행후, 다시 Ctrl+Shift+R을
  눌러 종료한다.  이 중간동작을 원하는 위치에서 반복하고 싶다면 
  Ctrl+Shift+P 를 누른다.
 
Ctrl+Shift+V (히스토리 붙이기) :
  Ctrl + V와는 달리 클립보드에 있는 복사된내용을 돌아가면서 붙여준다.
  따로 복사를 해주거나 할 필요는 없다. 그냥 Ctrl+C로 계속 원하는것을
  복사하면 된다.

Ctrl-Z : 이전으로 되돌리기

Ctrl-Shift-Z : 되돌렸다, 다시 복구하기

 

 

<디버그/빌드>-------------------------------------------------------------------------
F5 : 디버그 시작
F9 :디버그 브렉포인트 설정
Ctrl-F9 : 현위치 설정된 브렉포인트 해제
Ctrl-Shift-F9 : 모든 브렉포인트 해
Shift-F5 : 디버그 빠져나오기
Ctrl-F10 : 커서가 있는곳까지 실행
Shift-F11 : 현 함수를 빠져나감.

Shift+Ctrl+B :  전체 빌드(프로젝트가 여러개있을경우 모두 빌드)
Alt+B, C : 해당 프로젝트만 정리.
Alt+B, U : 해당 프로젝트만 빌드.


 

<창관련>-------------------------------------------------------------------------

Shift+Alt+Enter : 전체 창 (토글 됨)
F4 : 속성창 보여준다.
Ctrl+Alt+X : 리소스에디터 툴박스창
Ctrl+Alt+K : 작업목록 창.


 

비주얼 스튜디오를 쓰다가 단축키를 잊어먹거나 까먹어서 잘 못쓰는 경우가 많아 정리를 해보았다. 

단축키설명
Ctrl + TabEdit하고 있는 Child Window 간의 이동
Ctrl + F4현재 Edit하고 있는 Child Window를 닫기
Ctrl + I문자열 입력 점진적으로 문자열 찾기 (Incremental Search)
Ctrl + F3현재 커서에 있는 문자열 찾기 fowared (블록 지정 안 해도 됨)
Shift + F3현재 커서에 있는 문자열 찾기 backward
F3찾은 문자열에 대한 다음 문자열로 이동 (Next Search)
Ctrl + H문자열 찾아 바꾸기 (Replace)
Ctrl + Left/Right Arrow단어 단위로 이동
Ctrl + Delete 또는 Backspace단어 단위로 삭제
Ctrl + F2현재 라인에 북마크 지정/해제
F2지정된 다음 북마크로 이동
Ctrl + Shift + F2지정된 모든 북마크를 해제
F9현재 라인에 Breakpoint를 지정/해제
Ctrl + Shift + F9현재 Edit하고 있는 소스파일에 지정된 모든 Breakpoint 해제
Ctrl + ] 또는 E'{'괄호의 짝을 찾아줌 ('{'에 커서를 놓고 눌러야 함}
Ctrl + J, K#ifdef 와 #endif의 짝을 찾아줌
Ctrl + L한 라인을 클립보드로 잘라내기 (Cut)
Ctrl + Shift + L한 라인을 삭제
Alt + Mouse블록 설정 세로로 블록 설정하기 (마우스로)
Ctrl + Shift + F8세로로 블록 설정하기 (키보드로), 취소할 때는 Esc키를 눌러야 함
블록 설정 -> Tab선택된 블록의 문자열을 일괄적으로 들여쓰기(Tab) 적용
블록 설정 -> Shift + Tab선택된 블록의 문자열을 일괄적으로 내어쓰기 적용
Alt + F8 -> Tab 또는 Shift + Tab들여쓰기 자동 조정 (Tab:들여쓰기, Shift + Tab : 내어쓰기)
Ctrl + T현재 커서에 있는 변수/함수에 대한 Type이 Tooltip 힌트 창에 나타남
Ctrl + Alt + T멤버 변수/함수 목록에 대한 팝업 창이 나타남
Ctrl + Shift + T공백/콤마/파이프/괄호 등을 기준으로 좌우 문자열을 Swap시킴
Ctrl + Shift + 8문단기호 표시/감추기 : Tab은 ^, Space는 .으로 표시
Ctrl + D툴바의 찾기 Editbox로 이동
Ctrl + Up/Down Arrow커서는 고정시키고 화면만 스크롤 시키기


디버깅에 관련된 단축키 하나 더. 
변수이름을 적어 놓고 브래이크 포인터의 위치 여부와 관계 없이 변수의 내용을 추적하는 기능이 Watch Window에 들어 있다. 디버그 모드에서 추가하고픈 변수나 등등 앞에 커서를 위치 시킨후 Shift + F9를 누르면 그냥 바로 추가된다. 


Tab 들여쓰기,자동완성
Shift+Tab 내어쓰기
블록 설정 >> Tab 선택된 블록의 문자열을 일괄적으로 들여쓰기(Tab) 적용 
블록 설정 >> Shift+Tab 선택된 블록의 문자열을 일괄적으로 내어쓰기 적용

 


F2 설정된 북마크로 이동
F2 설정된 다음 북마크로 이동
F3 다음 단어 찾기
F4 다음 에러메세지로 이동
F5 Debugging 모드로 작동
F9 현재 라인에 BreakPoint를 설정/해제
F10 Debugging 모드로 작동하되 엔트리 포인트부터 시작
F12 마우스 오른쪽 버튼 눌렀을때 go to definition 단축기

 

 

Ctrl+Up/Down Arrow 커서는 고정시키고 화면만 스크롤 시키기 
ctrl+*(맨오른쪽 부분) 위에서 F12 눌렀을때 이전화면으로 돌아가기 
Ctrl+Left/Right Arrow 단어 단위로 이동 
Ctrl+Delete 또는 Backspace 단어 단위로 삭제 
Ctrl+Tab Edit하고 있는 Child Window 간의 이동 
Ctrl+Space 인텔리센스 출력(멤버목록 팝업창)

Ctrl+F2 북마크 설정
Ctrl+F2 현재 라인에 북마크 지정/해제 
Ctrl+F3 현재 커서에 있는 단어로 찾기
Ctrl+F4 현재 Edit하고 있는 Child Window를 닫기 
Ctrl+F5 빌드 후 프로그램 실행
Ctrl+F10 Debugging 모드로 작동하되 커서의 위치까지

Ctrl+] 괄호 짝 찾기
Ctrl+] 또는 E {괄호의 짝을 찾아줌 ({에 커서를 놓고 눌러야 함} 
Ctrl+A 전체 선택
Ctrl+B 브레이크 포인트 관리 메뉴
Ctrl+D 툴바의 찾기 Editbox로 이동 
Ctrl+E 현재 괄호랑 맞는 괄호를 찾아준다.
Ctrl+F 현재 커서에 있는 단어로 찾기
Ctrl+G 라인 바로 가기(GoTo)
Ctrl+H 문자열 찾아 바꾸기 (Replace)
Ctrl+I >> 문자열 입력 점진적으로 문자열 찾기 (Incremental Search) 
Ctrl+J, K #ifdef 와 #endif의 짝을 찾아줌 
Ctrl+L 한 라인을 클낳링藥?잘라내기 (Cut) 
Ctrl+T 현재 커서에 있는 단어의 툴팁정보 보기
Ctrl+U 모두 소문자로
Ctrl+W 클래스 위자드 (MFC 코딩시에만 사용)

Ctrl+Shite+Space 현재 가르키고 있는 함수의 매개변수 보기

Ctrl+Shift+F2 지정된 모든 북마크를 해제 
Ctrl+Shift+F3 이전 단어 찾기
Ctrl+Shift+F8 열 블럭(키보드로), 취소할 때는 Esc키를 눌러야 함 
Ctrl+Shift+F9 현재 Edit하고 있는 소스파일에 지정된 모든 Breakpoint 해제

Ctrl+Shift+8 문단기호 표시/감추기 : Tab은 ^, Space는 .으로 표시

Ctrl+Shift+L 한 라인을 삭제 
Ctrl+Shift+P 매크로 실행
Ctrl+Shift+R 매크로 기록
Ctrl+Shift+T 공백/콤마/파이프/괄호 등을 기준으로 좌우 문자열을 Swap시킴 
Ctrl+Shift+U 모두 대문자로

Ctrl+Alt+T 멤버 변수/함수 목록에 대한 팝업 창이 나타남

 

 

Alt+MouseMove 컬럼 Selection

Alt+B -> E Clean
Alt+B -> R Rebuild All
Alt+E+I 프로젝트 내의 모든 파일에서 찾기
Alt+G 그 함수가 선언된 파일이나 위치로 고!
Alt+O 헤더와 소스파일을 번갈아 보여줌

Alt+0 WorkSpace 윈도우 
Alt+2 output 윈도우

Alt+F7 Project Setting
Alt+F8 들여쓰기 자동 조정
Alt+F9 브레이크포인트 관리

Posted by SB패밀리
쌈꼬쪼려 소백촌닭

금액, 숫자를 문자로 바꾸기

금액 형식의 숫자를 한글로 바꾸어 반환하는 메서드입니다.

문자열 형식의 숫자를 인수로 넘기는 경우에는
콤마(,)는 허용, 그 외 숫자형식이 아닌 문자는 에러메시지로 처리합니다.
소숫점이하의 수는 소숫점에서 반올림 하여 계산합니다.

public string NumberToHangul( double number)
{
    return  NumberToHangul( number.ToString() );
}

public string NumberToHangul( string strNumber)
{
    // 콤마(,)제거
    strNumber = strNumber.Replace(",","");

     // 문자열이 숫자형식인지 체크
    for( int i=0; i<strNumber.Length; i++)
    {
        if( !Char.IsNumber( strNumber, i) && strNumber[i] != '.')
            return "숫자형식이 아닙니다.";
    }

    // 소숫점 이하 숫자가 존재하면 반올림처리
    if( strNumber.IndexOf(".") >=0 )   
    {
        double tempNum = Convert.ToDouble( strNumber );
        strNumber = Convert.ToString( Math.Round( tempNum ) );
    }

    string[] arrayAmt = new string[]
    {"일", "이", "삼", "사", "오", "육", "칠", "팔", "구", "십"};

    string[] arraypos = new string[] {"", "십", "백", "천"};

    string[] arrayUnit = new string[]
    {"", "만", "억", "조", "경", "해", "자", "양", "구", "간", "정", "재", "극",
        "항하사", "아승기", "나유타", "불가사의", "무량대수"};

     int pos = strNumber.Length%4; //자리수
    int unit = strNumber.Length/4;

    string korNumber = String.Empty;
    int op = 0;

    for( int i=0; i<strNumber.Length; i++ )
    {
        if( pos==0 ) pos=4;
        int num = Convert.ToInt16( strNumber.Substring(i,1) );
        if( num > 0 )
        {
            korNumber += arrayAmt[ num-1 ];
            korNumber += arraypos[ pos-1 ];
            op=1;
        }
        if(pos == 1)
        {
            if( op == 1 ) korNumber += arrayUnit[ unit ];
            unit--; op = 0;
        }
        pos--;
    }
    return korNumber ;
}

Posted by SB패밀리
쌈꼬쪼려 소백촌닭

사용자의 인터넷익스플로러 창 모두 닫기

//네임스페이스 선언
using System.Diagnostics;

//현재 사용자 컴퓨터에 열려 있는 익스플로러의 창을 모두 닫는다.
public static void KillExplorer()
{
   Process[] procs = Process.GetProcessesByName("IEXPLORE");
   for(int i=0; i< procs.Length; i++) procs[i].Kill();
}

현재 실행중인 프로세스를 죽이는 방법으로 iexplore를 종료시킵니다.

Posted by SB패밀리
쌈꼬쪼려 소백촌닭

출처:  http://support.microsoft.com/

파일이름으로 응용 프로그램 시작하기

using System;
using System.Diagnostics;

namespace Namespace1
{
    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {             

            //Get path of the system folder.
            string sysFolder =   Environment.GetFolderPath(Environment.SpecialFolder.System);

 

            //Create a new ProcessStartInfo structure.
            ProcessStartInfo pInfo = new ProcessStartInfo();

 

            //Set the file name member.
            pInfo.FileName = sysFolder + @"\eula.txt";

 

            //UseShellExecute is true by default. It is set here for illustration.
            pInfo.UseShellExecute = true;

            /*
                UseShellExecute는 실행 파일 이름(.exe) 대신 파일 확장명이나
                파일 형식을 기반으로 시작하는 프로세스를 지정합니다.
                이 속성은 기본적으로 true로 설정됩니다.
            */

 

            Process p  = Process.Start(pInfo);
            // 파일은 일반적으로 Notepad.exe인 .txt 파일 확장명에 연결된 응용 프로그램을

            // 사용하여 열립니다.

 

            /*
                UseShellExecute가 기본적으로 true이기 때문에 프로세스를 시작할 때
                ProcessStartInfo를 사용할 필요가 없습니다..
                아래와 같이 하나의 코드 줄을 사용하여 연결된 응용 프로그램을 시작할 수 있습니다.
                Process p  = Process.Start(@"C:\winnt\system32\eula.txt");

 

                컴퓨터에 연결된 응용 프로그램이 설치되어 있지 않거나
                 레지스트리의 연결이 올바르지 않을 수도 있으므로
                오류가 발생했을 때 사용하는 응용 프로그램에서 경고를 수신할 수 있도록
                이 코드를 try...catch 블록 안에 넣는 것이 좋습니다.

            */
        }
    }
}

Posted by SB패밀리