مطالب
Protocol Buffers فرمتی برای تبادل دیتا
Protocol Buffers  فرمتی جدید برای تبادل دیتا بین سرور و کلاینت میباشد که توسط گوگل طراحی و ساخته شده است و همچنین اکثر زیرساخت‌های گوگل از این فرمت برای تبادل اطلاعات بین سرویس‌ها استفاده میکنند. Protocol Buffer را میتوان به عنوان جایگزینی برای JSON/XML بکار برد و به دلایل زیادی که در ادامه درباره‌ی آن صحبت میکنیم میتواند گزینه‌ی مناسبی برای Microservices‌ها باشد و همچنین سرعت بالا، سادگی در استفاده، پشتیبانی از زبان‌های برنامه نویسی متعدد از ویژگی‌های منحصر به فرد این زبان برای تبادل اطلاعات است.
در ابتدا میخواهم کمی راجع به تبادل دیتا، از گذشته تا به حال صحبت کنم:
مدت‌ها است از csv‌ها برای تبادل اطلاعات استفاده میشود؛ اما مزایا و معایب خاص خود را دارد، از جمله اینکه parse کردن راحتی دارد، راحتی در خواندن و غیره. معایبش هم این‌است که گارانتی برای نوع type ندارد و اینکه المان‌هایی که حاوی کاما هستند با مشکل رو به رو میشوند و غیره...
بعد از آن دیتابیس‌ها وارد کار شدند که همه‌ی ما کم و بیش با آنها آشنا هستیم؛ در آن‌ها دیتا‌ها کاملا با type مشخصی هستند و اینکه در table‌های مجزا ذخیره میشوند. مشکلاتش هم این است که دیتا باید حتما flat باشد و اینکه بین دیتابیس‌های مختلف definition‌های مختلفی وجود دارد.
بعد از آن با JSON آشنایی داریم که مزایای زیادی دارد و مدت هاست که مورد استفاده قرار گرفته و شامل این‌است که دیتا در آن میتواند تو در تو ذخیره شود، آرایه داشته باشد، کاملا در دنیای وب مورد قبول واقع شده، به وسیله‌ی هر زبانی قابل خواندن‌است و اینکه خیلی راحت در شبکه قابل انتقال می‌باشد. معایبش هم این‌است که خیلی راحت میتواند خیلی بزرگ شود و اینکه قابلیت کامنت، متادیتا و داکیومنتیشن هم ندارد.
اما میرسیم به گزینه‌ی آخر که protocol buffers است و ابزاری هست که ممکن است خیلی‌ها با آن آشنا نباشند. قبل از بررسی دقیقش به مزایا و معایبش می‌پردازیم. مزایا آن این‌است که دیتا در آن کاملا typed میباشد. دیتای آن به صورت اتوماتیک compressed می‌شود. اسکیما در آن توسط زبان منحصر به فردش قابل تعریف است و توسط تقریبا همه‌ی زبان‌های برنامه نویسی مشهور قابل استفاده‌است. تغییرات اسکیما در آن کنترل شده‌است. 3 تا 10 بار کم حجم‌تر و 20 تا 100 بار سریعتر از xml است و اینکه از روی آن می‌توان کد آماده برای استفاده تولید کرد که سرعت برنامه نویسی را خیلی بالا می‌برد. از مشکلاتش هم این است که ممکن است در یک سری از زبان‌های برنامه نویسی خاص قابل استفاده نباشد. البته بر روی C#, Nodejs, C, Go, Python ,... به خوبی کار می‌کند. مشکل دیگرش هم این‌است که نمی‌شود فایلش را با ادیتورها باز کرد و قابل خواندن نیست؛ چون serialized و compressed شده‌است.

طریقه‌ی استفاده از پروتکل بافر
در طی مختصری، نحوه‌ی کار کردن با این ابزار را مورد بررسی قرار می‌دهیم. طبق شکل زیر:

ابتدا از طریق فرمت protocol buffer، فایل‌های خود را که قرار است انتقال داده شوند، مینویسیم.

سپس بصورت خودکار برای زبان برنامه نویسی مطبوع خود آن را generate میکنیم.

کد‌های تولید شده بصورت خودکار و کاملا آماده هستند و ضمن اینکه encode/decode شدن بصورت خودکار توسط فریم ورک انجام شده و قابلیت تعامل بین زبان‌های مختلف برنامه نویسی یا سرویس‌های مختلف برقرار است.


نکته:

  •  بعضی از دیتابیس‌ها از فرمت protocol buffers پشتیبانی میکنند.
  • اکثر فریم ورک‌های RPC شامل gRPC از پروتکل بافر برای تبادل دیتا استفاده میکنند.
  • گوگل برای تمام سرویس‌های داخلی خود از آن استفاده میکند.
  • بعضی از پروژه‌های خیلی بزرگ مثل etcd از پروتکل بافر برای تبادل دیتا استفاده میکنند.
  • ما در این مقاله از ورژن 3 پروتکل بافر استفاده میکنیم.


نصب Code generator

برای اینکه بتوانیم از طریق فایل‌هایی که میسازیم کد‌های generate شده را تولید کنیم، احتیاج به کامپایلر مربوطه را داریم.

اگر از MacOSX استفاده میکنید، به راحتی با استفاده از دستور زیر می‌توانید آن را نصب کنید:

brew install protobuf

اگر هم از ویندوز استفاده میکنید، از این طریق میتوانید نسخه‌ی مورد نظر را به راحتی دانلود و مورد استفاده قرار بدهید:

https://github.com/google/protobuf/releases
https://github.com/google/protobuf/releases/download/v3.5.1/protoc-3.5.1-win32.zip

حالا میخواهیم اولین فایل خود را با این فرمت بسازیم.

اول از همه با هم نگاهی به ساختار فایل مربوطه میاندازیم:

همانطور که در تصویر فوق می‌بینید، همه چیز به سادگی مشخص است؛ ورژن 3 که آخرین ورژن پروتکل بافر میباشد، آیتمی به نام MyMessage با پراپرتی‌هایی مشخص شده از Type بخصوص، تعریف شده‌اند، تگ‌ها هم باید به ترتیب وارد شده باشند.

حالا میخواهیم بصورت واقعی protocol buffer خود را طراحی کرده و سپس از روی آن کد‌های مربوطه را generate نماییم؛ به نام sample.proto بصورت زیر:

syntax = "proto3";

package helloworld;

service Greeter {
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}

در فایل فوق علاوه بر تعریف‌های اولیه، یک سرویس را هم اضافه کرده‌ایم و همچنین متدی را با ورودی و خروجی‌های مشخصی ایجاد کرده‌ایم (امکانات پروتکل بافر خیلی بیشتر از این موارد است؛ از جمله فرمت‌های آرایه و غیره را نیز پشتیبانی میکند، همچنین از روشی برای versioning استفاده میکند که obsolete کردن پراپرتی‌ها و نسخه بندی را بسیار راحت می‌کند و ...). به سادگی قابلیت طراحی و پیاده سازی سرور و کلاینت مربوط به این آیتم ایجاد شده با استفاده از زبان‌های برنامه نویسی مختلف فراهم میباشد. حال کافی‌است که پروتکل بافر خود را با زبان دلخواه خود generate کنیم. در قسمت زیر برای زبان‌های برنامه نویسی Go و #C، کد‌ها را تولید میکنیم.

