المتابعون للمدونة

الخميس، 21 مارس 2019

VB.NET Razor

مفاجأة مدهشة: أنشأت تطبيق ASP.NET MVC Core بلغة فيجوال بيزيك وعمل بشكل صحيح!
 

تعرفون بالطبع أنني سقطت في عشق لغة فيجوال بيزيك من أول نظرة عام 1998 وما زلت مغرما بها حتى اليوم، وأرى أنها أرقى ما وصلت إليه لغات البرمجة من حيث صياغتها القريبة من اللغة الإنجليزية العادية، والتسهيلات الذكية الكثيرة التي تمنحها للمبرمج فتجعله يكتب الكود ويحصل على النتائج الصحيحة بسرعة.. كل هذا جعلني مستاءا للغاية من إهمال ميكروسوفت لفيجوال بيزيك وتركها حبيس الويندوز وعدم استخدامها في Xamarin و ASP.NET Core.. وكلما سألهم سائل عن ذلك، تكون الإجابة إنك تستطيع استخدام فيجوال بيزيك بالفعل في هذه المنتجات، لكن في مكتبات الكود وليس تصميم الواجهات، وإن دعم ملفات vbhtml في تقنية Razor أمر يحتاج وقتا وجهدا وتكلفة عالية، وهم مشغولون في أشياء كثيرة أولى!
وقد ظللت أنتظر عامين لعل هذه الساسة تتغير في أي لحظة، لكن بلا جدوى!.. لهذا بدأت أميل إلى الاقتناع إلى أن ميكروسوفت ستهمل فيجوال بيزيك بالتدريج وتسقطها من حساباتها إلى أن تموت موتا بطيئا مؤلما!
وقد قررت ألا أجعل هذا الأمر سهلا بالنسبة لهم، لهذا عرضت عليهم الأسبوع الماضي أن أتطوع لإنشاء VB.NET Razor حتى لو استغرق هذا ستة أشهر، وأن يعوني بعض التوجيهات لإنجاز المهام المطلوبة، لكن ردهم جاء كما توقعت برفض الفكرة، بحجة أن دعم وتطوير VB Razor بعد أن أكتبه لهم مكلف في حد ذاته وليس لديهم استعداد لهذا!!
في هذه اللحظة قررت أن أمضي قدما بمفردي، ولأن الموضوع معقد فعلا، قررت تبسيطه بأن أفصل كود فيجوال بيزيك في ملف خلفي code-behind file مثلما يحدث في WPF، وأن يقتصر ملف vbhtml على كود HTML مع وجود إشارات موضعية لخصائص معرفة في ملف الكود الخلفي يتم التعويض عنها بقيمها مباشرة.
وبتأمل هذه الفكرة، تذكرت فجأة أن فيجوال بيزيك تدعم كتابة كود XML مباشرة في الكود مثل:
Dim X = <p>sample</p>
مع توفير التنسيق والتلوين وتدقيق الصياغة لهذه التعبيرات!.. والأجمل من هذا أنني أستطيع التعويض بقيم المتغيرات داخل هذه الصيغ، بوضعها داهل القوسين المستخدمين في ASP على الصيغة <%=  %>.. مثل:
Dim n = "1"
Dim X = <p>Sample <%= n %></p>
Console.WriteLine(X) ' Sample 1
وهنا سألت نفسي: أليس هذا هو بالضبط ما يفترض أن تفعله ملفات vbhtml التي تحتوي على كود HTML مع بعض كود VB للتعويض عن المتغيرات في وقت التنفيذ؟
وهنا صحت في دهشة: يا إلهي!.. فيجوال بيزيك تحتوي بالفعل على محرك Razor مبني جاهزا بداخلها، دون أن يتنبه له أحد!
ولاختبار هذه الفكرة، قررت أن أحضر ملف chtml وأحاول أن أكتب مثله بكود فيجوال بيزيك مباشرة.. وكان هذا هو كود هذا الملف:
@model IEnumerable<MvcBookStore.Models.Book>
@{
    ViewBag.Title = "BookStore";
}
<h3>Browse Books</h3>
<p>Select from @model.Count() Books:</p>
<ul>
    @foreach (var book in model)
    {
        <li>@book.Name</li>
    }
</ul>
بالنسبة للجزء:
model IEnumerable<MvcBookStore.Models.Book>
فأمره سهل، حيث يمكن تمرير الكائن model كمعامل لفئة فيجوال بيزيك التي ستقوم بإنتاج الصفحة، لاستخدام البيانات التي فيه ضمن كود HTML.
أما الجزء:
ViewBag.Title = "BookStore"
فهو سطر كود مباشر يمكن كتابته في حدث إنشاء الفئة كما هو، أو تحويله إلى تاج العنوان في HTML:
BookStore<title>BookStore</title>
أما بالنسبة للجزء:
<h3>Browse Books</h3>
<p>Select from @model.Count() Books:</p>
فيمكن تمثيله في تعبير XML في فيجوال بيزيك بسهولة:
Dim x =
  <h3>Browse Books</h3>
  <p>Select from <%= model.Count() %> Books:</p>
إلى هنا وكل شيء جميل ومباشر.. لكن كيف سأتعامل مع الجزء:
<ul>
    @foreach (var book in model)
    {
        <li>@book.Name</li>
    }
</ul>
هذا الجزء يحتوي على حلقة تكرار تنتج أجزاء من كود HTML لتكوين قائمة من الكتب، فكيف يمكن التعويض عنه في نص XML في كود فيجوال بيزيك، بحيث يبدو الكود مشابها لصياغة vbhtml؟
أول حل فكرت فيه هو استخدام استعلامات LinQ كالتالي:
<ul>
   <%= (From book In model Select
       <li><%= book.Name %></li>) %>
</ul>
ولقد نجحت هذه الفكرة وأعطت الناتج المتوقع، لكني شعرت أنها لا تشبه الكود الأصلي، لهذا قررت أن أستخدم حلقة تكرار For Eech لكن كيف يمكن تضمينها ضمن XML مباشرة بدون تعريف دالة مستقلة ووضعها فيها؟.. تذكر أن الهدف هو كتابة كود يبدو أشبه بكود HTML كامل وواضح حتى يمكن فهمه وتطويره فيما بعد، وأن تجزئته على عدة دوال يفسد هذا الهدف!
الحل الوحيد المتاح إذا هو استخدام الدوال الفورية Lambda Expressions.. هذه الدوال تمتاز بأنك تعرفها دخل كود الدوال العادية، كما يمكن استدعؤها مباشرة في نفس سطر تعريفها بمجرد وضع قوسي المعاملات ( ) بعد تعريفها (ولو كانت لهذه الدوال الفورية معاملات أرسلها بين القوسين).. لهذا طورت الكود ليصير:
<ul><%= (Iterator Function()
          For Each book In model
            Yield <li><%= book.Name %></li>
          Next
        End Function)() %>
</ul>
هذا الكود يعرف دالة فورية تعمل كمكرر Iterator، أي أنها تعيد استدعاء نفسها عدة مرات لتعيد مجموعة من القيم وليس قيمة واحدة، يتم الحصول على كل منها باستخدام الأمر Yield.. ناتج هذه الدالة سيكون مجموعة من النوع IEnemerator.. لاحظ أننا استدعينا هذه الدالة مباشرة بكتابة القوسين () بعد تعريفها، وأن هذا استلزم وضع تعريف الدالة كله بين قوسين على الصيغة:
(Function() End Function) ( )
لو نظرت للصيغة الأخيرة من الكود، فستلاحظ أنها قريبة للغاية من كود chtml الأصلي.. والحقيقة أن هذا الكود سيصير أفضل قليلا لو استطعنا أن نخفي تعريف الدالة الفورية ونكتبه مباشرة على الصيغة:
<ul><%= For Each book In model
            Yield <li><%= book.Name %></li>
        Next %>
</ul>
وهو ما اقترحته على فريق فيجوال بيزيك وأتمنى أن ينفذوه، لكن لا أتوقع هذا حاليا!
الآن قد أثبتنا فعلا أن فيجوال بيزيك تحتوي على كنز مخبوء هو تعبيرات XML التي لا يوجد مثلها في سي شارب، وأنها قادرة ذاتيا على تمثيل تقنية Razor وكان من الممكن أن توفر ملايين الدولارات لميكروسوفت لو استخدمتها من البداية!
الآن، يمكن أن نضع كل هذا العمل في الفئة التالية:
Class View1
    Dim model As IEnumerable(Of MvcBookStore.Models.Book) 

    Public Sub New(model As IEnumerable(Of MvcBookStore.Models.Book))
        Me.model = model
        ViewBag.Title = "BookStore"
    End Sub 

    Public ReadOnly Property Razor
        Get
            Dim X =
    <html>
        <h3>Browse Books</h3>
        <p>Select from <%= model.Count() %> Books:</p>
        <ul><%= (Iterator Function()
          For Each book In model
            Yield <li><%= book.Name %></li>
          Next
        End Function)() %>
        </ul>
    </html>

            Return X
        End Get
    End Property

End Class

الآن يمكننا أن نرسل إلى هذه الفئة قائمة الكتب، ونقرأ الصفحة التي تقرؤها من الخاصية Razor:
Dim Html = New View1(BookList).Razor
منتهى البساطة!
السؤال الآن، هو كيف يمكن أن نستفيد بهذا الاكتشاف المدهش لإنشاء مشاريع ASP .NET MVC Core بلغة فيجوال بيزك؟
هذا ما سأجيبكم عنه بإذن الله في الجزء الثاني من هذا الموضوع.. لكني أخبركم من الآن أنني نجحت بفضل الله في عمل هذا وأنشأت مشروعا بالإصدار التجريبي لفيجوال ستديو 2019 وعمل بنجاح وظهرت الصفحة كما صممتها.. وقد نشرت هذا المشروع على GitHub هنا:
سأشرح لكم كيف فعلت هذا بإذن الله في الجزء الثاني من هذا الموضوع، لأن هذا الجزء طال كثيرا بالفعل وقد تعبت من الكتابة :).. وقد حرصت على أن أشرح لكم الخطوات التدريجية وطرق التفكير والبدائل، لأنقل لكم الخبرة كاملة، علكم تستفيدون بها، ولعلها تحفز لديكم بعض الأفكار والمقترحات التي تساعدني في تطوير هذه المشروع!
وفي كل الأحوال، هذا يوم فرحة لمبرمجي فيجوال بيزيك، فقد تمكنا أخيرا من كسر الحصار المضروب علينا، وأثبتنا أن فيجوال بيزيك تحتوي على عناصر قوة مدهشة تنتظر من يستخدمها.

ليست هناك تعليقات:

إرسال تعليق

ملحوظة: يمكن لأعضاء المدونة فقط إرسال تعليق.

صفحة الشاعر