اشتراک‌ها
نحوه استفاده از بانک اطلاعاتی InfluxDB در دات نت

بانک اطلاعاتی InfluxDB  یکی از انواع بانک‌های اطلاعات NoSQL و مدل Time Series هست که برای مدیریت داده‌های سری زمانی بهینه شده است و هر ورودی با یک مهر زمانی مرتبط است.
محیط مدیریتی برای این بانک اطلاعاتی بعد از نصب از روی یک آدرس وب و با امکانات مفید در دسترس می‌باشد.
همچنین جهت کانکت شدن به این دیتابیس یک توکن بر اساس نام کاربری و پسوردی که برای کاربر ساخته می‌شود تولید می‌شود که از محیط مدیریتی این بانک اطلاعاتی بر روی وب قابل دسترس می‌باشد و برای اتصال از طریق دات نت از همان توکن استفاده می‌کند
نمونه کد اتصال به این بانک اطلاعاتی در صفحه اول سایت influxdata.com در دسترس می‌باشد.

📌  مستندات جهت یادگیری پایگاه اطلاعاتی InfluxDB

همچنین از طریق نصب پکیج InfluxDB.Client امکان کوئری زدن و فیلتر کردن اطلاعات با دستورات Linq روی این پایگاه داده فراهم شده است.

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

تصویر صفحه داشبورد تحت وب این دیتابیس

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

نحوه استفاده از بانک اطلاعاتی InfluxDB در دات نت
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 13 - معرفی View Components
- همانطور که در مقدمه‌ی بحث هم عنوان شد، مفهوم Child Actions از نگارش Core حذف شده‌است؛ چون مشکلات زیادی دارد (به این لیست، مشکلات async و همچنین آغاز یک چرخه‌ی جدید MVC را هم اضافه کنید که کارآیی مناسبی ندارد و یک سربار به شمار می‌رود).
- جایگزین آن ViewComponet است و از لحاظ دسترسی به منابع و سرویس‌ها محدودیتی ندارد. یک مثال
- هنوز هم اگر صرفا نیاز به رندر یک پارشال View را به صورت Ajax ایی دارید، روش زیر کار می‌کند:
جایی که می‌خواستید Html.RenderAction را قرار دهید، قطعه کد Ajax ایی زیر را فراخوانی کنید:
<div id="dynamicContentContainer"></div>
<script>   
    $.get('@Url.Action("GetData", "Home")', {id : 1}, function(content){
            $("#dynamicContentContainer").html(content);
        });
</script>
کار آن دریافت محتوای html ایی اکشن متد ذیل و افزودن آن به div مشخص شده‌است.
[HttpGet]
public IActionResult GetData(int id)
{
   return PartialView(id);
}
با این پارشال View فرضی:
@model int 
<span>Values from controler :</span> @Model
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 15 - بررسی تغییرات Caching
- چرا قسمت cache-control را کامل نکردید؟ دقیقا به همان صورتیکه عنوان شده

- برای اینکه مشاهده کنید این فیلتر کار می‌کند یا نه، باید به برگه‌ی network مرورگر مراجعه کنید و status code نمایش مجدد صفحه را مشاهده کنید:

اثر دکمه‌ی back برای صفحه‌ی لاگینی که کش مرورگر آن توسط فیلتر فوق غیرفعال شده (دریافت مجدد از سرور؛ بجای خوانده شدن از کش مرورگر).

اثر دکمه‌ی back برای یک صفحه‌ی معمولی (از کش مرورگر خوانده شده؛ بجای دریافت مجدد از سرور).

- ضمن اینکه تعریف این فیلتر صرفا برای صفحه‌ی login توصیه می‌شود و نه جای دیگری و نه کل سایت. گیرم شخصی با دکمه‌ی back، محتوای کش شده‌ی قبلی را مشاهده کند. مهم نیست. چون بلافاصله با ارسال یک درخواست جدید، فیلتر Authorize، دسترسی او را سد می‌کند. صفحه‌ی کش شده هم بر اساس دسترسی پیشین او در کش مرورگر وجود دارد. مشاهده‌ی آن صفحه‌ی قدیمی اهمیتی ندارد؛ چون اطلاعات بعدی به روز شده را باید با گذشت از فیلتر Authorize دریافت کند.

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

