Programming/.NET

ASP.NET 에서 Expressions 는 지정된 데이터 값을 반환하기 위해 런타임에서 파싱되는 특정 구문에 해당합니다. 이를 테면 SqlDataSource 컨트롤 사용시 ConnectionString 속성에 DB연결정보 제공을 위해서 다음과 같은 형태의 값을 지정하곤 했는데 이것이 바로 Expressions 에 해당합니다.

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:new_connection %>" SelectCommand="SELECT Top 100 * FROM [Person].[PersonPhone]"></asp:SqlDataSource>

ASP.NET 은 aspx 페이지를 파싱할때 SqlDataSource 컨트롤에서 <%$ %> 내용이 포함된 구문을 발견하면 Web.config 로 부터 데이터베이스 연결정보를 가져옵니다. 이때 Expressions 에 사용된 ConnectionStrings 라는 접두사는 ConnectionStringsExpressionBuilder 클래스를 사용해 해당 Expressions 을 파싱할것을 알려주게 됩니다.

ConnectionStringsExpressionBuilder 클래스는 Expression 을 파싱하는데 사용되는 Expression Builders 중 하나로서 ASP.NET 은 이러한 Expression Builders 를 다수 포함하고 있습니다. 그 중에서 Web.config 의 DB 연결정보값을 가져오기 위한 것중 하나가 바로 ConnectionStringsExpressionBuilder 에 해당합니다.

또한 Expressions 에서 AppSettings 접두사를 사용하면 이것은 Web.config 파일의 appSettings 섹션 에서 지정한 값을 가져와야 한다는 것을 의미하는 것으로 AppSettingsExpressionBuilder 클래스를 사용해 파싱을 시도합니다.

<appSettings>
 <add key="test" value="테스트" />
</appSettings>

▶Web.config 의 appSettings 설정

<asp:Label ID="Label1" runat="server" Text="<%$ AppSettings:test %>"></asp:Label>

▶ <코드 1-1>

<코드 1-1>은 Web.config 의 appSettings 에서 지정한 Key 에 해당하는 값을 가져옵니다.

Resources 접두사는 웹프로젝트의 로컬리소스를 가져오며 ResourceExpressionBuilder 클래스를 사용해 파싱됩니다.

<asp:Label ID="Label1" runat="server"Text="<%$ Resource: LocalResources.test %>"></asp:Label>

뿐만 아니라 ASP.NET 은 위에서 처럼 정해진 Expressions 이외에 System.Web.Compilation.ExpressionB
uilder 클래스를 기반으로 개발자 자신만의 Expression 을 직접 구현하여 사용할 수도 있습니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression("Hello"));
    }
}

▶ <코드 1-2>

<코드 1-2>는 ExpressionBuilder 클래스에서 파생된 myExpression 클래스를 정의한 것으로서 새로운 ExpressionBuilder 클래스를 생성한 것입니다. 클래스에서 지정된 ExpressionPrefix 와 ExpressionEditor 속성은 .NET 으로 하여금 해당 클래스가 Expression 에 사용되는 클래스임을 알려주기 위한 것으로 실제 Expression 이 파싱될때 그에 맞는 적절한 ExpressionBuilder 클래스를 찾아낼 수 있도록 합니다.

myExpression 클래스안에서 오버라이드(재정의)된 GetCodeExpression 메소드는 네임스페이스 상으로 CodeDom 하위에 속합니다. CodeDom 은 ASP.NET 이 런타임시에 코드를 동적으로 생성하고 생성된 코드를 실행한 결과를 반환하는데 사용되는 기반클래스입니다. Expression 에서 CodeDom 이 언급되는 이유는 직접 구현한 ExpressionBuilder 클래스 자체가 코드가 되어 동작하는 것이 아니라 런타임에 .NET 으로 하여금 어떠한 코드를 생성하고 실행해야 하는지를 알려주는 이정표같은 역활을 하기 때문입니다. GetCodeExpression 안에서 작성된 CodeCastExpression 메소드는 형변환을 수행하기 위한 코드를 생성해야 함을 나타내며 실제 런타임에서 C#의 경우 ((Int64)(1000)) 과 같은 코드를 생성해 내고 동작을 수행하게 되는 것입니다.

GetCodeExpression 메소드는 대략 3가지 정도의 파라메터를 가지고 있는데 이 중 두개의 파라메터에 주목해 주세요. 첫번째 파라메터인 entry 는 Expression 이 사용될때 어느 속성에 연결되어 있는지를 알아내기 위한 것입니다. 예를 들면 <코드 1-1>에서 Label 의 Text 속성에 Expression 이 사용되었는데 이때 entry 는 Label 컨트롤및 여기에 바인딩된 Text 속성에 관한 정보를 가지게 됩니다.

두번째 파라메터인 parseData 는 ParseExpression 메소드에 의해 파싱되는 데이터를 포함하고 있습니다. 사실 <코드 1-2>와 같이 ExpressionBuilder 를 생성하고 다음과 같이 Expression 을 바인딩했다고 했을때

<asp:Label ID="Label1" runat="server" Text="<%$ mEx:hi %>"></asp:Label>

이때 mEx 접두사 다음에 사용된 hi라는 데이터값을 읽고 저장하는 파라메터가 바로 parseData 에 해당합니다.

다만 실제로 동작결과를 살펴보면 parseData 에는 아무런 값도 없고(null) 그저 Hello 이라는 값만이 나오게 됩니다. parseData 파라메터를 제대로 활용하려면 우선 값을 파싱하기 위한 ParseExpression 메소드를 오버라이드해야 하며 parseData 에 따른 값을 반환시키려면 <코드 1-2>에서 Hello 이라는 값 대신 parseData 로 바꿔줘야 합니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression(parsedData));
    }

    public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
    {
        return expression;
    }
}

만약 aspx 페이지의 Page 지시에서 CompilationMode 속성이 Naver 등으로 설정되어 페이지가 no-compile 모드로 동작하는 경우에는 위 방법 대신에 SupportsEvaluate 속성과 EvaluateExpression 메소드를 오버라이드해서 Expression 의 값을 가져와야 합니다.

[ExpressionPrefix("mEx")][ExpressionEditor("myExpressionEditor")]
public class myExpression : System.Web.Compilation.ExpressionBuilder
{
    public override System.CodeDom.CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return new CodeCastExpression("String", new CodePrimitiveExpression(parsedData));
    }

    public override object ParseExpression(string expression, Type propertyType, ExpressionBuilderContext context)
    {
        return expression;
    }

    public override bool SupportsEvaluate
    {
        get { return true; }
    }

    public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
    {
        return parsedData;
    }
}

SupportsEvaluate 속성을 통해 Evaluate 사용을 허가하고 EvaluateExpression 메소드를 재정의하면 이 메소드가 페이지가 no-compile 모드일때 GetCodeExpression 메소드대신 Expression 값을 가져오는데 사용됩니다.

마지막으로 ExpressionBuilder 를 생성하고 나면 web.config 파일의 expressionBuilders 노드에 해당 클래스의 존재와 접두사를 추가함으로서 ASP.NET 이 런타임에 Builder 클래스를 찾을 수 있도록 해야 합니다.

<system.web>
  <compilation debug="true" targetFramework="4.0">
    <expressionBuilders>
      <add expressionPrefix="mEx" type="Webtest.App_Code.myExpression" />
    </expressionBuilders>
  </compilation>
</system.web>

0 0