Аналізатор виразів в ASP .NET

Доброго дня.
Так як навчання вже закінчилось, з’явилась можливість частіше писати на цьому блозі :). В цій статті ви можете прочитати про те, як створювати власного білдера виразів, який представляє собою одну з можливостей зв’язування даних в ASP .NET.

Приклади зв’язування

Для початку, я продемонструю кілька типів зв’язування, які вже доступні в ASP .NET.

Отже створіть проект типу ASP .NET Web Application, після чого відкрийте сторінку Default.aspx, де ви побачите її розмітку:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="Sample._Default"%>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
  <h2>
     Welcome to ASP.NET!
  </h2>
  <p>
    To learn more about ASP.NET visit <a href="http://www.asp.net" title="ASP.NET Website">www.asp.net</a>.
  </p>
  <p>
You can also find <a href=<a href="http://go.microsoft.com/fwlink/?LinkID=152368&amp;clcid=0x409">http://go.microsoft.com/fwlink/?LinkID=152368&amp;clcid=0x409</a> title="MSDN ASP.NET Docs">documentation on ASP.NET at MSDN</a>.
  </p>
</asp:Content>

В кінці добавте звичайний текст:

<label>The time is now: </label>

Застосуємо звичайний тип зв’язування, який має синтаксис <%# %>:

<label>The time is now: <%# DateTime.Now %> </label>

В C# коді цієї сторінки, в обробнику події Page_Load добавте виклик методу Page.DataBind():

protected void Page_Load(object sender, EventArgs e)
{
    Page.DataBind();
}

Тепер, після запуску ви побачите сторінку, на якій пише текст та точна дата її генерування:

Мал. 1.1

Тепер розглянемо інший тип зв’язування, який має синтаксис <%$ %>.

Цей тип зв’язування відрізняється від попереднього тим, що він не потребує виклику Page.DataBind(), і працює тільки тоді, коли він вставляється в властивості якогось елемента правління.

Також, ви не можете просто доступатись до будь-яких статичних або екземплярних типів, тому потрібно вказати тип виразу, який ви застосовуєте:

<br /><asp:Label ID="lblImagePath" runat="server" Text="<%$ AppSettings:ImagePath %>" />

AppSettings являє собою один з доступних типів виразів, який дозволяє доступатись до даних, які знаходяться в конфігураційному файлі. ImagePath – це ключ, по якому дані мають бути знайдені.

Відкрийте web.config файл та в розділ <configuration> добавте наступні параметри:

<configuration>
 <appSettings>
 <add key="ImagePath" value="D:\TestImage.jpg"/>
</appSettings>

Натисніть F5 та впевніться, що результат відобразився на сторінці:

Мал. 1.2

Насправді вираз <%$ AppSettings %> реалізований класом AppSettingsExpressionBuilder, який входить стандартний набір компонентів ASP .NET.

Отже, коли вам відомо, для чого, і як використовувати зв’язування в розмітці *.aspx файлу, можна перейти до створення власного аналізатора виразів.

Створення власного аналізатора виразів

Тепер можна створити власного аналізатора виразів. Цей аналізатор буде повертати суму заданих чисел, і буде мати ось такий синтаксис: <%$ Sum 5,5,5 %>

Добавте новий *.cs файл та розмістіть в ньому новий клас, який буде називатись SumExpressionBuilder:

public class SumExpressionBuilder
{
}

Добавте наступні директиви:

using System.Web.Compilation;
using System.CodeDom;

Після чого унаслідуйте створений клас від класу ExpressionBuilder :

public class SumExpressionBuilder : ExpressionBuilder
{
}

Добавте статичний метод, за допомогою якого можна буде отримувати суму:

public static Int32 GetSum(Int32[] numbers)
{
    Int32 result = 0;
    foreach (Int32 number in numbers)
    {
        result += number;
    }
    return result;
}