protoc sample.proto --go_out=plugins=grpc:.  
protoc sample.proto --csharp_out=.

بعد از تولید شدن کد‌ها با استفاده از زبان برنامه نویسی دلخواه خود میتوانید مشاهد کنید سرویس ها، تایپ‌ها و غیره همگی ساخته شده‌اند و کاملا آماده‌ی استفاده هستند.

در مقاله‌ی بعدی به آشنایی با gRPC می‌پردازیم و ضمن اینکه یک سرور با #C و یک کلاینت با زبان برنامه نویسی Go را نوشته که از طریق پروتکل بافر با هم به تبادل اطلاعات می‌پردازند!

مطالب
banned.h

مطالبی توسط تیم Security Development Lifecycle مایکروسافت منتشر شده مبنی بر اینکه آن‌ها هم یک سری از توابع استاندارد زبان C را در کدهای جدید خود ممنوع کرده‌اند. مستندات آن‌را در مقاله زیر می‌توانید مشاهده نمائید:


اخیرا فایل header آن نیز مطابق آخرین به روز رسانی‌های مورد استفاده منتشر شده است:


استفاده از این توابع در کدهای جدید مایکروسافت ممنوع بوده و کدهای قدیمی نیز به مرور اصلاح خواهند شد.

جدیدترین تابعی که به این لیست اضافه شده ، تابع memcpy است که سر منشاء نقایص امنیتی زیر بوده است:
MS03-030 (DirectX)
MS03-043 (Messenger Service)
MS03-044 (Help and Support)
MS05-039 (PnP)
MS04-011 (PCT)
MS05-030 (Outlook Express)
CVE-2007-3999 (MIT Kerberos v5)
CVE-2007-4000 (MIT Kerberos v5)
...!

#pragma deprecated (memcpy, RtlCopyMemory, CopyMemory)
در این حالت زمانیکه کد خود را کامپایل نمائید با اخطار زیر مواجه خواهید شد:
warning C4995: 'memcpy': name was marked as #pragma deprecated
جایگزین آن تابع memcpy_s معرفی شده است و در این حالت کد قدیمی:
char dst[32];
memcpy(dst,src,len);
باید به کد زیر تبدیل گردد:
char dst[32];
memcpy_s(dst,sizeof(dst), src,len);
که یک آرگومان بیشتر دارد و آن هم اندازه‌ی بافر مقصد مورد نظر است.

برای مطالعه بیشتر
Please Join me in welcoming memcpy() to the SDL Rogues Gallery
Unsafe at any speed: Memcpy() banished in Redmond
Good hygiene and Banned APIs
A Look Inside the Security Development Lifecycle at Microsoft

پاسخ به بازخورد‌های پروژه‌ها
نمایش چندی خطی یک فیلد
با سلام
با استفاده از سلول سفارشی مشکل padding شد، ممنون.

منتهی همانطور که مشاهده می‌کنید کماکان با تاریخ مشکل دارم. از تابع FixWeakCharacters نیز استفاده کرده ام ولی باز هم مشکل دارم، کد سلول سفارشی نیز این است : 

public PdfPCell RenderingCell(CellAttributes attributes)
        {
            var value = attributes.RowData.TableRowData.GetSafeStringValueOf(colName);
            var mainTable = new PdfGrid(1)
            {
                WidthPercentage = 100,
                RunDirection = PdfWriter.RUN_DIRECTION_RTL
            };
            string[] seperatedLine = value.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
            foreach (var line in seperatedLine)
            {
                mainTable.AddSimpleRow((data, cellProperties) =>
                       {
                           cellProperties.BorderWidth = 1f;
                           cellProperties.BackgroundColor = attributes.BasicProperties.BackgroundColor;
                           data.Value = line.FixWeakCharacters();
                           cellProperties.RunDirection = PdfRunDirection.RightToLeft;
                           cellProperties.CellPadding = 2;
                           cellProperties.PdfFont = attributes.BasicProperties.PdfFont;
                           cellProperties.HorizontalAlignment = HorizontalAlignment.Left;
                       });
            }

            var cell = new PdfPCell
            {
                Border = 1,
                RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                HorizontalAlignment = Element.ALIGN_RIGHT
            };
            cell.AddElement(mainTable);
            return cell;

        }

با تشکر

مطالب
استفاده از ادیتور CKEditor در صفحات ASP.NET
در مواردی مانند همین وبلاگ احتیاج به داشتن محل نوشتن، در محیط ادیتور مانندی میباشد که برای این مورد میتوان از ادیتور CKEditor استفاده کرد. بعد از دانلود محتویات مربوطه (که در اینجا از dll مربوط به asp.net استفاده نشده بلکه فایل‌های ادیتور مستقیما مورد استفاده قرار گرفته است)، کافیست لینک‌های مربوط به جاوا اسکریپت و استایل را به هدر اضافه کرد:

<link href="admin/editor/contents.css" rel="stylesheet" type="text/css" />
<script src="admin/editor/ckeditor.js" type="text/javascript"></script>
 و در کد صفحه، بسته به زبان مورد نیاز، یک اسکریپت را به صفحه اضافه نمود؛ در اینجا فارسی استفاده شده:
var clientId = "txtPostBody";
var strEditor = strBodyFa = "CKEDITOR.replace( '" + clientId + "',{skin : 'office2003' , language : 
'fa' , contentsLangDirection : 'rtl'});";
ClientScript.RegisterStartupScript(GetType(), clientId + "_Editor", strBodyFa, true);
در مثال بالا برای باکس متنی به بنام txtPostBody، کد مربوط ایجاد و به صفحه افزوده شده است.
نکته: پوشه مربوط به ادیتور در محلی که در دسترس صفحه باشد باید قرار گیرد که در اکثر موارد قسمت ادمین وب یا اپلیکشن است
مطالب
برنامه نویسی پیشرفته JavaScript - قسمت 5 - معرفی برخی عملگرها

معرفی برخی عملگرها

در مقالات قبلی مقدماتی را جهت ورود به برنامه نویسی شیء گرا در جاوا اسکریپت مطرح کردیم و در اینجا نیز به معرفی برخی عملگرها می‌پردازیم که در برنامه نویسی شیء گرا نقشی اساسی را ایفا می‌کنند.


عملگر typeof

از آنجائیکه جاوا اسکریپت دارای نوع داده‌ای ضعیف یا Loosely Typed می‌باشد، باید در بکارگیری متغیرها و یا آرگومانهای ورودی توابع، دقت لازم را داشته باشیم تا خطایی در اجرای کد یا محاسبات به وجود نیاید. بنابراین به راهکارهایی نیاز داریم تا بتوانیم نوع داده‌ای یک متغیر را تشخیص دهیم و قبل از بکارگیری آنها صحت و اعتبار داده‌های ورودی را بررسی کنیم. با استفاده از عملگر typeof می‌توانیم نوع داده‌ای یک متغیر را تشخیص دهیم که برای هر نوع داده‌ای مقادیر زیر را بر میگرداند:

· برای متغیرهایی که شامل مقدار undefined می‌باشند مقدار "undefined"

· برای متغیرهای منطقی یا Boolean مقدار "boolean"

