GIGO MIND DEV BLOG

ASP.NET FRAMEWORK AND CORE(1)

DOT NET에 대해 알기 전.. C#?

Microsoft가 만든 Object-Oriented Programming Language, C# = C++++, 자바와 매우 흡사.
자바는 JVM이 있듯, C#은 .NET Framework가 있다 (가상머신).

JAVA가 겪는 일을 대충 정리하자면,
Java Source 는 Compile을 통해 Java Byte Code라는 것으로 변한다. 그리고 이 바이트코드는 Java Virtual Machine(JVM)이 번역해서 Native code(Machine code)로 쓰이게 된다.

C#같은 CLS(Common Language Source)가 겪는일은,
CLS(C#,Visual Basic)는 Compile을 통해 Intermediate Language(IL)이라는 것으로 변한다. 그리고 이 IL은 Common Language Runtime(CLR)이 번역해서 Native Code(Machine code)로 쓰이게 된다.

가상머신인 JVM이 하는 Garbage Collection과 같은 기능은 CLR에도 있다.


여기서 Garbage Collection을 이해하기 위해 Memory에 대한 설명을 조금 해본다.

C에서는 Primitive Type, 즉 int, double, short 등등과 같은 데이터 타입들은 전부 메모리의 Stack 부분에 저장 된다. 이 구조가 존재하기에, 앞서 말한 primitive type들은 Scope라는게 필수적으로 존재한다. Local Variable과 같은 녀석들은 그 Function 내부 안에서만 보여질 수 있다(visible).
왜냐고? Function 하나하나가 메모리에서는 stack으로써 존재하며, return을 하거나 다른 function으로 넘어갈 때는 Stack의 다른 element로 넘어가기 버리기 때문에, primitive type같이 그 function 내부, 즉 stack의 한 부분에 저장된 녀석들은 그 function 내부에서밖에 볼 수 없는 것이다.

하지만 당연하겠지만, 우리는 변수의 값을 Stack의 다른 부분에서도 보고 싶어한다. 값을 보내고, 바꾸고, 받아서 쓰고, 또 primitive type말고 다른 복잡한 데이터 타입도 써보고 싶다. 이를 위해, Stack 말고도 Dynamically Allocatable Memory, Heap이라는 부분을 만들어 놨다. 그리고 C는 pointer라는 녀석을 쓸 수 있게 해줬다.

Heap은 요청에 따라서 어느 정도 사이즈의 memory를 쓸 수 있게 나눠주는 녀석이다. 즉, Integer같은 4바이트의 메모리를 Stack같이 곧 무너져 없어질 녀석 말고, Heap에게 가서 4바이트만 나눠주십쇼, 하고 그 장소에 넣어두면, 그 메모리를 안쓴다고 하기 전까지는 안전하게 보관되는 것이다.

Pointer는 말 그대로 메모리의 주소를 가리키는 녀석이다. 그리고 이 녀석 또한 메모리에 저장이 되므로, 자신 또한 메모리 주소가 있다. 쓰고 싶은 변수의 메모리 주소만 알면, 바꾸고, 다른 데서 보고 할 수 있는 것이다. 그리고 당연하겠지만, 이 포인터라는 녀석들은 다 쓰이고 나서 가리키고 있는 대상, 즉 메모리 주소를 지워버리지 않으면 나중에 또 참조 될 수도 있고, 더 이상 쓰이지 않는 주소를 가리키고 있을 수 있으므로, Garbage가 되버린다. 또한 Heap에서 나눠준 메모리 또한 아무도 참조하지 않는, 포인터 하나 가리키고 있지 않는 외로운 상태가 돼버리면 나같이 친구없는 쓰레기, Garbage가 돼버리는 것이다.

자, 위에 Garbage 설명은 끝났다. 다음 문단은 읽기 귀찮으면 무시해도 된다. Array와 같은 데이터 구조의 원리 설명이다.
당연하겠지만, primitive type의 세상인 C에선 array같은 것은 마법같이 그냥 존재하는게 아니다.
구조를 알아야 쓸 수 있는 것이다. Array는 메모리 주소에서 채울 데이터 크기 * 어떠한 크기를 지닌 한 뭉탱이를 뜻한다.
무슨 말이냐고? Heap의 메모리 주소 0에 사이즈가 40바이트를 텅텅 비워놨다. 그리고 여기를 하나당 4바이트인 Integer을 채운다고 생각해보자. 몇개 채울 수 있는가?
10개의 값을 채울 수 있다.
Integer Array of Size 10 완성이다.
index 0의 int element는 어떻게 참조하나? 메모리주소 0을 가리키는 포인터의 값을 보면 된다. index 9인 마지막 int element는 어떻게 참조하나? 메모리주소 0 을 가리키는 포인터의 0 + 4(bytes)*9인 메모리주소 36을 보면 된다. 포인터의 메모리주소에 offset을 더하고 빼는 식인 거다.

자, 서론이 길었다.
저런식으로 생성되는 Garbage는 C에 국한된 것이 아니다.
Object-Oriented Language라고 불리우는 Java는 Object를 쓰고 난 뒤에 발생 할 수 있는 pointer ( reference ) 들을 어떻게 살포시 버려주는지 생각해보자.
Java도 Primitive types들이 존재하며, C와 똑같이 동작한다.
Object들은 Heap 메모리를 이용한다. 그 말은 즉슨, new Object() 라는 식으로 instance를 만들었을 때, 위에 설명한 Array와 같이 한 뭉탱이의 메모리가 그 instance를 위해 주어졌다는 것이다. 그리고 그 Object instance를 가리키는 reference는 stack안의 function에서 쓰이고 있을 터이다.
당연하게 C를 공부한 사람이라면, 그 Function이 return되고 reference를 통해 참조하여 쓰여지던 Object instance가 더 이상 쓰이지 않을 것이라고 생각 되면, Free( Heap에서 아무도 참조하지않고 찾아주지 않는데 특정 크기를 나눠 준 메모리를 allocate 될 수 있게 해주는 것)를 하고 메모리 주소를 가리키는 pointer를 없애줘야 한다고 생각해야 정상이다. 그리고 이는 틀리지 않았고 사실 JVM이 하고 있는 정확한 일이다. 약간의 Overhead를 이용, 유저가 해야할 일들을 포착해, 더 이상 참조받고 있지 않는 Object, allocation memory 가 존재할 시 Free하여 메모리를 알아서 관리해 주는 것이다.


C#은 OOP의 특징인 Encapsulation, Polymorphism 등의 속성을 모두 가지고 있다.

즉, Java의 Private, Default, Protected, Public + (internal = default, protected internal = protected) 등과 같은 Access Modifiers 를 클래스 이름, 메소드 이름, 변수 이름 앞에 붙임으로써, Scope를 클래스 내부에서만 쓰이게 할 지, 패키지 내부에서 쓰이게 할 지, Subclass에서 쓰이게 할지, 아니면 프로그램 내에서 쓰이게 할지 정할 수 있다.

| C#                  | Java            | Scala                    | Meaning                                                                                                       |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| no modifier         | private (1)     | private                  | accessible only within the class where it is defined                                                          |
| private             |                 |                          |                                                                                                               |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| protected           |   --            | protected                | accessible within the class and within derived classes (2)                                                    |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| internal            | no modifier     | private[package_name]    | accessible within the same assembly (C#) or within the same package (Java / Scala) (3)                        |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| protected internal  | protected       | protected[package_name]  | accessible within derived classes (2) and anywhere in the same assembly (C#) or package (Java / Scala) (3)    |
|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| public              | public          | no modifier              | accessible anywhere                                                                                           |
 ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
출처: https://stackoverflow.com/questions/22968085/what-are-the-equivalents-of-cs-access-modifiers-in-java-and-scala

어쨋든, C#은 C++과 Java를 합친 것처럼 보인다.

Java에서의 프로젝트는 패키지라고 하는 것을 이용해 여러가지 클래스를 묶어서 쓸 수 있다.
패키지는 Project를 포함하며, 그 Project안의 클래스들의 모음이며, 실제 소스 코드의 위치, 즉 파일시스템의 Path를 “.” delimiter를 이용해 나타낸다. 흔히 자바에서 다른 라이브러리의 import에서 보이는 java.util.*과 같은 것들이 사실은 패키지의 java/util/classes들을 import하는것과 같은 것이다.
그리고 이 패키지의 쓰임새의 큰 이유 중 하나는 클래스명의 Uniqueness이다.

C#은 C++의 namespace라는 것을 이용함으로써 자바가 File system의 경로를 따르는 패키지와 동일해야 한다는 점을 보완했다.

.NET Framework

Microsoft가 static website를 벗어나겠다고 만든 ASP (Active Server Page)가 시초.
JSP나 PHP와 매우 흡사하고 scriptlet과 비슷한 inline server code를 사용하는 것도 동일하다.
ASP classic 이나 ASP.NET(successor)이나 하는 일은 Server side에서 코드를 실행시킨다는 점이 같다.
(이 점은 보완상의 Webshell attack(유저가 *.aspx와 같은 파일을 서버에 보내 결과적으로 실행시킴으로써 서버의 shell 권한을 얻어버리는 무시무시한 공격)으로 이어질 수 있다는 구조적 특징도 있다.)
ASP.NET framework은 4.6까지 공식적으로 업데이트 되었고, 5까지 나올 예정이였으나, ASP.NET CORE이라는 cross-platform을 지원하는 클라우드 사용에 집중한 고성능 오픈 소스 프레임워크가 나옴에 따라 .NET 5, 6, 7,…은 CORE을 지칭하는 말이 되었다.

.NET framework는 Windows Server(IIS - Internet Information Service, 윈도우 기반 OS만 사용 가능)를 사용해야 하는 폐쇄적인 느낌이 강한 것이다.

.NET Framework에서는 대표적으로 WPF (VSC과 같은 디자인적으로 우수한 애플리케이션을 만드는데 쓰인다), WINDOW FORM, WEBFORM, MVC 등을 제공한다.

ASP.NET WEB PAGES

Single Page Application(SPA) 모델을 따른다.

ASP.NET Web Page를 만들 때는 Razor markup를 C#이나 VB와 함께 사용 하면 된다.

Razor은 markup syntax로써 C#과 같은 서버 코드를 ASP.NET 웹 페이지에서 사용할 수 있게끔 해준다.

JSP의 <% Java 코드 %> scriptlet같은 경우는 Razor에서는 @{C# 코드}과 동일하다. JSP의 <%= 결과 값 %> expression은 Razor에서는 @결과 값 과 동일하다.

그렇다면, JSP를 이용해서 웹 페이지를 만들어 본 사람은 ASP.NET Web Page를 Razor markup을 통해 만들 수 있어야한다. (Razor markup은 jsp와 비슷하고, Java는 C#과 비슷하니까)..

그렇다면 navbar, 즉 header나 footer등을 만들 때 쓰이는 기능인 다른 컨텐츠를 그대로 들고오는, JSP의 <%@ taglib prefix = “tagfile” tagdir=”src/tags” %> directive 과 같은 것도 있지 않을까?
있다. @RenderPage()라는 메소드가 이를 수행한다.
prefix를 굳이 설정하지 않아도, 컨텐츠가 넣어질 자리에 @RenderPage(“src/tags/header.cshtml”)를 쓰면 된다.

반대로 레이아웃을 먼저 셋업 해주고 싶을 때는 레이아웃 틀을 만들어 놓고, 컨텐츠를 채워 넣어줄 메소드를 써넣는다. 그리고 다른 페이지가 레이아웃 틀을 추가함으로써 그 페이지의 내용들을 컨텐츠에 채워 넣는 식으로 할 수 있다.
이는 복잡하게 들리나 사실 JSP에 존재하는 .tag 파일에 html과 를 이용해 틀을 만들어놓고, 다른 컨텐츠 파일에서 <%@taglib prefix=”layout” tagdir=..> 후에 <layout:”.tag”> 태그를 쓴 후에 틀의 각각 fragment에 를 통해 채워넣어 주는 것과 동일하다. Razor 에서는 @RenderBody()라는 메소드가 이를 수행한다. Header, Footer 사이에 body 부분만 바꿔주는 역할을 하는 것이다. 이렇게 레이아웃을 사용하는 웹 페이지들은 @{Layout="Layout.cshtml"}이라는 Razor의 Layout property를 레이아웃 태그파일로 바꿔주면 된다.

참고로 위의 header.cshtml, footer.cshtml, layout.cshtml 등의 파일들이 유저에게 노출되게 하지 않기 위해서는 _를 prefix로 붙이면 된다. 같은 원리로 _AppStart.cshtml 이라는 파일은 위험한 정보(sql passwords, email passwords, ..)를 담는 것에 사용되기도 한다.

어쨋든 위와 같은 기능을 통해 웹 사이트는 통일성을 가지게 된다.


ASP상의 URL에서 ~ operator은 linux의 home 으로 가는 디렉토리를 생각하면 편하다. linux에서는 루트디렉토리가 ‘/’ 로써 존재하고, ‘~’는 유저의 홈 디렉토리를 가리킨다.
이처럼 ASP.NET 상 URL에서 path 앞에 붙는 ~는 지금 현재의 asp.net application의 루트디렉토리를 가리킨다. 이는 웹사이트의 subdirectory일 수도 있는 것이다.

var imageFolder = "~/images";
위의 imageFolder은 
URL상으로 www.gigo.com/images 이며
파일시스템상으로는 C:\web\gigo\images 처럼
실제 root (web)이 아닌 app root (gigo)로부터 시작된다.

이렇게 만들어진 경로는 Server.MapPath라는 메소드를 통해 원래의 파일시스템상의 경로로 바꿔질 수 있다.

var actualPath = Server.MapPath(imageFolder);
-> C:\web\gigo\images

반대로 만들어진 경로를 브라우저가 해석 할 수 있게 바꿀 수도 있다. 이 때는 Href 메소드를 사용한다.

var imageFile = "~/images/image1";
<a href= @Href(imageFile)>image1</a>
-> /images/image1

ASP.NET Web Pages서의 서버사이드 코딩에서는 유저의 페이지에 대한 요청이 들어 왔을때 응답을 하기 전 두 가지의 코드를 수행할 수 있게끔 해준다.

  • _AppStart
  • _PageStart

Prefix로 _가 있는걸 보면 알 수 있듯이, 이 코드들은 브라우저에는 보이지 않는다.
그리고, AppStart는 App이 시작하기 전, 최소 한번 실행을 하며, 한번 실행 된 이후로는 다시는 실행 되지 않는 코드이다. PageStart는 각 Page가 load 되기 전 실행되며, 유저의 login state를 체크하는 등의 과정이 여기에 포함될 수 있다.


ASP.NET Web Pages에서 쓰이던 메소드와 Properties들은 하나의 Object의 derivatives 라고 볼 수 있다.
이는 JSP에서의 implicit objects와 동등하다.
JSP에서는 9개의 오브젝트들이 주어졌었다.

  • out JspWriter
  • request HttpServletRequest
  • response HttpServletResponse
  • config ServletConfig
  • application ServletContext
  • session HttpSession
  • pageContext PageContext
  • page Object
  • exception Throwable

이 중 주로 쓰이는 request, response, session등을 보면 알 수 있겠지만, jsp의 implicit object로써 코드 내부에서 아무 invocation 없이 쓰일 수 있었다.

-JSP-
<%if (session.getAttribute("user_id") == null) ..%>
<%if (request.getAttribute("errorMessage") == null) ..%>
<%=request.getRequestURL()%> 등등이 있다. 

ASP.NET Web Pages Object Properties

  • Layout LayoutPage
  • Page SharedData (Page.data=””)
  • Request HttpRequest
  • Server HttpServerUtility
  • IsPost (obsolete) checks HttpMethod==”Post”

Methods

  • href
  • RenderBody()
  • RenderPage(page)
  • Write(object)
  • WriteLiteral

.txt, .xml, .csv 포맷을 지닌 파일들은 flat files라고 불리운다.
이 들의 특징은 데이터를 넣을 수 있다는 것이다.
우리가 엑셀에서 테이블 형식으로 접하는 데이터들도 막상 .csv 파일을 텍스트 파일로 열어보면 comma-delimited values로 되어있다.

students.csv file을 열었을 때..
Ju, UMD
Ji, UVA
Hoon, UCA ...

이러한 text file들을 다룰 때는 App_Data에 넣어준다.
그리고, C#상에서는 File.ReadAllLines() 메소드를 이용해 array의 형태로 전달 받습니다. 당연히 인자로는 file의 physical path가 필요하다.

위에 다뤘던 Server.MapPath() 함수를 이용
@{
var file = Server.MapPath("~/App_Data/students.csv");
Array students = File.ReadAllLines(file);
}
로 변수를 받아 놓은 후,
Array를 iterate 해 데이터를 출력하면 된다.

JSP나 ASP 등의 Web Pages에서 데이터베이스를 다룰 때는 개념을 파악해 두면 편하다.

JSP나 ASP나 둘 다 결국에는 OOP 언어인 Java나 C#등의 코드를 이용해 데이터베이스에 연결하는 것과 동일하다.
그리고 이런 객체 언어들은 connection을 오브젝트로써, 각 DBMS 드라이버의 메소드를 이용해 받아오게 된다.
당연하게도, Connection은 켜져있는 SQL 서버의 데이터베이스의 오브젝트이며, 이 오브젝트의 메소드를 이용해 쿼리를 실행시켜 테이블의 데이터들을 받아오는 형태로 진행된다.

자바:
Connection con = DriverManager.getConnection("jdbc:postgresql://postgres/teamup", "root", "password");

String query = "SELECT * FROM TABLE";
PreparedStatement p = con.prepareStatement(query);
p.executeQuery();

C#:
ADO.NET
Entity Framework
등을 이용해 SQL과 connection을 만들고, query를 이용해 통신한다.

.NET Framework에서의 구조에서는 데이터 베이스가
1) 파일로 존재할 경우 - App_Data의 폴더안에 데이터베이스의 이름으로 존재할 경우가 있고
2) DBMS의 데이터베이스로 존재할 경우 - Web.config 파일 안에 이름이 부여된 “connection string”이라는 것으로 존재할 경우가 있다. 이 Connection String은 자바에서의 Connection에 쓰여졌던 문자열과 비슷하다. 이렇게 데이터베이스의 세팅이 이미 끝나있는 상태이므로, ASP에서 데이터베이스를 이용하는 것은 매우 쉽다.

@{
// teamup이라는 파일 혹은 web.config의 teamup에 부여된 connection string을 통해 데이터베이스에 연결
var db = Database.Open("teamup");
var query = "SELECT * FROM TABLE";

foreach(var row in db.Query(query))
{
<tr>
<td>@row.Id</td>
<td>@row.Name</td>
</tr>
}
}

...

ASP.NET에서 Database Object는 다음과 같은 References들이 존재한다.

- Database.Execute(SQLUpdate)
- Database.GetLastIndex()
- Database.Open(filename)
- Database.Open(ConnectionStringName)
- Database.OpenConnectionString(connectionString)
- Database.Query(SQLStatement)
- Database.QuerySingle(SQLstmt)
- Database.QueryValue(SQLstmt)