Тепер ми підійшли до самої складної частини цього завдання. Для простішого розуміння роботи, яку нам потрібно виконати, уявляйте ніби ви вручну перетворюєте команди мови C# на об’єктну модель.

Для реалізації аналізатора виразів, потрібно переписати метод GetCodeExpression, який знаходиться в базовому класі ExpressionBuilder:


public override CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
   ......
}

Текст (вираз), який нам потрібно аналізувати, знаходиться в властивості Expression об’єкту BoundPropertyEntry, який передається першим параметром:


public override CodeExpression GetCodeExpression(System.Web.UI.BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
    if(!entry.Expression.Contains(','))
       throw new ArgumentException("Please, specify at least two numbers");
    ......
}

В цьому коді, я просто перевіряю чи переданий вираз є синтаксично правильним та викидаю помилку якщо він не проходить перевірку.

В іншому випадку, я розбиваю переданий вираз на окремі стрічки, за допомогою методу String.Split(), після чого намагаюсь перетворити їх в числа та добавити в масив об’єктів CodeExpression, який являє собою вхідний параметр для методу GetSum:

else
{
    String[] strNumbers =  entry.Expression.Split(',');
    CodeExpression[] arrayParams = new CodeExpression[strNumbers.Length];
    for (Int32 i = 0; i < strNumbers.Length; i++)
    {
       Int32 parsedValue = 0;
       Int32.TryParse(strNumbers[i], out parsedValue);
       arrayParams[i] = new CodePrimitiveExpression(parsedValue);
    }
    .......
}

Тепер все, що нам потрібно зробити – це створити посилання на об’єкт SumExpressionBuilder, створити вхідні параметри для методу GetSum, після чого його викликати:

else
{
    CodeTypeReferenceExpression typeRef = new CodeTypeReferenceExpression(typeof(SumExpressionBuilder));
    CodeExpression[] methodParams = new CodeExpression[1];
    methodParams[0] = new CodeArrayCreateExpression(new CodeTypeReference(typeof(Int32[])), arrayParams);
    return new CodeMethodInvokeExpression(typeRef, "GetSum", methodParams);
}

З цього коду видно, що посилання на об’єкт представляється екземпляром класу CodeTypeReferenceExpression, в конструктор якого я передав тип SumExpressionBuilder.

Після цього, я створив масив для об’єктів CodeExpression та всіх об’єктів, які його унаслідують, в який добавив один вхідний параметр – масив об’єктів CodeExpression, обгорнутий класом CodeArrayCreateExpression. Цей масив містить числа взяті з виразу:

methodParams[0] = new CodeArrayCreateExpression(new CodeTypeReference(typeof(Int32[])), arrayParams);

І в кінці методу, я повернув результат, представивши виклик методу GetSum екземпляром класу CodeMethodInvokeExpression, в який передав посилання на об’єкт з методом, назву методу та його вхідні параметри:

return new CodeMethodInvokeExpression(typeRef, "GetSum", methodParams);

Наш аналізатор готовий! Тепер все, що потрібно зробити – це підключити його в конфігураційному файлі:

Відкрийте файл web.config.

В секцію compilation добавте набір аналізаторів, вкажіть префікс та назву аналізатора:

<compilation debug="true" targetFramework="4.0">
 <expressionBuilders>
 <add expressionPrefix="Sum" type="SampleProject.SumExpressionBuilder"/>
 </expressionBuilders>
 </compilation>

В файлі Default.aspx добавте наступну мітку:

<br /><asp:Label ID="lblSumTest" runat="server" Text="<%$ Sum: 5,5,5 %>" />

Після запуску сторінки, ви побачите, що відображається сума переданих елементів:

Мал. 2.1

Звичайно аналізатор виразів, який я створив для демонстрації не є ідеальним та дуже корисним. Але почитавши цю статтю, ви будете мати уяву про їх створення та можливість створити власний більш складний аналізатор.

Всього найкращого! 🙂

Скачати вихідний код програми.

Advertisements

, , ,

  1. Leave a comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: