ASP.Net Expression Builders. Редактор свого типу виразів. Частина 2, Різне, Програмування, статті

Продовжимо гратися з “будівника виразів” в ASP.Net.

Нагадаю, що існує три вирази поставляються за замовчуванням разом з ASP.Net:

<system.web>

    <compilation>

        <expressionBuilders>

            <add expressionPrefix=”Resources”

                 type=”System.Web.Compilation.ResourceExpressionBuilder”/>

            <add expressionPrefix=”ConnectionStrings”

                 type=”System.Web.Compilation.ConnectionStringsExpressionBuilder”/>

            <add expressionPrefix=”AppSettings”

                 type=”System.Web.Compilation.AppSettingsExpressionBuilder”/>

        </expressionBuilders>

    </compilation>

</system.web>

Для кожного з них існує деякий редактор, який дозволяє встановлювати значення властивостей в Design-Time.

Розглянемо нашу невелику сторінку:

default.aspx

<%@ Page Language=”C#” AutoEventWireup=”true”

    CodeBehind=”Default.aspx.cs” %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN”

    “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>

<html xmlns=”http://www.w3.org/1999/xhtml”>

<head runat=”server”>

    <title>ASP.Net Expression Builder Test</title>

</head>

<body>

    <h1>ASP.Net Expression Builder Test</h1>

    <table class=borderall cellpadding=”3″ cellspacing=”0″>

        <col style=”color: DarkGreen” align=”left” />

        <tr>

            <th>$AppSettings</th>

            <td>

                <asp:Label ID=”appSettingsLabel” runat=”server”

                           Text=”<%$ AppSettings: MyAppSetting %>” />

            </td>

        </tr>

        <tr>

            <th>$ConnectionStrings</th>

            <td>

                <asp:Label ID=”connectionStringsLabel” runat=”server”

                           Text=”<%$ ConnectionStrings: MyConnectionString %>” />

            </td>

        </tr>

        <tr>

            <th>$Resources</th>

            <td>

                <asp:Label ID=”resourcesLabel” runat=”server”

                           Text=”<%$ Resources: MyResources, MyResourceKey %>” />

            </td>

        </tr>

    </table>

</body>

</html>


Перемикаємося в перегляд дизайну:


Скріншот: default.aspx в режимі Дизайн


Вибираємо довільний серверний контрол (на скріншоті у мене обраний перший appSettingsLabel) і дивимося у вікно Properties.


Скріншот: Вікно властивостей в Design-Time


Речі, на які варто звернути увагу я виділив. Перше, це маленький квадратик біля властивості Text – Якщо до нього підвести мишу, то з’явитися підказка “Property is expression bound.”. Друге, це секція Data і її елемент (Expressions). Саме в ньому і прихований редактор, який дозволяє присвоювати різним властивостями елемента значення параметрам вираження.


Скріншот: Редактор для зв 


“Bindable properties” показує список доступних властивостей елемента керування до яких можна “прібіндіть” вираз.


У випадаючому списку “Expression type” можна вибрати будь-який ExpressionBuilder зареєстрований в web.config.


Тепер найцікавіше. У вікні “Expression properties” можна побачити стандартний грід з набором властивостей (так, на скріншоті видно тільки одну властивість, але якщо вибрати Resources серед типів, то там буде вже два). Цей грід є “редактором” для вибраного типу висловлювання. І для свого типу виразу можна реалізувати свій редактор.


Робиться це за допомогою атрибута ExpressionEditorAttribute, Спадкоємця ExpressionEditor (Який знаходиться в System.Design.dll) і спадкоємця ExpressionEditorSheet.


Реалізація редактора властивостей для вираження


У якості вираження я буду використовувати простеньке вираз HashItExpression. Синтаксис вигадаємо наступним:


<% $ HashIt: MD5 ("рядок, хеш якій я хочу отримати"): Base64%>


Параметрами мого висловлювання будуть служити:



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


HashItEvaluator.cs

using System;

using System.Linq;

using System.Security.Cryptography;

using System.Text;

using System.Text.RegularExpressions;

 

namespace Home.Andir.Examples

{

    public enum HashAlg

    {

        MD5,

        SHA1,

        SHA256,

        SHA512

    }

 

    public enum EncodeType

    {

        Base64,

        Hex

    }

 

    public static class HashItEvaluator

    {

        public class HashItParseResults

        {

            public HashAlg HashAlg { get; set; }

            public string Source { get; set; }

            public EncodeType EncodeType { get; set; }

        }

 

        public static string Eval(string expression)

        {

            var parseResults = ParseExpression(expression);

            if (parseResults != null)

            {

                return Eval(parseResults);

            }

 

            return “Invalid expression”;

        }

 

        private static string Eval(HashItParseResults parseResults)

        {

            HashAlgorithm hash = CreateAlgorithm(parseResults.HashAlg);

 

            var result = hash.ComputeHash(

                Encoding.Default.GetBytes(parseResults.Source));

 

            if (parseResults.EncodeType == EncodeType.Hex)

            {

                return String.Concat(

                    result.Select(x => String.Format(“{0:x2}”, x)).ToArray()

                    );

            }

 

            return Convert.ToBase64String(result);

        }

 

        private static HashAlgorithm CreateAlgorithm(HashAlg alg)

        {

            switch (alg)

            {

                case HashAlg.MD5: return MD5.Create();

                case HashAlg.SHA1: return new SHA1Managed();

                case HashAlg.SHA256: return new SHA256Managed();

                case HashAlg.SHA512: return new SHA512Managed();

            }

 

            throw new ArgumentOutOfRangeException(“alg”);

        }

 

        public static HashItParseResults ParseExpression(string expression)