DbProviderFactory  در Net Framework 2.0. ارائه شده است.برای درک و چگونگی استفاده از DBProviderFactory مثالی را بررسی می‌نماییم.
ابتدا کد زیر را درون یک فرم کپی نمایید:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data.Common;

namespace DBFactory
{
    public partial class Form1 : Form
    {
        private string _MySQLProvider = "MySql.Data.MySqlClient";
        private string _SQLProvider="System.Data.SqlClient";
        private string _OracleProvider ="System.Data.OracleClient";
        private DbProviderFactory _DbProviderFactory;
        private DbConnection _DbConnection = null;
        private DbCommand _DbCommand = null;
        private DbDataAdapter _DbDataAdapter = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            try
            {

             string _SQLconnectionstring = "Integrated Security=SSPI;Persist Security Info=False;Initial Catalog=Test;Data Source=FARHAD-PC";
             string _Oracleconnectionstring = "Data Source=ServiceName;User Id=Username;Password=Password";
             
            _DbProviderFactory = DbProviderFactories.GetFactory(_SQLProvider);
            _DbConnection = _DbProviderFactory.CreateConnection();
            _DbConnection.ConnectionString = _SQLconnectionstring;
            
            _DbConnection.Open();

            if (_DbConnection.State == ConnectionState.Closed)
            {

                MessageBox.Show("اتصال با دیتابیس برقرار نشده است");
            }
            else
            {
                MessageBox.Show("اتصال با دیتابیس با موفقیت بر قرار شده است");
            }
            }
            catch (System.Exception excep)
            {
                MessageBox.Show(excep.Message.ToString());    
            }         

        }
    }
}

برای استفاد از DBProviderFactory می‌بایست از فضای نامی System.Data.Common استفاده نمایید. بعد از اعلان کلاس فرم تعدادی آبجکت تعریف شده است، که سه آبجکت ابتدایی آن، بیانگر Provider دیتابیس‌های MySQL،SQLSERVER و Oracle می‌باشد:
 private string _MySQLProvider = "MySql.Data.MySqlClient";
 private string _SQLProvider="System.Data.SqlClient";
 private string _OracleProvider ="System.Data.OracleClient";
Provider‌های بیان شده، جهت استفاده DBFactory برای تشخیص نوع Database می‌باشد، تا بتواند آبجکت‌های مربوط به دیتابیس را ایجاد و در اختیار برنامه نویس قرار دهد. در این مثال ارتباط با دیتابیس SQLSERVER را امتحان می‌کنیم. بنابراین خواهیم داشت:
_DbProviderFactory = DbProviderFactories.GetFactory("System.Data.SqlClient");

در کد بالا، Provider، دیتابیس SQLSERVER به DbProviderFactory به عنوان ورودی داده شده است، بنابراین آبجکتهای مربوط به دیتابیس SQL Server ایجاد و در اختیار شما قرار می‌گیرد.

اگر به نام فضای نامی System.Data.Common توجه نمایید،از کلمه Common استفاده شده است و منظور این است که تمامی کلاسهایی را که این فضای نامی ارائه می‌دهد، در هر دیتابیسی قابل استفاده می‌باشد. برای تشخیص، کلاسهای مربوط به این فضای نامی نیز در ابتدای نام آنها از دو حرف DB استفاده شده است. تمامی کلاسهای زیر در فضای نامی System.Data.Common قابل ارائه و استفاده می‌باشد:
DbCommand 
DbCommandBuilder 
DbConnection 
DbDataAdapter 
DbDataReader 
DbException 
DbParameter 
DbTransaction

جهت اطلاع: ممکن است سئوالی در ذهن شما ایجاد شود که دات نت چگونه براساس نام Provider نوع دیتابیس را تشخیص می‌دهد؟
جواب: زمانی که دیتابیس‌های مختلف روی سیستم شما نصب می‌شود، Provider‌های مربوط به هر دیتابیس درون فایل Machine.config که مربوط به دات نت میباشد، درج می‌شود. و دات نت براساس اطلاعات مربوط به همین فایل آبجکت‌های دیتابیس را ایجاد می‌نماید.

امیدوارم مطلب فوق مفید واقع شود.
مطالب
ساخت تم سفارشی در انگیولار متریال ۲ - بخش اول

در  قسمت قبل  بیان شد همراه با نصب Angular Material، تعدادی تم از قبل ساخته شده نیز نصب خواهند شد که شامل یکسری استایل با رنگهای مشخصی هستند. این تم‌ها عبارتند از:

  • indigo-pink
  • deeppurple-amber
  • purple-green
  • pink-bluegrey 

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


مقدمه

تم در انگیولار متریال، از ترکیب چند پالت رنگی، ساخته می‌‌شود. پالت‌های رنگ را در طراحی متریال ( Material Design ) در  اینجا می‌توانید مشاهده کنید. انگیولار متریال رنگهای مورد استفاده خود را در گروه‌های زیر دسته بندی کرده است. 

  • Primary : این پالت رنگی به صورت گسترده در بخشهای مختلف صفحه و کامپوننت‌ها مورد استفاده قرار می‌گیرد.
  • Accent : این پالت رنگی برای دکمه‌های شناور و همچنین المنتهای تعاملی مورد استفاده قرار می‌گیرد.
  • Warn : این پالت رنگی برای مشخص کردن حالت‌های خطا، مورد استفاده قرار می‌گیرد.
  • Foreground : این پالت رنگی برای متون و آیکونها مورد استفاده قرار می‌گیرد.
  • Background : این پالت رنگی برای المنت‌های پس زمینه مورد استفاده قرار می‌گیرد.

در انگیولار متریال تمامی تم‌ها در زمان build به صورت استاتیک تولید می‌شوند. این قابلیت با خارج کردن چرخه تولید تم از چرخه راه‌اندازی برنامه، باعث بهبود در راه‌اندازی خواهد شد. 


تعریف تم سفارشی

برای ساخت تم سفارشی نیاز به یک فایل Sass خواهیم داشت. پس در مسیر /src یک فایل Sass را  با نام my-custom-theme.scss ایجاد می‌کنیم (شما می‌توانید از هر نام دیگری برای فایل Sass استفاده کنید). اگر از AngularCLI برای برنامه‌های خود استفاده می‌کنید، بایستی فایل Sass ایجاد شده را به لیست استایل‌ها در فایل angular-cli.json اضافه کنید. این کار باعث می‌شود AngularCLI این فایل Sass را در زمان build به css کامپایل کند. 

نکته: استفاده از فایل Sass برای ساختن تم سفارشی به این معنی نیست که شما از Sass برای سایر Style های برنامه خود استفاده کنید.

"styles": [
  "styles.css",
  "my-custom-theme.scss"
],

اگر از AngularCLI استفاده نمی‌کنید، شما نیاز به ابزاری برای کامپایل فایل Sass به css خواهید داشت.  ابزارهای بسیاری در این زمینه وجود دارند از جمله: gulp-sass و grunt-sass . ولی ساده‌ترین ابزار برای این کار node-sass می‌باشد. کافی است بعد از نصب، دستور زیر را اجرا کنید تا فایل sass به css کامپایل شود. فایل css تولید شده را مستقیما در صفحه index.html خود می‌توانید استفاده کنید.

node-sass src/my-custom-theme.scss dist/my-custom-theme.css

در فایل تم ایجاد شده ( my-custom-theme.scss ) ابتدا بایستی فایل Sass اصلی انگیولار متریال را وارد کنید.

@import '~@angular/material/theming';

در قدم بعدی mixin تعریف شده با نام mat-core  را در فایل Sass  انگیولار متریال، وارد می‌کنیم. این mixin شامل تمامی Styleهای مشترکی است که توسط کامپوننت‌های مختلف استفاده می‌شود. 

@include mat-core();

نکته: مطمئن شوید فقط یک بار این mixin را در سرتاسر برنامه خود وارد کرده باشید. در غیر این صورت، فایل css تولید شده شامل یکسری Style تکراری خواهد بود و این باعث بزرگ و حجیم شدن فایل css نهایی خواهد شد. 


تا اینجا فایل تم ایجاد شده اینگونه خواهد بود:  

@import '~@angular/material/theming';
@include mat-core();

حالا نوبت تعریف تم سفارشی است. ولی قبل از آن باید با سیستم رنگها در طراحی متریال ( Material Design ) آشنایی داشته باشیم. در طراحی متریال ۱۹ پالت رنگی با نام‌های مختلف وجود دارند. برای ۱۶ پالت رنگی، ۱۴ طیف رنگی و برای ۳ پالت رنگی دیگر، ۱۰ طیف رنگی در نظر گرفته شده است. هر کدام از این طیف‌های رنگی، دارای یک مقدار عددی است. یعنی یک رنگ در سیستم طراحی متریال متشکل از یک نام رنگ و یک شماره طیف رنگ است که مقدار پیش فرض طیف رنگ، عدد ۵۰۰ می‌باشد. 


حالا با استفاده از تابع mat-palette تعریف شده در فایل Sass انگیولار متریال، سه متغیر را برای رنگهای Primary ، Accent و Warn در فایل my-custom-theme.scss ، به شکل زیر تعریف می‌کنیم. 

$my-app-primary: mat-palette($mat-indigo);
$my-app-accent:  mat-palette($mat-pink, 500, A100, A400);
$my-app-warn:    mat-palette($mat-deep-orange);

تابع mat-palette در فایل Sass اصلی انگیولار متریال، به شکل زیر تعریف شده است. 

@function mat-palette($base-palette, $default: 500, $lighter: 100, $darker: 700)

این تابع یک پارامتر اجباری دارد و بقیه پارامترها اختیاری هستند.

  • base-palette $: نام رنگ را دریافت می‌کند. این پارامتر اجباری است و باید مشخص شود. 
  • default$: با این پارامتر، طیف پیش‌فرض رنگ انتخاب شده را مشخص می‌کنیم. این پارامتر اختیاری است و مقدار پیش فرض آن 500 است.
  • lighter$: با این پارامتر، طیف روشن رنگ انتخاب شده را مشخص می‌کنیم. این پارامتر اختیاری است و مقدار پیش فرض آن 100 است.
  • darker$: با این پارامتر، طیف تیره رنگ انتخاب شده را مشخص می‌کنیم. این پارامتر اختیاری است و مقدار پیش فرض آن 700 است.

در قدم آخر با استفاده از تابع mat-light-theme یا mat-dark-theme، رنگهای تعریف شده در مرحله قبل را ترکیب کرده و نتیجه را به عنوان ورودی به mixin به نام angular-material-theme  ارسال و بارگذاری می‌کنیم. 

تابع mat-light-theme و mat-dark-theme سه پارامتر را دریافت می‌کند. پارارمتر اول پالت رنگ ایجاد شده توسط تابع mat-palette برای گروه Primary ، پارامتر دوم پالت رنگ ایجاد شده برای گروه Accent و پارامتر سوم پالت رنگ ایجاد شده برای گروه Warn را دریافت می‌کند. دو پارامتر اول اجباری و پارامتر سوم اختیاری با مقدار پیش فرض mat-palette($mat-red) می‌باشد. 

شکل کلی فایل Sass در نهایت به شکل زیر خواهد بود. 

@import '~@angular/material/theming';
@include mat-core();
$my-app-primary: mat-palette($mat-teal);
$my-app-accent:  mat-palette($mat-amber, 500, A100, A400);
$my-app-warn:    mat-palette($mat-deep-orange);

$my-app-theme: mat-light-theme($my-app-primary, $my-app-accent, $my-app-warn);

@include angular-material-theme($my-app-theme);

برای استفاده از پالت رنگ‌های ایجاد شده، از خصوصیت color در المنت‌های انگولار متریال استفاده می‌کنیم. برای نمونه بعد از تغییر فایل Sass به شکل بالا و حذف لینک تم از پیش ساخته شده که در پست قبلی به Style.cs اضافه کرده بودیم، می‌توانیم کار خود را به صورت زیر آزمایش کنیم. در فایل app.component.html در تگ main کدهای زیر را اضافه کنید. 

<md-card>
  <button md-raised-button color="primary">
    Primary
  </button>
  <button md-raised-button color="accent">
    Accent
  </button>
  <button md-raised-button color="warn">
    Warning
  </button>
</md-card>

خروجی زیر را مشاهده خواهید کرد. 

همچنین می‌توانید به جای استفاده از تابع mat-light-theme از تابع mat-dark-theme استفاده کنید. دراین صورت خروجی زیر را خواهید دید. 

در بخش بعدی نحوه ساخت چند تم دیگر را در کنار تم اصلی، ساخت تم به ازای هر کامپوننت و نحوه تعویض تم از طریق کد را دنبال خواهیم کرد. 

کدهای این قسمت را از اینجا دریافت کنید:  ساخت-تم-سفارشی-در-انگولار-متریال-۲---بخش-اول.rar 

نظرات مطالب
طراحی جدول فایل‌های پیوستی پایگاه داده
در اکثر موراد مطرح شده فوق ، فایل‌های آپلود شده وابسته بوند به یک رکورد که ابتدا می‌بایست رکورد مورد نظر درج تا بتوان فایل را با آن کلید آپلود و ذخیره نمود .
ولی در توضیح آقای ربال ، فرض کنید همین ادیتور سایت فعلی ، شما قصد نوشتن یک مقاله را دارید و لابه لای متون نیاز به قراردادن عکس هم دارید ، در این حالت سایت فعلی عکس مورد نظر ذخیره نموده و فقط آدرس آن برگشت داده میشود و داخل تگ src قرار داده می‌شود تا فایل نمایش داده شود . در این حالت فقط مشخص می‌شود که کاربر x فایل y  را آپلود کرده است .
نظرات مطالب
نمایش خطاهای اعتبارسنجی سمت کاربر ASP.NET MVC به شکل Tooltip به کمک Twitter bootstrap
- «... محل قرار گیری صحیح ارجاعات ... »
هرجایی که کار کند «صحیح» است و مرورگر آن‌را درک و پردازش کرده‌است. اما «بهتر» است آن‌ها را قبل از بسته شدن تگ body قرار داد تا بارگذاری آن‌ها سبب ایجاد وقفه در نمایش صفحه و بروز یک فلش سفید نشود. البته برای رفع این مشکل هم async scripts ارائه شده‌است.
- «... زمانی که فایل‌های ارجاع به js رو بعد از فوتر قرار می‌دهم این ویژگی غیر فعال است ...»
تقدم و تاخرها را رعایت نکردید. اسکریپت‌ها را باید به ترتیب و با درنظر گرفتن پیشنیازها در قسمت خاصی از صفحه اضافه کرد (از دیدگاه اجرایی برای مرورگر مهم نیست که کجا باشند).
نظرات مطالب
نحوه استفاده از ViewModel در ASP.NET MVC
سلام؛ وقتی رو صفحه اصلی سایت کاربر روی ادامه مطلب کلیک میکنه و وارد صفحه مربوط به اون مطلب میشه، صفحه جدید از یک پارشال ویوو تشکیل شده که دارای یک تگ فرم هست برای ارسال نظرات کاربران و هم چنین یک پارشال ویوو دیگر برای نمایش مطلب کامل اون لینک میباشد. برای استفاده هردو مدل یک view model تعریف شده که شامل هر دو موجودیت‌ها است. وقتی توی ویوو اصلی دکمه ادامه مطلب زده میشه این ارور داده میشه:

The model item passed into the dictionary is of type 'Class.Domain.Enities.Product', but this dictionary requires a model item of type 'WebAli.ViewModel.ProductCommentListViewModel'. 

پاسخ به بازخورد‌های پروژه‌ها
نمایش چندی خطی یک فیلد
به نظر در نگارش‌های اخیر iTextSharp حروف یونیکد نامرئی را حذف می‌کنند و اعمال نمی‌شود. به همین جهت متد یاد شده تاثیری نداشته. باید این مساله را در mailing list آن‌ها ارسال کنید. یا در استک اور فلو در تگ iTextSharp ارسالش کنید (هر دو حالت توسط تیم iText خوانده می‌شود)
اگر مطلبی را هم خواستید ارسال کنید سعی کنید عمومی باشد. مثلا عنوان کنید این رشته را می‌خواهم راست به چپ نمایش دهم به همراه اضافه کردن یک سری حروف یونیکد خاص. iTextSharp این حروف را حذف می‌کند و اعمال نمی‌کند.
(جهت اطلاع من یکبار این‌کار را در mailing list آن‌ها انجام دادم و پاسخی نگرفتم ...) 
مطالب
راه اندازی 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
    }