[Из песочницы] Мост из мира .NET в мир JavaScript

Хочу поделиться интересной находкой — Bridge.net. Если в двух словах, это фреймворк, позволяющий транслировать C# код в JavaScript. Идея, которая движет командой разработчиков очень проста и понятна — транслировать логику настолько идентично, насколько это возможно. Что радует, если вспомнить все различия и специфику этих языков.

dff15b703e00491eb2c3be4d31dbb575.png
Пожалуй, каждый сможет найти свое персональное применение, но я хотел бы отметить те моменты, которые привлекли лично меня:

  • Возможность применения для мобильной разработки. JavaScript работает на всех платформах
  • Применимость для Web. Особенно, если нужно переписать устаревший проект, например, в виде SPA приложения
  • Возможность переиспользовать C# код одновременно на стороне сервера и клиента
  • Трансляция, выполняемая во время сборки проекта
  • Проект находится в стадии активной разработки, есть адекватная поддержка со стороны разработчиков
  • Bridge.net — это OpenSource проект с лицензией на использование в коммерческих целях (лицензия Apache 2.0)


В качестве демонстрации использования Bridge, я хочу поделиться решением задачи валидации полей в Web приложении. Надеюсь, пример будет наглядным, ведь подобная задача может встречаться достаточно часто. Для простоты буду использовать ASP.NET Web Forms.

Итак, у нас есть поле, в которое пользователь должен ввести регистрационный номер автомобиля и нажать на кнопку. В нашем случае кнопка будет проверять корректность ввода (в реальной жизни мы могли бы возвращать, например, зарегистрированные штрафы).

Серверная логика проверки ввода
protected void submitButton_OnClick(object sender, EventArgs e)
{
    var isCorrect = IsCorrectPlateNumber(plateTextBox.Text);
    plateTextBox.BackColor = isCorrect ? Color.LightGreen : Color.Coral;
}
private static bool IsCorrectPlateNumber(string plateNumber)
{
    var success = false;
    if (!string.IsNullOrWhiteSpace(plateNumber))
    {
        plateNumber = plateNumber.Trim();
        if (plateNumber.Length >= 8 || plateNumber.Length <= 9)
        {
            var rgx = new Regex(@"^[АВЕКМНОРСТУХавекмнорстух]\d{3}[АВЕКМНОРСТУХавекмнорстух]{2}\d{2,3}$");
            success = rgx.IsMatch(plateNumber);
        }
    }
    return success;
}


d2dad2fc1a194ed79c3ddaaf8a3d6e80.png

Хорошо, теперь мы хотим снизить нагрузку на сервер и выполнять валидацию поля на стороне клиента. Вариантов тут несколько:

1) Заново написать клиентскую валидацию, которая будет проверять самые простые сценарии, так сказать, «защита от дурака». Основные проверки будут по-прежнему выполняться на стороне сервера.

Простая клиентская валидация
Рег. номер автомобиля (формат X 000 XX 000):
function validatePlate() {
    var value = document.getElementById('<%=plateTextBox.ClientID%>').value;
    if (value && value.length) {
        return true;
    }
    alert("Введите рег. номер автомобиля!");
    return false;
}


2) Портировать серверную валидацию, насколько это возможно, тем самым повторив код. Плюсы очевидны — минимальное расхождение результатов валидации на сервере и на клиенте. Минусы тоже есть — повторяя серверную логику, хотелось бы также поддерживать ее в актульном состоянии, что может добавить головной боли. Переписывать вручную код не буду, он вполне понятен. Давайте лучше посмотрим, как нам помог бы Bridge. Для этого воспользуемся online редактором. Транслированный код будет выглядеть следующим образом:

Полная клиентская валидация
(function (globals) {
    "use strict";

    Bridge.define('Demo.ServerLogic', {
        statics: {
            isCorrectPlateNumber: function (plateNumber) {
                var success = false;
                if (!Bridge.String.isNullOrWhiteSpace(plateNumber)) {
                    plateNumber = plateNumber.trim();
                    if (plateNumber.length >= 8 || plateNumber.length <= 9) {
                        var rgx = new Bridge.Text.RegularExpressions.Regex("constructor", "^[АВЕКМНОРСТУХавекмнорстух]\\d{3}[АВЕКМНОРСТУХавекмнорстух]{2}\\d{2,3}$");
                        success = rgx.isMatch(plateNumber);
                    }
                }
                return success;
            }
        }
    });

    Bridge.init();
})(this);

Нам остается подключить файл Bridge.js (для простоты я взял файл скрипта из онлайн редактора), а также немного модифицировать нашу первоначальную функцию валидации:
function validatePlate() {
    var value = document.getElementById('<%=plateTextBox.ClientID%>').value;
    if (Demo.ServerLogic.isCorrectPlateNumber(value)) {
        return true;
    }
    alert("Неверный рег. номер автомобиля!");
    return false;
}


3) Переиспользовать логику. Если мы хотим поддерживать ее в актуальном состоянии, то можно настроить, чтобы трансляция валидации из C# в JavaScript выполнялась при каждой сборке проекта. Таким образом, логика по-настоящему становится переиспользуемой, программисты не тратят свое время попусту, приложение становится стабильнее, а пользователи еще счастливее! Для этого нужно выполнить несколько шагов:

Встраивание Bridge в проект
1. Создадим в имеющемся солюшене проект WebApplication1.Bridge

2. Установим в него Nuget пакет. Устанавливайте этот пакет в отдельный проект, т.к. при установке удаляются конфликтующие References.

a0f5850ce77a4a748efcbc5620ad31c7.png

3. В проекте WebApplication1 вынесем логику в отдельный файл/класс. Соответственно, теперь этот класс будет использован в обработчике события нажатия на кнопку (изменения понятны, код не привожу).

ServerLogic.cs
using System.Text.RegularExpressions;

namespace WebApplication1
{
    public class ServerLogic
    {
        public static bool IsCorrectPlateNumber(string plateNumber)
        {
            var success = false;
            if (!string.IsNullOrWhiteSpace(plateNumber))
            {
                plateNumber = plateNumber.Trim();
                if (plateNumber.Length >= 8 || plateNumber.Length <= 9)
                {
                    var rgx = new Regex(@"^[АВЕКМНОРСТУХавекмнорстух]\d{3}[АВЕКМНОРСТУХавекмнорстух]{2}\d{2,3}$");
                    success = rgx.IsMatch(plateNumber);
                }
            }
            return success;
        }
    }
}


4. Добавим созданный файл в проект WebApplication1.Bridge как ссылку

5. Изменим output директорию для проекта WebApplication1.Bridge. Для этого настроим в файле bridge.json:

"output": "../WebApplication1/Scripts/Bridge"

6. После сборки в Solution Explorer нажмем Show All Files и сможем увидеть сгенерированный скрипт webApplication1.js

7. Добавим нужные ссылки и обновим скрипты на странице Demo.aspx:

Demo.aspx скрипты





8. Всё. Можно собирать проект и запускать. Теперь любые изменения в логику валидации будут автоматически работать как для серверной проверки, так и для клиентской.


Так, на простом примере, мы увидели как можно легко переиспользовать C# код, даже когда это нужно сделать с помощью JavaScript. И что может представлять бОльшую ценность — как такой подход встраивается в процесс разработки и сборки Web приложения. Однако, это не единственное преимущество Bridge.net. Я вижу его неоспоримым помощником в кроссплатформенной мобильной разработке, особенно для тех, кто не представляет свою жизнь без .NET’а, но об этом в следующий раз!

© Habrahabr.ru