        {

            // expression == MD5(source) [: Base64]

            Regex expRe = new Regex(

                @”(?<alg>MD5/SHA1/SHA256/SHA512)(“(?<source>.+)”)(s*:s*(?<enc>(Base64/Hex)))?”,

                RegexOptions.IgnoreCase

                );

 

            var match = expRe.Match(expression);

 

            if (match != null)

            {

                string alg = match.Groups[“alg”].Value;

                string source = match.Groups[“source”].Value;

                string enc = match.Groups[“enc”].Value;

 

                return new HashItParseResults()

                {

                    HashAlg = (HashAlg)Enum.Parse(typeof(HashAlg), alg, true),

                    Source = source,

                    EncodeType = enc.ToUpper() == “BASE64” ? EncodeType.Base64 : EncodeType.Hex

                };

            }

 

            return null;

        }

    }

}


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


Метод HashItEvaluator. Eval використовуючи результати парсинга, обчислює вираз (тобто хешірует строчку і отриманий результат представляє в текстовому вигляді).


Ну а тепер можна і реалізувати сам ExpressionBuilder і його редактор. Слідкуйте за руками.


HashItExpressionBuilder.cs

using System.CodeDom;

using System.Web.Compilation;

using System.Web.UI;

 

namespace Home.Andir.Examples

{

    [ExpressionEditor(typeof(HashItExpressionEditor))]

    public class HashItExpressionBuilder : ExpressionBuilder

    {

        public override CodeExpression GetCodeExpression(

            BoundPropertyEntry entry,

            object parsedData,

            ExpressionBuilderContext context)

        {

            return new CodePrimitiveExpression(

                HashItEvaluator.Eval(entry.Expression));

        }

    }

}


Звертаємо увагу на атрибут встановлений у класу.


HashItExpressionEditor.cs

using System;

using System.Web.UI.Design;

 

namespace Home.Andir.Examples

{

    public class HashItExpressionEditor : ExpressionEditor

    {

        public override object EvaluateExpression(

            string expression,

            object parseTimeData,

            Type propertyType,

            IServiceProvider serviceProvider)

        {

            return HashItEvaluator.Eval(expression);

        }

 

        public override ExpressionEditorSheet GetExpressionEditorSheet(

            string expression,

            IServiceProvider serviceProvider)

        {

            return new HashItExpressionEditorSheet(expression, serviceProvider);

        }

    }

}


У редактора треба реалізувати дві функції: EvaluateExpression – обчислює вираз і GetExpressionEditorSheet – повертає джерело для редактора властивостей (той самий грід!).


HashItExpressionEditorSheet.cs

using System;

using System.ComponentModel;

using System.Web.UI.Design;

 

namespace Home.Andir.Examples

{

    public class HashItExpressionEditorSheet : ExpressionEditorSheet

    {

        public HashItExpressionEditorSheet(

            string expression,

            IServiceProvider serviceProvider

            ) : base(serviceProvider)

        {

            var parseResults = HashItEvaluator.ParseExpression(expression);

            if (parseResults != null)

            {

                HashAlg = parseResults.HashAlg;

                EncodeType = parseResults.EncodeType;

                Source = parseResults.Source;

            }

        }

 

        [DefaultValue(HashAlg.MD5), DisplayName(“Hash algorithm”)]

        public HashAlg HashAlg { get; set; }

        [DefaultValue(EncodeType.Hex), DisplayName(“Result encoding”)]

        public EncodeType EncodeType { get; set; }

        [DefaultValue(“”), DisplayName(“Some text”)]

        public string Source { get; set; }

 

        public override bool IsValid

        {

            get { return true; }

        }

 

        public override string GetExpression()

        {

            var result = String.Format(“{0}(“{1}”)”, HashAlg.ToString(), Source);

 

            if (EncodeType == EncodeType.Base64)

                result += “: Base64”;

 

            return result;

        }

    }

}


Отже, тут три властивості, які і визначають параметри мого висловлювання.


Тестуємо.


Примітка: Щоб студія довантажити новий зареєстрований редактор для вираження, потрібно скомпілювати проект і студію перезапустити.


Реєструємо новий вираз в web.config

<?xml version=”1.0″?>

<configuration>

    <system.web>

        <compilation debug=”true”>

            <expressionBuilders>

                <add expressionPrefix=”HashIt”

                     type=”Home.Andir.Examples.HashItExpressionBuilder”

                     />

            </expressionBuilders>

        </compilation>

    </system.web>

</configuration>

Створюємо тестову сторінку:

HashItExpression.aspx

<%@ Page Language=”C#” %>

<html xmlns=”http://www.w3.org/1999/xhtml”>

<head runat=”server”>

    <title>ASP.Net HashIt Expression Builder Test</title>

</head>

<body>

    <h1>ASP.Net HashIt Expression Builder Test</h1>

    <table class=borderall cellpadding=”3″ cellspacing=”0″>

        <col style=”color: DarkGreen” align=”left” />

        <tr>

            <th>

                <span>$HashItExpression</span>

            </th>

            <td>

                <asp:Label ID=”hashItLabel” runat=”server”

Text = “<% $ HashIt: MD5 (" Рядок "): Base64%>” />

            </td>

        </tr>

    </table>

</body>

</html>


І відкриваємо її в режимі Design:


Скріншот: Тестова сторінка з виразом в Design-Time


Вибираємо елемент управління hashItLabel і відкриваємо діалог для Біндінга виразів:



Скріншот: Діалог Біндінга виразів до властивостей елемента керуванняЯк видно на скріншоті, з’явився тип виразу “HashIt” і в редакторі властивостей з’явилися всі властивості цього виразу. Відмінно!

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*