· برای متغیرهای رشته‌ای یا String مقدار "string"

· برای متغیرهای عددی و مقادیر NaN و Infinity مقدار "number"

· برای تابع مقدار "function"

· برای اشیا و مقادیر null مقدار "object"

var x;
var n = 12;
var obj = {};
var fn = function () { };
var a = new Array();

alert(typeof x);        // "undefined"
alert(typeof n);        // "number"
alert(typeof obj);     // "object"
alert(typeof fn);       // "function"
alert(typeof a);        // "object"

عملگر instanceof

عملگر typeof بهترین روش جهت تشخیص نوع داده‌ای متغیرهایی است که دارای نوع داده‌ای پایه یا Primitive Type هستند. اما جهت تشخیص نوع داده‌ای اشیاء و به صورت کلی انواع ارجاعی، این عملگر فقط مقدار "object" را برمیگرداند و اشاره‌ای به ماهیت واقعی آن Object ندارد. برای این منظور می‌توانیم از عملگر instanceof استفاده نماییم تا بررسی کنیم یک نوع ارجاعی از جنس چه نوع Object ی می‌باشد. شکل کلی استفاده از این عملگر به صورت زیر است:

result = variable instanceof constructor

اگر variable ، از جنس نوع ارجاعی تعیین شده در بخش سازنده یا constructor باشد، عملگر instanceof مقدار true را بر می‌گرداند. به مثال زیر توجه کنید:

var a = new Array();
alert(a instanceof Array); // true
alert(a instanceof Object);   // true
alert(a instanceof Date); // false
توجه داشته باشید که اگر عملگر instanceof برای یک نوع ارجاعی به کار رود و با سازنده Object بررسی شود، همیشه مقدار true برمی گرداند.

عملگر in

همانطور که قبلا اشاره شد، جهت دسترسی به اعضای یک شیء، می‌توان با آن شیء همانند یک آرایه رفتار نمود. به عبارتی دیگر میتوان نام یک ویژگی یا تابع را در [] قرار داد تا به مقدار آن دسترسی داشت. بنابراین می‌توان همانند یک آرایه و با استفاده از یک حلقه‌ی for-in تمامی اعضای یک شیء را پیمایش نمود. در واقع عملگر in در این حلقه بررسی می‌کند چه ویژگی‌ها و توابعی در یک شیء وجود دارند و تمامی آنها را بر می‌گرداند. به مثال زیر توجه کنید:

var person = {
    name: "Meysam",
    age: 33,
    sayInfo: function () {
        alert(name + ":" + age);
    }
};

for (var i in person) 
    alert(i + " => " + person[i]);

خروجی :

     name => Meysam

    age => 33

    sayInfo => function() {
        alert(name + ":" + age);
    }
در مثال فوق، توسط حلقه‌ی for-in ، شیء person را پیمایش نمودیم. در این پیمایش، متغیر i ، به تک تک اعضای موجود در این شیء اشاره می‌کند. بنابراین متغیر i شامل نام ویژگی یا تابع می‌باشد و person[i] مقدار موجود در آن ویژگی یا محتوای تابع را بر میگرداند.

کاربرد دیگر عملگر in بررسی وجود یک ویژگی یا تابع در یک شیء می‌باشد. اگر ویژگی یا تابع مورد نظر در شیء وجود داشته باشد، مقدار true را  بر می‌گرداند. به مثال زیر توجه کنید:

alert("name" in person); // true
alert("sayInfo" in person); // true
alert("birth" in person); // false


عملگر delete

از عملگر delete جهت حذف یک ویژگی و یا یک تابع از یک شیء استفاده می‌شود. به مثال زیر توجه کنید:

var person = {
    name: "Meysam",
    age: 33,
    sayInfo: function () {
        alert(name + ":" + age);
    }
};

alert("sayInfo" in person); // true
delete person.sayInfo;
alert("sayInfo" in person); // false
در مثال فوق پس از به کارگیری عملگر delete ، تابع sayInfo از شیء person حذف شده است. بنابراین در آخرین alert اعلام می‌کند که شیء person دیگر شامل این تابع نمی‌باشد.


ویژگی constructor

پس از عملگرهای فوق، یکی از پرکاربردترین ویژگی‌هایی که برای اشیاء وجود دارد، ویژگی constructor می‌باشد. در واقع این ویژگی نیز یکی از راهکارهای بررسی صحت و اعتبار متغیرها، آرگومانها و اشیا می‌باشد. ویژگی constructor ، به تابع سازنده‌ی یک شیء اشاره می‌کند و آن سازنده را به عنوان خروجی بر میگرداند. دقت داشته باشید که خروجی این ویژگی، خود تابع سازنده می‌باشد و یک مقدار رشته‌ای نیست. به مثال زیر توجه کنید:

var obj = {};
var a = new Array();
var x = 10;

alert(obj.constructor);
alert(obj.constructor === Object);
alert(typeof obj.constructor);
alert(a.constructor);
alert(x.constructor);

خروجی :

    function Object() { [native code] }
    true
    function
    function Array() { [native code] }
    function Number() { [native code] }
همانطور که در مثال فوق مشاهده می‌نمایید، کدهای obj.constructor ، a.constructor و x.constructor تابع سازنده‌ی این اشیا را برگردانده است. در مقایسه obj.constructor===Object نیز مشاهده می‌کنید که خروجی این ویژگی یک شیء می‌باشد و در typeof obj.constructor هم نشان دادیم که نوع این ویژگی یک تابع است.

در اینجا دیگر آماده‌ی ورود به برنامه نویسی شیء گرا در جاوا اسکریپت می‌باشیم که در مقالات بعدی به آن خواهیم پرداخت و همچنین با جزئیات بیشتری اشیاء را تشریح می‌نماییم. 

مطالب
معماری module based در TypeScript قسمت اول
در صورت استفاده از TypeScript، قطعا با module‌ها و هدف استفاده‌ی از آن‌ها آشنایی دارید. در این مقاله می‌خواهیم با متداول‌ترین روش‌های بسته بندی آن‌ها آشنا شده و به صورت عملیاتی آن را پیاده نماییم. اولین روش commonjs میباشد. از آنجایی که این روش بیشتر برای برنامه‌های خارج از مرورگر میباشد، به همین قدر معرفی آن بسنده میکنیم. اما دو روش مهم دیگری که در typeScript برای ماژول‌ها اهمیت فراوانی دارند:

1) AMD یا Asynchronous Module Definition
2) در این روش از امکانات توکار کامپایلر typescript برای combine کردن فایل‌ها استفاده میشود

ابتدا AMD را بررسی مینماییم
این روش بدین صورت عمل میکند که هر ماژول، در صورتیکه بطور صریح نیاز به ماژول دیگری داشته باشد، آن را import کرده و به صورت async آن ماژول درخواستی را دریافت مینماید. بهترین ابزار برای انجام اینکار requirejs میباشد و در وبسایت رسمی آن، خودش را اینگونه معرفی کرده است:
RequireJS is a JavaScript file and module loader ، ما عملیات load کردن فایل‌ها را به requirejs واگذار میکنیم.
حال میخواهیم به پیاده سازی AMD با استفاده از typescript و البته requirejs بپردازیم.
بنده برای اینکار از IDE محبوب خود visual studio استفاده خواهم کرد. قطعا شما از IDE/Text editor مورد نظر خود میتوانید استفاده نمایید (البته با کمی تغییرات جزیی در محتوای آموزشی این مقاله).
ابتدا یک پروژه‌ی asp.net از نوع empty را بدون هیچ وابستگی ایجاد کرده و index.html را بدان اضافه مینماییم:

نام پروژه‌ی من AMD و فایل index.html بدان اضافه شده است. فرض کنید یک پوشه‌ی جدید را به نام modules به آن اضافه میکنیم و در آن دو فایل typescript ی را به نام‌های module1.ts و module2.ts، اضافه میکنیم.

محتویات module1 را اینگونه مینویسیم:

export module module1 {
    export abstract class firstCls {
        static f1(str: string) {
            console.log(str);
        }
    }
}

و همچنین module2 به شکل زیر خواهد بود:

import * as Amd from 'module1';

module module2 {
    export class secondCls {
        f2(str: string) {
            Amd.module1.firstCls.f1(str);
        }
    }
}

new module2.secondCls().f2(`amd work's`);

(دقت کنید بعد از کامپایل شدن لفظ import تبدیل به define میشود)

از طریق add - new item فایل tsconfig.json را به مسیر اصلی پروژه اضافه کنید. در صورتی که آن را پیدا نکردید، به صورت دستی فایل آن را ساخته و محتویات زیر را در آن کپی نمایید:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": false,
    "target": "es6",
    "module": "amd"
  },
  "exclude": [
    "node_modules"
  ]
}
exclude مسیرهایی هستند که قرار نیست کامپایل شوند. target نوع کد تولید شده را مشخص مینماید (در صورتیکه مرورگر شما از es6 پشتیبانی نمیکند، میتوانید target را به es5 تغییر دهید) و module نیز از نوع amd تعریف میشود. کاری که قرار است انجام دهیم این است که به محض فراخوانی module2 به صورت async ، ماژول module1 را load کرده تا بتوان از آن بهره برد. متاسفانه در حال حاضر هیچ مرورگری به صورت توکار این ویژگی را پشتیبانی نمیکند! به همین دلیل فعلا مجبور به استفاده از ابزار‌های third party همچون requirejs هستیم.

در ادامه به root پروژه رفته و دستور npm init را ارسال کرده تا فایل package.json تولید شود. همچنین برای requirejs نیز دستور زیر را ارسال مینماییم:

npm install requirejs --save-dev

حال requirejs به پروژه‌ی شما اضافه شده است.


برای مدیریت کردن فراخوانی initial module در پوشه‌ی modules که قبلا ساخته بودیم فایل main.js راساخته و کد‌های زیر را بدان اضافه مینماییم.

(لازم به ذکر است این فایل را میتوانیم با استفاده از typescript نوشته و  requirejs definitely typed  را به پروژه اضافه کرده و از مزایای intellisense بودن بهره ببریم)

کد‌های زیر را درون main.js مینویسیم:

require(['modules/module2.js'], modules_module2());

function modules_module2() {
    //additionals config goes here
}

از آنجاییکه ممکن است تعداد وابستگی فایل‌ها زیاد باشد و ترتیب load شدن آن‌ها نیز اهمیت داشته باشد، در این قسمت میتوان configهای بیشتری را همچون sequence در load کردن فایل‌ها، تعریف کرد که میتوانید در وبسایت رسمی requirejs آن را مطالعه بفرمایید.


حال فایل index.html را باز کرده و config برای فراخوانی requirejs, main.js را مینویسیم؛ به صورت زیر:

<h1>Hello requirejs and amd modules</h1>

<!--src means require js address-->
<!--data-main means initial require config-->

<script src="node_modules/requirejs/require.js" data-main="modules/main.js"></script>

<script></script>

پر واضح است که src آدرس فایل require.js و همچنین data-main آدرس initial require config پروژه را مشخص می‌کند.

اکنون پروژه را run کرده و می‌بینید که فایل‌های مورد نیاز به صورت async برای ما load میشوند. اگر از مرورگر کروم استفاده می‌نمایید، بدین صورت میتوانید network و همچنین console را مشاهد نمایید:


مشاهد میکنید که فایل‌های مورد نیاز load شده‌اند و همچنین amd work's در console نمایش داده شده است.

requirejs بدین صورت عمل میکند: بعد از یافتن هر فایل، با استفاده از regex کل فایل را بررسی کرده و به دنبال وابستگی‌های آن فایل میگردد (منظور همان import‌ها میباشد و آن فایل به صورت async لود میشود) و در فایل‌های بعدی نیز همین روال ادامه خواهد یافت. هر چند راهکارهایی برای بهبود کارآیی در آن اندیشیده شده است؛ بدین صورت که اساس کارش با استفاده از singleton میباشد و بعد از require کردن فایلی، هر دفعه که فراخوانی میشود، نیاز به پردازش مجدد ندارد. با این وجود ممکن است در بعضی مواقع و مخصوصا با اشتباهات سهوی برنامه نویسان از کارآیی نرم افزار مطبوع شما بکاهد.


کد‌های این برنامه را میتوانید از اینجا دریافت نمایید (ضمن اینکه وابستگی‌های اضافه‌تری مانند پوشه‌ی node_modules حذف شده‌اند؛ بنابراین npm install فراموش نشود)

دانلود AMD.zip  


در قسمت بعد به امکانات توکار کامپایلر typescript برای معماری ماژول‌ها میپردازیم

مطالب
کار با SignalR Core از طریق یک کلاینت جاوا اسکریپتی
کلاینت جاوا اسکریپتی SignalR Core، بازنویسی کامل شده‌است و دیگر وابستگی به jQuery ندارد. این کلاینت از طریق npm توزیع می‌شود:
 npm install @aspnet/signalr-client --save
فایل‌های آن نیز شامل فایل‌های جاوا اسکریپتی مرتبط و همچنین Typings مورد استفاده‌ی در TypeScript است که نمونه‌ای از نحوه‌ی استفاده از این Typings را در مطلب «کار با SignalR Core از طریق یک کلاینت Angular» مطالعه کردید.


بررسی محتوای پوشه‌ی node_modules\@aspnet\signalr-client

پس از نصب بسته‌ی «aspnet/signalr-client@»، در مسیر node_modules\@aspnet\signalr-client\dist دو پوشه‌ی src و browser را خواهید یافت. پوشه‌ی src حاوی منبع کامل این کلاینت و همچنین فایل‌های Typings مخصوص تایپ‌اسکریپت است.


و پوشه‌ی browser آن شامل دو گروه فایل است:


- در اینجا گروهی از فایل‌ها، حاوی عبارت ES5 هستند و تعدادی خیر. SignalR JavaScript بر اساس ES 6 یا EcmaScript 2015 تهیه شده‌است و از مفاهیمی مانند Promises  و  arrow functions استفاده می‌کند. باید دقت داشت که تعدادی از مرورگرها مانند IE از این قابلیت‌ها پیشتیبانی نمی‌کنند. در بین این فایل‌ها، آن‌هایی که حاوی عبارت ES5 نیستند، یعنی بر اساس ES 6 تهیه شده‌اند. سایر فایل‌ها توسط قابلیت Transpile مربوط به TypeScript به ES5 ترجمه شده‌اند. به علاوه حجم این فایل‌ها نیز بیشتر می‌باشد؛ چون حاوی تعاریف وابستگی‌هایی هستند که در ES 5 وجود خارجی ندارند. بنابراین بسته به نوع مرورگر مدنظر، یکی از این دو گروه را باید انتخاب کرد؛ ES 6 برای مرورگرهای جدید و ES 5 برای مرورگرهای قدیمی.
- به علاوه در اینجا تعدادی از فایل‌ها حاوی عبارت msgpackprotocol هستند. نگارش جدید SignalR از پروتکل‌های هاب سفارشی مانند پروتکل‌های باینری نیز پشتیبانی می‌کند. همچنین حاوی یک پیاده سازی توکار از پروتکل‌های باینری بر اساس MessagePack نیز هست. چون حجم کدهای پشتیبانی کننده‌ی از این پروتکل ویژه بالا است، آن‌را به یک فایل مجزا انتقال داده‌اند تا در صورت نیاز مورد استفاده قرار گیرد. بنابراین اگر از این پروتکل استفاده نمی‌کنید، نیازی هم به الحاق آن در صفحات خود نخواهید داشت. فایل third-party-notices.txt نیز مربوط است به یادآوری مجوز استفاده‌ی از MessagePack که MIT می‌باشد.
- در هر گروه نیز، دو فایل min و معمولی قابل مشاهده‌است. فایل‌های min برای توزیع نهایی مناسب هستند و فایل‌های غیرفشرده شده برای حالت دیباگ.


استفاده از کلاینت جاوا اسکریپتی SignalR Core

برای کار با کلاینت جاوا اسکریپتی SignalR Core از همان فایل‌های موجود در پوشه‌ی node_modules/@aspnet/signalr-client/dist/browser استفاده می‌کنیم. تفاوت این کلاینت با نگارش قبلی SignalR به صورت یک ذیل است:
1) ارجاع به فایل قدیمی signalR-2.2.1.min.js با فایل جدید signalR-client-1.0.0-alpha1.js جایگزین می‌شود. اگر می‌خواهید مرورگرهای قدیمی را پشتیبانی کنید، نگارش ES5 آن‌را لحاظ کنید.
2) پروکسی‌ها با new HubConnection جایگزین شده‌اند.
3) برای ثبت callbackهای سمت کلاینت، از متد جدید on استفاده می‌شود.
4) بجای متد done مربوط به jQuery، در اینجا از متد then مربوط به ES6 کمک گرفته شده‌است.
5) کار فراخوانی متدهای هاب توسط متد invoke انجام می‌شود.


یک مثال: بازنویسی قسمت سمت کلاینت مثال «کار با  SignalR Core از طریق یک کلاینت Angular» با jQuery

هرچند کلاینت جدید SignalR Core وابستگی به jQuery ندارد، اما جهت سهولت کار با DOM، کدهای سمت کلاینت مثال قبلی را با jQuery بازنویسی می‌کنیم. تمام کدهای سمت سرور این مثال با مطلب «کار با SignalR Core از طریق یک کلاینت Angular» یکی است؛ مانند ایجاد هاب، فعالسازی SiganlR در فایل آغازین برنامه و ثبت مسیرهاب. بنابراین در اینجا، این قسمت از کدهای سمت سرور را مجددا تکرار نمی‌کنیم و تمام نکات آن یکی هستند.

برای کار با کلاینت جاوا اسکریپتی SignalR Core، اینبار دستور ذیل را در ریشه‌ی پروژه‌ی وب اجرا می‌کنیم (یا هر پروژه‌ای که قرار است مدیریت فایل‌های سمت کلاینت و Viewهای برنامه را انجام دهد):
npm init
npm install @aspnet/signalr-client --save
bower install
دستور اول یک فایل package.json خالی را ایجاد می‌کند و دستور دوم بسته‌ی جاوا اسکریپتی SiganlR Core را نصب خواهد کرد. به علاوه این وابستگی را در فایل package.json نیز ثبت می‌کند. دستور سوم نیز وابستگی‌های قید شده‌ی در فایل bower.json را نصب می‌کند.

مرحله‌ی بعدی کار، تنظیمات فایل bundleconfig.json است؛ تا تمام اسکریپت‌های مورد نیاز جمع‌آوری و یکی شوند:
[
  {
    "outputFileName": "wwwroot/css/site.min.css",
    "inputFiles": [
      "wwwroot/lib/bootstrap/dist/css/bootstrap.min.css",
      "wwwroot/css/site.css"
    ]
  },
  {
    "outputFileName": "wwwroot/js/site.min.js",
    "inputFiles": [
      "wwwroot/lib/jquery/dist/jquery.min.js",
      "wwwroot/lib/bootstrap/dist/js/bootstrap.min.js",
      "node_modules/@aspnet/signalr-client/dist/browser/signalr-client-1.0.0-alpha1-final.min.js",
      "wwwroot/lib/jquery-validation/dist/jquery.validate.min.js",
      "wwwroot/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js",
      "wwwroot/lib/jquery-ajax-unobtrusive/jquery.unobtrusive-ajax.min.js",
      "wwwroot/js/site.js"
    ],
    "minify": {
      "enabled": false,
      "renameLocals": false
    },
    "sourceMap": false
  }
]
در اینجا نحوه‌ی ثبت فایل signalr-client-1.0.0-alpha1-final.min.js مبتنی بر ES 6 را مشاهده می‌کنید. اگر می‌خواهید نگارش ES 5 آن‌را ذکر کنید، از فایل signalr-clientES5-1.0.0-alpha1-final.min.js استفاده نمائید.
با توجه به خروجی‌های نهایی فایل bundleconfig.json، تنها نیاز است مداخل ذیل را به فایل layout برنامه اضافه کرد:
<link href="~/css/site.min.css" rel="stylesheet" asp-append-version="true" />
<script src="~/js/site.min.js" type="text/javascript" asp-append-version="true"></script>

مرحله‌ی بعد، تغییر نام متد send قسمت قبل به broadcastMessage است:
public class MessageHub : Hub
{
   public Task Send(string message)
   {
     return Clients.All.InvokeAsync("broadcastMessage", message);
   }
}
به این ترتیب می‌توان به تمایز بهتری بین نام callback سمت کلاینت و متد Send سمت سرور رسید. بهتر است این‌دو هم‌نام نباشند.
در ادامه یک کنترلر ساده را به نام JsClientController با View ذیل ایجاد می‌کنیم:
<form method="post"
      asp-action="Index"
      asp-controller="Home"
      data-ajax="true"
      role="form">
  <div class="form-group">
     <label label-for="message">Message: </label>
     <input id="message" name="message" class="form-control"/>
  </div>
  <button class="btn btn-primary" type="submit">Send To Home/Index</button>
  <button class="btn btn-success" id="sendmessageDirect" type="button">Send To /message hub directly</button>
</form>

<div id="discussion">
</div>
کار آن نمایش فرم ذیل است:


از اولین دکمه برای ارسال یک پیام به کنترلر Home که در آن توسط <IHubContext<MessageHub پیامی به تمام کلاینت‌ها ارسال می‌شود، استفاده شده‌است. دومین دکمه متد Send هاب را مستقیما فراخوانی می‌کند؛ با این کدهای سمت کلاینت:
@section Scripts
{
   <script type="text/javascript" asp-append-version="true">
   $(function() {
      var connection = new signalR.HubConnection('/message');
      connection.on('broadcastMessage', function (message) {
          // Add the message to the page.
          var encodedMsg = $('<div />').text(message).html();
          $('#discussion').append('<li>' + encodedMsg + '</li>');
      });

      connection.start().then(function () {
          console.log('connected.');
          $('#sendmessageDirect').click(function () {
              // Call the Send method on the hub.
              connection.invoke('send', $('#message').val());
          });
      });
   });
   </script>
}
- ابتدا یک شیء جدید signalR.HubConnection ایجاد می‌شود. این شیء به آدرس Hub تعریف شده‌ی در فایل آغازین برنامه اشاره می‌کند.
- سپس در متد on هست که مشخص می‌کنیم متد سمت کلاینتی که قرار است از سمت سرور فراخوانی شود، چه نامی دارد. نام آن‌را در این مثال broadcastMessage درنظر گرفته‌ایم. در اینجا پارامتر message از سمت سرور دریافت شده و سپس در صفحه‌ی جاری نمایش داده می‌شود.
بدیهی است متد Send می‌تواند تعداد پارامترهای بیشتری را بپذیرد و همچنین متد broadcastMessage نیز محدودیتی از لحاظ تعداد پارامتر ندارد. اگر پارامترهای بیشتری را تعریف کردید، در همینجا باید قید شوند.
- در ادامه کار شروع این اتصال آغاز می‌شود. در متد then هست که باید کار اتصال دکمه‌ی sendmessageDirect صورت گیرد. چون عملیات اتصال ممکن است زمانبر باشد و connection ارسالی هنوز آغاز نشده باشد. در اینجا نحوه‌ی فراخوانی مستقیم متد Send سمت سرور را با یک پارامتر ملاحظه می‌کنید. این متد نیز می‌تواند بر اساس امضای متد Send سمت سرور، تعداد پارامترهای بیشتری را قبول کند.


کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید: SignalRCore2WebApp02.zip
برای اجرا آن باید این دستورات را به ترتیب وارد کنید:
dotnet restore
npm install
npm install -g bower
bower install
dotnet watch run
نظرات اشتراک‌ها
منابع مطالعاتی Owin - قسمت دوم
در یکی از فیدخوان‌های آنلاین آدرس سایتش را وارد کنید. بعد قادر خواهید مطالب آن‌را از طریق فید سایت مطالعه کنید. فید خوان‌ها قابلیت auto discovery دارند. یعنی قادرند صفحه‌ی اصلی سایت را برای یافتن فید RSS آن اسکن کنند و link type=application/rss+xml‌ها را مورد استفاده قرار دهند.
مطالب
بارگذاری فایل‌های ایستا از پوشه‌ی Views در ASP.NET MVC
گاهی از اوقات تنها نیاز است یک View خاص و نه تمام صفحات سایت، فایل اسکریپت ویژه‌ی خود را مورد استفاده قرار دهد. در این حالت می‌توان فایل اسکریپت مورد نیاز آن‌را مطابق معمول در پوشه‌ی Scripts در کنار سایر فایل‌ها قرار داد و یا ... حتی شاید بهتر باشد این فایل اسکریپت ویژه را در همان پوشه‌ی View مورد نظر قرار داد. اگر اینکار را انجام دهیم، برنامه کار نخواهد کرد و فایل اسکریپت با خطای 404، بارگذاری نمی‌شود. علت اینجا است که در ریشه پوشه‌ی Views، فایل web.config خاصی با تنظیم ذیل قرار دارد:
  <system.webServer>
    <handlers>
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode"
           type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
به این ترتیب هر درخواستی که به پوشه‌ی views یک برنامه‌ی ASP.NET MVC برسد، با پیغام 404 مواجه خواهد شد.
در ادامه می‌خواهیم این تنظیم همانگونه که بوده‌است، حفظ شود (چون مسیر پردازش صفحات در MVC از کنترلر به View است و نیازی نیست تا ابتدا View خاصی بارگذاری شود) اما اجازه دهیم تا فایل‌های JavaScript از این مسیر قابل بارگذاری و استفاده شوند. برای این منظور می‌توان با ویرایش فایل Views/web.config به صورت زیر عمل کرد:
  <system.webServer>
    <handlers>
      <add name="JavaScriptHandler"
         path="*.js"
         verb="*"
         preCondition="integratedMode"
         type="System.Web.StaticFileHandler" />
      <remove name="BlockViewHandler"/>
      <add name="BlockViewHandler" 
           path="*" 
           verb="*" 
           preCondition="integratedMode"
           type="System.Web.HttpNotFoundHandler" />
    </handlers>
  </system.webServer>
در اینجا امکان قرار دادن فایل‌های اسکریپت یک پوشه‌ی خاص تحت ریشه‌ی Views و بارگذاری معمولی آن میسر شود؛ بدون اینکه امکان دسترسی به فایل‌های cshtml یا سایر فایل‌های دیگر مانند قبل وجود داشته باشد.


در ادامه برای مسیر دهی این فایل اضافه شده باید به نحو ذیل عمل کرد:
 <script type="text/javascript" src="~/Views/Home/Test.js"></script>
مطالب
راه اندازی StimulSoft Report در ASP.NET MVC
یکی از ارکان لاینفک سیستم‌های سازمانی در هر پلتفرمی، چه وب و چه دسکتاپ و ... گزارش گیری از اطلاعات موجود و جزو ساختار حیاتی آن است. از آنجا که حتی ممکن است این گزارشات در هر دوره نیاز به تغییرات داشته باشند و گزارش‌های پویایی باشند؛ این نیاز احساس می‌شود که از یک برنامه گزارش ساز مناسب بهره ببریم. یکی از گزارش سازهای محبوب به خصوص در ایران که حتی نماینده رسمی آن هم در ایران وجود دارد، گزارش ساز StimulSoft Report است.

دارا بودن امکانات بسیار قدرتمند و پشتیبانی از محیط فارسی و همچنین پشتیبانی آن‌ها جهت پاسخگویی به سوالات، چه از طریق ایمیل یا چت، از نقاط قوت این ابزار به شمار می‌روند. در جدول مقایسات می‌توانید تفاوت نسخه‌های موجود این گزارش ساز را مشاهده کنید. برای استفاده در MVC از نسخه وب آن استفاده میکنیم.

در این مقاله قصد داریم با نحوه راه ندازی این ابزار در وب (MVC) آشنا شویم که شامل مباحث زیر می‌شود:
  1. استفاده از EF به عنوان منبع داده و ارسال آن‌ها به سمت گزارش ساز
  2. نحوه طراحی فایل MRT و بایند کردن داده‌های اطلاعاتی و ایجاد جدول
  3. استفاده از امکانات فایل خروجی ، چاپ و پیش نمایش و...
  4. بررسی Direction جهت استفاده در محیط‌های فارسی زبان
  5. نحوه ارسال اطلاعات بین دو اکشن متفاوت


طراحی فایل MRT

فایل MRT در واقع یک قالب (Template) خالی از مقادیر متغیر است که در StimulSoft Studio به طراحی آن میپردازیم و در برنامه خود، این مقادیر متغیر را با اطلاعات دلخواه خود جایگزین می‌کنیم. تصویر زیر یک نمونه از یک گزارش خالی است که ابتدا آن را طراحی کرده و سپس در برنامه آن را مورد استفاده قرار می‌دهیم:

برای اینکه فایل MRT بتواند دیتاهای لازمی را که به آن پاس میدهیم، بخواند و در جای مشخص شده قرار بدهد، باید یک BussinessObject برای آن ایجاد کنیم. بعد از اینکه یک گزارش جدید ایجاد کردید، در سمت راست به قسمت Dictionary بروید و در قسمت BussinessObject گزینه NewBussinessObject را انتخاب کنید. یک نام و نام مستعار که عموما هم یکی است، برای آن انتخاب کنید. در زیر همان پنجره شما می‌توانید ستون‌های اطلاعاتی خود را تعریف کنید. در اینجا من میخواهم اطلاعات یک راننده را به همراه خودروی وی، نشان دهم. برای همین، من دو موجودیت راننده و خودروی راننده را دارم. پس اسم Business Object را DriverReport میگذارم و ستون‌های اطلاعاتی فقط راننده (بدون در نظر گرفتن خودروی وی) را وارد میکنم.

در همین کادر بالا شما میتوانید تصیم بگیرید که آیا میخواهید اطلاعات خودرو را به همراه دیگرستون‌های اطلاعاتی راننده، ایجاد کنید یا اینکه برای خودرو یک نوع مجزا انتخاب کنید. اگر تنها یک خودرو برای راننده باشد، شاید راحت‌تر باشید همانند اطلاعات راننده با آن رفتار کنید. ولی اگر مثلا بخواهید خودروی‌های گذشته راننده را هم جز لیست داشته باشید، بهتر است یک  Business Object جدید متعلق و زیر مجموعه Business Object راننده ایجاد کنید. در اینجا چون تنها یک خودرو است، من آن اطلاعات آن را به همراه راننده، ارسال میکنم. شکل زیر ساختار درختی از گزارش بالاست:

شکل زیر هم یک ساختار دیگر از یک گزارش است که شامل Business object‌های مختلف می‌شود: 

سپس همین فیلدها را به سمت صفحه خالی بکشانید. با دو بار کلیک روی فیلدهای قرار گرفته در صفحه، با نحوه بایند کردن مقادیر آشنا می‌شوید؛ هر فیلدی که قرار است دیتای آن بایند شود، باید به شکل زیر در بخش Expression پنجره باز شده، نوشته شود:

{driverReport.LastName}
در صورتیکه قرار است Business Object به شکل یک لیست ارسال شود؛ مثلا لیست رانندگان یا حتی لیست خودروهایی که یک راننده از گذشته تا کنون داشته است، می‌توانید به جای درگ کردن فیلد به درون صفحه، خود Business Object را درگ کنید تا از روی آن یک جدول درست شود و با ارسال یک لیست به سمت آن و به ازای هر آیتم از این لیست یک سطر داشته باشید.

در دیکشنری همچنین انواع دیگری از فیلدها نیز به چشم میخورد:
متغیرها: این نوع فیلد یک متغیر است که به طور جداگانه میتواند مقداردهی شود و از آن بیشتر برای ارسال داده‌های تکی چون تصاویر، تاریخ شمسی و ... میتوان استفاده کرد.
متغیرهای سیستمی: این نوع متغیرها توسط خود گزارش ساز به طور مستقیم پر می‌شوند که شامل شماره صفحه، تاریخ و زمان، تعداد صفحات، مقادیر دو ارزشی (آیا صفحه آخر گزارش است؟) و ... می‌شود.
توابع: گزارش ساز شامل یک سری توابع آماده برای اعمال تغییرات بر روی داده‌ها میباشد که در دسته‌های مختلفی چون کار با رشته‌ها، زمان، ریاضیات و... قرار گرفته‌اند.
بعد از تکمیل آن، فایل MRT را ذخیره و در یک دایرکتوری در ساختار پروژه قرار دهید.

راه اندازی گزارش ساز در ASP.Net MVC

اولین کاری که می‌کنیم، ورود سه dll اصلی به پروژه است:

Stimulate.Base

Stimulate.Report

Stimulate.Report.MVC

در مرحله بعد یک متد ساخته و یک ویوو را برای صفحه گزارش گیری ایجاد می‌کنیم:

public ActionResult Report(int id)
{
   return View();
}
در ویوی مربوطه کدهای زیر را اضافه می‌کنیم:
@Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
   
    Localization = "~/content/reports/fa.xml",
    Actions =
        {
        
            GetReportSnapshot = "LoadReportSnapshot",
            ViewerEvent = "ViewerEvent",
            ExportReport = "ExportReport",
            PrintReport = "PrintReport",
        }
 }

در نسخه‌های دو سال اخیر، استفاده از این Helper تفاوت‌هایی در نحوه استفاده از خصوصیت‌های آن کرده است. در این روش جدید، پراپرتی‌ها دسته بندی شده و برای دسترسی به هر کدام باید به بخش آن مراجعه کنید؛ مثلا پراپرتی‌های Action، در دسته Actions قرار گرفته‌اند یا خصوصیت‌های ظاهری در دسته Appearance، یا گزینه‌های مرتبط با خروجی گرفتن‌ها، در دسته Export قرار گرفته‌اند و الی آخر که در نسخه‌های پیشین، کد بالا را به شکل زیر،  با پیشوند نام دسته می‌نوشتیم:
@Html.Stimulsoft().StiMvcViewer(new StiMvcViewerOptions()
{
   
    Localization = "~/content/reports/fa.xml",
            ActionGetReportSnapshot = "LoadReportSnapshot",
            ActionViewerEvent = "ViewerEvent",
            ActionExportReport = "ExportReport",
            ActionPrintReport = "PrintReport",
            
}
خصوصیت GetReportSnapshot نام یک اکشن متد است که کار ارسال دیتا را به گزارش ساز، انجام میدهد. باقی خصوصیت‌ها را در ادامه بررسی میکنیم. پس متد LoadReportSnapshot را ایجاد می‌کنم و کدهای زیر را در ادامه آن می‌نویسیم:

بعد از آن لازم است دیتا‌ها را از طریق EF خوانده و به یک مدل جدید که بر اساس اطلاعات گزارش شماست و قرار است گزارش شما این پراپرتی‌ها را بشناسد، به طور دستی یا با استفاده یک کتابخانه mapping مثل automapper انتقال دهید. یا حتی می‌توانید مانند کد زیر از ساختاری ناشناس استفاده کنید. در کد زیر، من به صورت تمرینی اطلاعات یک راننده و خودروی او را انتقال میدهم:
var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                Model = "نام خودرو",
                MotorNumber = 415244,
                ProductionYear = 1394,
                Capacity = 4
                
};
اگر اطلاعات خودرو را هم به صورت مجزا BussinessObject ساخته‌اید باید آن را به شکل زیر تعریف کنید ( با فرض اینکه نام BussinessObject در گزارش، با نام car تعریف شده باشد):
var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                car = new
                {
                    Model = "نام خودرو",
                    MotorNumber = 415244,
                    ProductionYear = 1394,
                    Capacity = 4
                }
};
بعد از اینکه دیتاهای لازم را بر اساس فرمت دلخواه خود آماده کردیم، باید آن‌ها را به سمت گزارش ساز ارسال کنیم:
var report = new StiReport();
            report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
در مرحله اول یک وهله از شیء StiReport را می‌سازیم و فایل گزارشی را که در مرحله قبل ساختیم، به آن معرفی میکنیم. سپس داده‌های لازم را به آن انتقال می‌دهیم. پارامتر اول نام BussinessObject اصلی یعنی driverReport را وارد می‌کنیم و پارامتر دوم هم، همان اطلاعات گزارش است. خط بعدی هم یک متغیر است که من در گزارش تعریف کرده‌ام و در اینجا آن را با تاریخ شمسی امروز پر میکنم. توجه داشته باشید که انتقال اطلاعات حتما باید بعد از استفاده از متد Load باشد؛ در غیر اینصورت انتقالی انجام نخواهد شد. اینکه صرفا شما وهله‌ای از شیء StiReport بسازید و مقادیر را بدون ترتیب پر کنید، کفایت نمی‌کند. یعنی ترتیب زیر یک ترتیب کاملا اشتباه است:
var report = new StiReport();
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
           report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
چیزی که بعدا در خروجی می‌بینید، یک صفحه گزارش بدون مقدار است.
پس کد کامل ما برای ایجاد یک گزارش به شکل زیر می‌شود:
 public ActionResult LoadReportSnapshot()
{
  var driver = new
            {
                FirstName = "علی",
                LastName = "یگانه مقدم",
                NationalCode = "12500000000",
                FatherName = "حسین",
                Model = "نام خودرو",
                MotorNumber = 415244,
                ProductionYear = 1394,
                Capacity = 4

            };

            var report = new StiReport();
            report.Load(Server.MapPath("~/Content/Reports/driver.mrt"));
            report.RegBusinessObject("driverReport", driver);
            report.Dictionary.Variables.Add("today", DateTime.Today.ToPersianString(PersianDateTimeFormat.Date));
return StiMvcViewer.GetReportSnapshotResult(HttpContext, report);
}
همه خطوط، همان قبلی هاست که بررسی کردیم؛ بجز خط آخر که یک ActionResult اختصاصی است که در آن نحوه انتقال اطلاعات به گزارش ساز پیاده سازی شده است و تنها کاری که باید بکنیم این است که شیء گزارش ایجاد شده در بالا را به آن پاس دهیم.

اگر دوباره در ویو مربوطه، به سراغ helper برویم می‌بینیم که سه اکشن متد دیگر وجود دارند که در زیر، به ترتیب با نحوه کار آن‌ها و کد اکشن متد آن‌ها اشاره میکنیم:
Viewer Events : این اکشن متد که تنها یک خط ActionResult استاتیک را فراخوانی می‌کند، جهت مدیریت رویدادهای گزارش چون: زوم، صفحه بندی گزارش، خروجی‌ها و چاپ می‌باشد و وجود آن در گزارش از الزامات است.
 public virtual ActionResult ViewerEvent()
 {
            return StiMvcViewer.ViewerEventResult();
 }

PrintReport: برای مدیریت و ارسال گزارشات به دستگاه چاپ می‌باشد. این اطلاعات از طریق شی HttpContext به سمت اکشن متد ارسال شده و توسط PrintReportResult آن را دریافت می‌کند.
public virtual ActionResult PrintReport()
        {
            return StiMvcViewer.PrintReportResult(this.HttpContext);
        }

ExportReport: گزارش ساز استیمول به شما اجاز میدهد در فرمت‌های گوناگونی چون xlsx,docx,pptx,pdf,rtf و ... از گزارش خود خروجی بگیرید. اطلاعات گزارش از طریق شی HttpContext به سمت اکشن متد ارسال شده و توسط ExportReportResult  دریافت می‌شود. 
 public virtual ActionResult ExportReport()
        {
            return StiMvcViewer.ExportReportResult(this.HttpContext);
        }
حال اگر برنامه را اجرا کنید، باید گزارشی به شکل زیر نمایش داده شود و مقادیر در جای خود شکل گرفته باشند. ولی مشکلی  که ممکن است این گزارش داشته باشد این است که برای فارسی، حالت راست به چپ را ندارد.


 البته خوشبختانه این مشکل  در حالت پیش نمایش و چاپ و خروجی‌ها دیده نمی‌شود و فقط مختص نمایش روی فرم Html است. برای حل این مشکل ممکن است از گزینه یا پراپرتی RightToLeft، در بخش Appearance موجود در helper استفاده کنید که البته استفاده از آن مانند تصویر بالا، فقط محدود به container گزارش و نوار ابزار آن می‌شود. برای حل این مشکل کافی است کد css زیر را به صفحه گزارش اضافه کنید تا مشکل حل شود:
.stiMvcViewerReportPanel table{
    direction:ltr !important;
}
مجددا گزارش را ایجادکنید تا گزارش را به طور صحیحی مشاهده کنید:

حال حتما پیش خود میگویید که این روش برای اطلاعات ایستا و تمرینی مناسب است و من چگونه باید پارامترهای ارسالی به اکشن متد Report را به اکشن متد LoadReportSnapshot ارسال کنم. برای این منظور استفاده از SessionState‌ها زیاد توصیه شده‌است:
 public virtual ActionResult Report(int id)
        {
            TempData["id"]=id;
            return View();
        }

         public virtual ActionResult LoadReportSnapshot()
        {
            var driverId = (int)TempData ["id"];
              //.....
        }
  ولی این روش مشکلات زیادی را دارد. اول اینکه اگر کاربر چند گزارش جداگانه را پشت سر هم باز کند، به دلیل اینکه گزارش مدتی طول می‌کشد باز شود، همه گزارش‌ها آخرین گزارش درخواستی خواهند بود و دوم اینکه مقداری از حافظه سرور را هم بی جهت اشغال میکند. ولی برای کار با استیمول به هیچ یک از این کارها نیازی نیست، چون خود استیمول به طور خودکار پارامترهای ارسالی را انتقال می‌دهد. یعنی کد باید به شکل زیر نوشته شود:
public virtual ActionResult Report(int id)
        {
    
            return View();
        }

         public virtual ActionResult LoadReportSnapshot(int id)
        {
             //.....
        }
همین مقدار کد برای ارسال پارمترها کفایت میکند و مابقی کار را به stimul بسپارید.

نکته بسیار مهم: گزارش ساز استیمول متاسفانه شامل تنظیم پیش فرض نامناسبی است که عملیات کش را بر روی گزارش‌ها اعمال می‌کند. به عنوان مثال تصور کنید من صفحه گزارش شخصی به نام «وحید نصیری» را باز میکنم و در تب دیگر گزارش شخص دیگری با نام «علی یگانه مقدم» را باز میکنم. حال اگر کاربر به سراغ تب آقای نصیری برود و بخواهد چاپ یا خروجی درخواست کند، اشتباها با گزارش علی یگانه مقدم روبرو خواهد شد که این اتفاق به دلیل کش شدن رخ میدهد. برای غیر فعال کردن این قابلیت پیش فرض، کد زیر را در Helper اضافه کنید:
Server =
    {
        GlobalReportCache = false
    }