// Pure JavaScript errors handler window.addEventListener('error', function (err) { var lineAndColumnInfo = err.colno ? ' line:' + err.lineno +', column:'+ err.colno : ' line:' + e.lineno; _gaq.push([ '_trackEvent', 'JavaScript Error', err.message, err.filename + lineAndColumnInfo + ' -> ' + navigator.userAgent, 0, true ]); });
معرفی جیسان، JSON
موتور شبیه سازی فیزیک در محیط 2 بعدی
ASP.NET MVC #5
اگر بخواهیم از داخل کنترلرمون مقادیریمون را در قالب alert تو view نمایش بدیم باید چکار کرد؟
من خودم به این شکل عمل کردم
<script language="javascript" type="text/javascript"> alert(' @ViewData["ErrorMessage"]'); </script>
اصلا بهتر نیست از partialview استفاده کنم که یه view برای alert کلا داشته باشم؟
مرسی
- Observable state: در MobX نیز همانند Redux، کل شیء state به صورت یک شیء جاوا اسکریپتی ارائه میشود؛ با این تفاوت که در اینجا این شیء، یک Observable است که نمونهای از مفهوم آنرا در مثال قسمت قبل بررسی کردیم.
- Actions: متدهایی هستند که state را تغییر میدهند.
- Computed properties: در مورد مفهوم خواص محاسباتی در قسمت قبل بحث کردیم. این خواص، مقدار خود را بر اساس تغییرات سایر خواص Observable، به روز میکنند.
- Reactions: سبب بروز اثرات جانبی (side effects) میشوند؛ مانند تعامل با دنیای خارج. نمونهای از آن، متد autorun است که تغییرات Observableها را ردیابی میکند.
برای مثال خاصیت محاسباتی fullName، تغییرات سایر خواص Observable را احساس کرده و مقدار خودش را به روز میکند. سپس یک Reaction به آن، میتواند به روز رسانی DOM، جهت نمایش این تغییرات باشد و یا نمونهی دیگری که میتواند بسیاری از این مفاهیم را نمایش دهد، کلاس زیر است:
import { action, observable, computed } from 'mobx'; class PizzaCalculator { @observable numberOfPeople = 0; @observable slicesPerPerson = 2; @observable slicesPerPie = 8; @computed get slicesNeeded() { console.log('Getting slices needed'); return this.numberOfPeople * this.slicesPerPerson; } @computed get piesNeeded() { console.log('Getting pies needed'); return Math.ceil(this.slicesNeeded / this.slicesPerPie); } @action addGuest() { this.numberOfPeople!++; } }
- برای مثال زمانیکه تعریف observable numberOfPeople@ را داریم، به این معنا است که میخواهیم تغییرات تعداد افراد را تحت نظر قرار دهیم و اگر تغییری در مقدار آن صورت گرفت، آنگاه مقدار خواص محاسباتی که با computed@ مزین شدهاند، به صورت خودکار به روز رسانی شوند.
- action@ به این معنا است که متدی در اینجا، سبب بروز تغییری در state کلاس جاری میشود. MobX به همراه یک strict mode است که اگر فعال باشد، ذکر تزئین کنندهی action@ بر روی یک چنین متدهایی ضروری است، در غیراینصورت، الزامی به درج آن نیست.
در این قطعه کد تعدای console.log را هم ملاحظه میکنید. علت آن نمایش مفهوم کش کردن اطلاعات در MobX است. فرض کنید برای بار اول، مقدار یکی از خواصی را که به صورت observable تعریف شدهاند، تغییر میدهیم. در این حالت تمام خواص محاسباتی وابستهی به آنها، به صورت خودکار مجددا محاسبه شده و console.logها را نیز مشاهده خواهیم کرد. اگر برای بار دوم همین فراخوانی صورت گیرد و تغییری در مقادیر خواص observable صورت نگیرد، MobX از نگارش کش شدهی این خواص محاسباتی استفاده میکند و بیجهت سبب رندر مجدد UI نخواهد شد که در نهایت کارآیی بالایی را سبب خواهد شد. برای پیاده سازی یک چنین قابلیتی با Redux باید از مفهومی مانند React.memo و Memoization و کتابخانههای کمکی مانند Reselect استفاده کرد؛ اما در اینجا به صورت توکار و خودکار اعمال میشود.
ساختارهای دادهای که توسط MobX پشتیبانی میشوند
MobX از اکثر ساختارهای دادهای متداول در جاوا اسکریپت پشتیبانی میکند؛ برای مثال:
- اشیاء مانند ({})observable
- آرایهها مانند ([])observable
- Maps مانند observable(new Map())
چند نکته:
- همانطور که در قسمت قبل نیز ذکر شد، decorators در اصل یکسری تابع هستند و برای مثال میتوان observable را به صورت observable@ و یا به صورت یک تابع معمولی مورد استفاده قرار داد.
- اگر شیءای را به صورت ({})observable معرفی کنیم، با افزودن خواصی به آن پس از این فراخوانی، این خواص دیگر مورد ردیابی قرار نخواهند گرفت. علت آنرا هم در شبهکد زیر میتوان مشاهده کرد:
const extendObservable = (target, source) => { source.keys().forEach(key => { const wrappedInObservable = observable(source[key]); Object.defineProperty(target, key, { set: value.set. get: value.get }); }); };
برای رفع این مشکل میتوان از Map استفاده کرد. یعنی در اینجا اگر قرار است تعداد خواص اشیاء را به صورت پویا تغییر دهید، آنها را به صورت Map تعریف کنید؛ چون متد set آن توسط observableها ردیابی میشود.
استفاده از MobX با React توسط کتابخانهی mobx-react
تا اینجا MobX را به صورت متکی به خود مورد بررسی قرار دادیم. اکنون قصد داریم آنرا به یک برنامهی React متصل کنیم. برای اینکار کتابخانههای زیادی وجود دارند که در این قسمت کلیات روش کار با کتابخانهی mobx-react را در بین آنها بررسی میکنیم.
نصب کتابخانهی mobx-react
ابتدا نیاز است تا این کتابخانه را نصب کنیم:
> npm install --save mobx mobx-react
تحت نظر قرار دادن کامپوننتها
در ادامه پس از نصب کتابخانهی mobx-react، نیاز است کامپوننتها را تحت نظر MobX قرار دهیم که اینکار را میتوان توسط تزئین کنندهی observer آن انجام داد. همانطور که عنوان شد، تزئین کنندهها را میتوان به صورت معمولی observer@ به یک کلاس و یا به صورت فراخوانی تابع، برای مثال به یک کامپوننت تابعی اعمال کرد. برای نمونه کامپوننتهای کلاسی را به نحو زیر میتوان با observer@ مزین کرد:
import { observer } from "mobx-react"; @observer class Counter extends Component {
و یا کامپوننتهای تابعی را میتوان توسط متد observer به صورت زیر محصور کرد:
const Counter = observer(({ count }) => { return ( // ... ); });
class ContainerComponent extends Component () { componentDidMount() { this.stopListening = autorun(() => this.render()); } componentWillUnmount() { this.stopListening(); } render() { … } }
تعریف مخزن و اتصال آن به کامپوننتها
کار شیء Provider که بالاترین کامپوننت را در سلسله مراتب کامپوننتها محصور میکند، ارائهی store، به تمام کامپوننتهای فرزند است. در Redux فقط یک store را داریم که به شیء Provider آن ارسال میکنیم. اما در حین کار با MobX چنین محدودیتی وجود ندارد و میتوان چندین store را تعریف کرد و در اختیار برنامه قرار داد که شبهکد نحوهی تعریف آن به صورت زیر است:
import { Provider } from 'mobx-react'; import ItemStore from './store/ItemStore'; import Application from './components/Application'; const itemStore = new ItemStore(); ReactDOM.render( <Provider itemStore={itemStore}> <Application /> </Provider>, document.getElementById('root'), );
@inject('itemStore') class NewItem extends Component { // ...
const UnpackedItems = inject('itemStore')( observer(({ itemStore }) => ( // ... )), );
یک مثال: پیاده سازی مثال شمارشگر قسمت سوم این سری با mobx-react
در ادامه قصد داریم برنامهی شمارشگر ارائه شده در قسمت سوم بررسی redux را با mobx پیاده سازی کنیم. به همین جهت یک پروژهی جدید React را ایجاد میکنیم:
> create-react-app state-management-with-mobx-part2 > cd state-management-with-mobx-part2 > npm start
> npm install --save mobx mobx-react bootstrap
import "bootstrap/dist/css/bootstrap.css";
پس از آن فایل src\index.js را به صورت زیر تغییر میدهیم:
import "./index.css"; import "bootstrap/dist/css/bootstrap.css"; import { autorun, decorate, observable } from "mobx"; import React from "react"; import ReactDOM from "react-dom"; import Counter from "./components/Counter"; import * as serviceWorker from "./serviceWorker"; class Count { value = 0; increment = () => { this.value++; }; decrement = () => { this.value--; }; } decorate(Count, { value: observable }); const count = (window.count = new Count()); autorun(() => console.log("The count changed!", count.value)); ReactDOM.render( <main className="container"> <Counter count={count} /> </main>, document.getElementById("root") ); serviceWorker.unregister();
- در قسمت قبل، روش تحت نظر قرار دادن یک شیء متداول جاوا اسکریپتی را توسط متد observable مشاهده کردیم. در اینجا نگارش کلاسی آن مثال را بر اساس کلاس Count مشاهده میکنید. اگر نخواهیم از decorator ای مانند observable@ بر روی خاصیت value این کلاس استفاده کنیم، روش تابعی آنرا با فراخوانی متد decorate و ذکر نوع کلاس و سپس خاصیتی که باید به صورت observable تحت نظر قرار گیرد، در اینجا مشاهده میکنید. این هم یک روش کار با mobx است.
- پس از ایجاد کلاس Count که در اینجا نقش store را نیز بازی میکند، یک وهلهی جدید را از آن ساخته و به متغیر count در این ماژول و همچنین window.count انتساب میدهیم. انتساب window.count سبب میشود تا بتوان در کنسول توسعه دهندگان مرورگر، با نوشتن count و سپس enter، به محتویات این متغیر دسترسی یافت و یا حتی آنرا تغییر داد؛ مانند تصویر زیر که بلافاصله این تغییر، در UI برنامه نیز منعکس میشود:
- در اینجا تعریف شیء Provider را که پیشتر در مورد آن بحث کردیم، مشاهده نمیکنید؛ چون با تک کامپوننت Counter تعریف شدهی در این مثال، نیازی به آن نیست. میتوان این شیء store را به صورت مستقیم به props کامپوننت Counter ارسال کرد.
اکنون تعریف کامپوننت شمارشگر واقع در فایل src\components\Counter.jsx به صورت زیر خواهد بود که این کامپوننت، count را به صورت props دریافت میکند:
import { observer } from "mobx-react"; import React from "react"; const Counter = observer(({ count }) => { return ( <section className="card mt-5"> <div className="card-body text-center"> <span className="badge m-2 badge-primary">{count.value}</span> </div> <div className="card-footer"> <div className="d-flex justify-content-center align-items-center"> <button className="btn btn-secondary btn-sm" onClick={count.increment} > + </button> <button className="btn btn-secondary btn-sm m-2" onClick={count.decrement} > - </button> </div> </div> </section> ); }); export default Counter;
تا زمانیکه کامپوننت، با تابع observer محصور شدهاست، به props رسیده گوش فرا داده و خواص و اشیاء observable آنرا تشخیص میدهد و سبب رندر مجدد کامپوننت، با تغییری در آنها خواهد شد.
کدهای کامل این قسمت را میتوانید از اینجا دریافت کنید: state-management-with-mobx-part2.zip
روش اول: استفادهی دستی از اعتبارسنج کتابخانهی Fluent Validation
روشهای زیادی برای استفادهی از قواعد تعریف شدهی توسط کتابخانهی Fluent Validation وجود دارند. اولین روش، فراخوانی دستی اعتبارسنج، در مکانهای مورد نیاز است. برای اینکار در ابتدا نیاز است با اجرای دستور «dotnet add package FluentValidation.AspNetCore»، این کتابخانه را در پروژهی وب خود نیز نصب کنیم تا بتوانیم از کلاسها و متدهای آن استفاده نمائیم. پس از آن، روش دستی کار با کلاس RegisterModelValidator که در قسمت قبل آنرا تعریف کردیم، به صورت زیر است:
using FluentValidationSample.Models; using Microsoft.AspNetCore.Mvc; namespace FluentValidationSample.Web.Controllers { public class HomeController : Controller { public IActionResult Index() { return View(); } [HttpPost] public IActionResult RegisterValidateManually(RegisterModel model) { var validator = new RegisterModelValidator(); var validationResult = validator.Validate(model); if (!validationResult.IsValid) { return BadRequest(validationResult.Errors[0].ErrorMessage); } // TODO: Save the model return Ok(); } } }
یک نکته: متد الحاقی AddToModelState که در فضای نام FluentValidation.AspNetCore قرار دارد، امکان تبدیل نتیجهی اعتبارسنجی حاصل را به ModelState استاندارد ASP.NET Core نیز میسر میکند:
public IActionResult RegisterValidateManually(RegisterModel model) { var validator = new RegisterModelValidator(); var validationResult = validator.Validate(model); if (!validationResult.IsValid) { validationResult.AddToModelState(ModelState, null); return BadRequest(ModelState); } // TODO: Save the model return Ok(); }
روش دوم: تزریق اعتبارسنج تعریف شده در سازندهی کنترلر
بجای وهله سازی دستی RegisterModelValidator و ایجاد وابستگی مستقیمی به آن، میتوان از روش تزریق وابستگیهای آن نیز استفاده کرد. در این حالت اعتبارسنج RegisterModelValidator با طول عمر Transient به سیستم تزریق وابستگیها معرفی شده:
namespace FluentValidationSample.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient<IValidator<RegisterModel>, RegisterModelValidator>(); services.AddControllersWithViews(); }
namespace FluentValidationSample.Web.Controllers { public class HomeController : Controller { private readonly IValidator<RegisterModel> _registerModelValidator; public HomeController(IValidator<RegisterModel> registerModelValidator) { _registerModelValidator = registerModelValidator; } [HttpPost] public IActionResult RegisterValidatorInjection(RegisterModel model) { var validationResult = _registerModelValidator.Validate(model); if (!validationResult.IsValid) { return BadRequest(validationResult.Errors[0].ErrorMessage); } // TODO: Save the model return Ok(); } } }
روش سوم: خودکار سازی اجرای یک تک اعتبارسنج تعریف شده
اگر متد الحاقی AddFluentValidation را به صورت زیر به سیستم معرفی کنیم:
namespace FluentValidationSample.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddTransient<IValidator<RegisterModel>, RegisterModelValidator>(); services.AddControllersWithViews().AddFluentValidation(); }
namespace FluentValidationSample.Web.Controllers { public class HomeController : Controller { [HttpPost] public IActionResult RegisterValidatorAutomatically(RegisterModel model) { if (!ModelState.IsValid) { // re-render the view when validation failed. return View(model); } // TODO: Save the model return Ok(); } } }
نکته 1: تنظیمات فوق برایASP.NET Web Pages و PageModels نیز یکی است. فقط با این تفاوت که اعتبارسنجها را فقط میتوان به مدلهایی که به صورت خواص یک page model تعریف شدهاند، اعمال کرد و نه به کل page model.
نکته 2: اگر کنترلر شما به ویژگی [ApiController] مزین شده باشد:
namespace FluentValidationSample.Web.Controllers { [Route("[controller]")] [ApiController] public class HomeController : Controller { [HttpPost] public IActionResult RegisterValidatorAutomatically(RegisterModel model) { // TODO: Save the model return Ok(); } } }
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "One or more validation errors occurred.", "status": 400, "traceId": "|84df05e2-41e0d4841bb61293.", "errors": { "FirstName": [ "'First Name' must not be empty." ] } }
public void ConfigureServices(IServiceCollection services) { // ... // override modelstate services.Configure<ApiBehaviorOptions>(options => { options.InvalidModelStateResponseFactory = context => { var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => p.ErrorMessage)).ToList(); return new BadRequestObjectResult(new { Code = "00009", Message = "Validation errors", Errors = errors }); }; }); }
روش چهارم: خودکار سازی ثبت و اجرای تمام اعتبارسنجهای تعریف شده
و در آخر بجای معرفی دستی تک تک اعتبارسنجهای تعریف شده به سیستم تزریق وابستگیها، میتوان تمام آنها را با فراخوانی متد RegisterValidatorsFromAssemblyContaining، به صورت خودکار از یک اسمبلی خاص استخراج نمود و با طول عمر Transient، به سیستم معرفی کرد. در این حالت متد ConfigureServices به صورت زیر خلاصه میشود:
namespace FluentValidationSample.Web { public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews().AddFluentValidation( fv => fv.RegisterValidatorsFromAssemblyContaining<RegisterModelValidator>() ); }
سازگاری اجرای خودکار FluentValidation با اعتبارسنجهای استاندارد ASP.NET Core
به صورت پیشفرض، زمانیکه FluentValidation اجرا میشود، اگر اعتبارسنج دیگری نیز در سیستم تعریف شده باشد، اجرا خواهد شد. به این معنا که برای مثال میتوان FluentValidation و DataAnnotations attributes و IValidatableObjectها را با هم ترکیب کرد.
اگر میخواهید این قابلیت را غیرفعال کنید و فقط سبب اجرای خودکار FluentValidationها شوید، نیاز است تنظیم زیر را انجام دهید:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews().AddFluentValidation( fv => { fv.RegisterValidatorsFromAssemblyContaining<RegisterModelValidator>(); fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false; } ); }
در طول این سری آموزشهای MDX (البته هنوز نمیدانم چند قسمت خواهد بود) تلاش خواهم کرد تمامی موارد موجود در MDXها را به طور کامل با شرح و توضیح مناسب پوشش دهم.
امیدوارم شما دوستان عزیز پس از مطالعهی این مجموعه مقالات به دانش کافی در خصوص MDX Queryها دست پیدا کنید.
در قسمت اول این آموزشها در نظر دارم در ابتدا مفاهیم اولیه OLAP و همچنین مفاهیم مورد نیاز در Multi Dimentional Data Base ها برای شما عزیزان توضیح دهم و در قسمتهای بعدی این مجموعه در خصوص MDX Queryها صحبت خواهم کرد.
انباره داده (Data Warehouse)
عملا یک یا چند پایگاه داده میباشد که اطلاعات تجمیع شده از دیگر پایگاههای داده را درخود نگه داری میکند. برای ارایه گزارشاتی که از پایگاه دادههای OLTP نمیتوانیم به راحتی بگیریم.
(OLTP (Online transaction processing
سیستم پردازش تراکنش برخط میباشند . که عملا همان سیستم هایی میباشند که در طول روز دارای تغییرات بسیار زیادی میباشند (مانند سیستمهای حسابداری، انبار داری و ... که در طول روز دایما دارای تغییرات در سطح داده میباشند.)
(OLAP (OnLine Analysis Processing
این سیستمها خدماتی در نقش تحلیلگر داده و تصمیم گیرنده ارائه میکند. چنین سیستمهایی میتوانند، داده را در قالبهای مختلف برای هماهنگ کردن نیازهای مختلف کاربران مختلف، سازماندهی کنند.
تفاوت انبار داده (Data Warehouse) و پایگاه داده(Data Base)
وظیفه اصلی سیستمهای پایگاهداده کاربردی OnLine ،پشتیبانی از تراکنشهای برخط و پردازش کوئری است. این سیستمها، سیستم پردازش تراکنش برخط(OLTP) نامیده میشوند و بیشتر عملیات روزمره یک سازمان را پوشش میدهند. از سوی دیگر انبارداده، خدماتی در نقش تحلیلگر داده و تصمیم گیرنده ارائه میکند. چنین سیستمهایی میتوانند داده را در قالبهای مختلف برای هماهنگ کردن نیازهای مختلف کاربران مختلف، سازماندهی و ارائه میکند. این سیستمها با نام سیستمهای پردازش تحلیلی برخط (OLAP) شناختهمیشوند.
موارد تفاوت انبار داده (Data Warehouse) و پایگاه داده(Data Base)
• از لحاظ مدلهای داده: پایگاههای داده برای مدل OLTP بهینه سازی شدهاست. که بر اساس مدل داده رابطهای امکان پردازش تعداد زیادی تراکنش همروند، که اغلب حاوی رکوردهای اندکی هستند را دارد. اما در انبارهای داده که برای پردازش تحلیلی بر خط، طراحی شدهاند امکان پردازش تعداد کمی کوئری پیچیده بر روی تعداد بسیار زیادی رکورد داده فراهم میشود. سرورهای OLAP میتوانند از دو نوع رابطهای (ROLAP) یا چندبعدی باشند (MOLAP).
• از لحاظ کاربران: کاربران پایگاهداده کارمندان دفتری و مسؤولان هستند در حالیکه کاربران انبارداده مدیران و تصمیمگیرندهها هستند.
• از لحاظ عملیات قابل اجرا بر روی آنها: عملیات انجام شده برروی پایگاههای داده عمدتا عملیات (Select/Insert/Update/Delete) میباشد ، در حالی که عملیات روی انبار داده عمدتا Select ها میباشند.
• از لحاظ مقدار دادهها: مقدار دادههای یک پایگاهداده در حدود چند مگابایت تا چند گیگابایت است در حالی که این مقدار در انبار داده در حدود چند گیگابایت تا چند ترابایت است.
• از لحاظ زمان پرس و جو : به طور کلی سرعت پرس و جو ها روی انبارهی داده بسیار بالاتر از کوئری مشابه آن روی پایگاه داده میباشد.
• پاکسازی داده (Data Cleansing)
پاکسازی دادهها عبارت است از شناسایی و حذف خطاها و ناسازگاریهای داده ای به منظور دستیابی به دادههایی با کیفیت بالاتر.
اگر دادهها از منابع یکسان مثل فایلها یا پایگاههای داده ای گرفته شوند خطاهایی از قبیل اشتباهات تایپی، دادههای نادرست و فیلدهای بدون مقدار را خواهیم داشت و چنانچه دادهها از منابع مختلف مثل پایگاه دادههای مختلف یا سیستم اطلاعاتی مبتنی بر وب گرفته شوند .با توجه به نمایشهای دادهای مختلف خطاها بیشتر بوده و پاکسازی دادهها اهمیت بیشتری پیدا خواهد کرد. برای دستیابی به دادههای دقیق و سازگار، بایستی دادهها را یکپارچه نموده و تکرارهای آنها را حذف نمود.
وجود خطاهای نویزی، ناسازگاری در دادههای انبار داده و ناقص بودن دادهها امری طبیعی است. فیلدهای یک جدول ممکن است خالی باشند و یا دارای دادههای خطا دار و ناسازگار باشند. برای هر کدام از این حالتها روشهایی جهت پاکسازی و اصلاح دادهها ارایه میشود.
در این بخش عملیات مختلفی برای پاکسازی دادهها قابل انجام است:
• نادیده گرفتن تاپلهای نادرست
• پرکردن فیلدهای نادرست به صورت دستی
• پرکردن فیلدهای نادرست با یک مقدار مشخص
• پرکردن فیلدها با توجه به نوع فیلد و دادهها ی موجود
• پرکردن فیلدها با نزدیکترین مقدار ممکن (مثلا میانگین فیلد تاپلهای دیگر میتواند به عنوان یک مقدار مناسب در نظر گرفته شود)
• یکپارچهسازی (Integration)
• تبدیل دادهها(Data Transformation)• شناسایی فیلدهای یکسان: فیلدهای یکسان که در جدولها ی مختلف دارای نامهای مختلف میباشند.
• شناسایی افزونگیها ی موجود در دادهها ی ورودی: دادههای ورودی گاهی دارای افزونگی است. مثلا بخشی از رکورد در جداول مختلف وجود دارد.
• مشخص کردن برخوردهای داده ای: مثالی از برخوردهای داده ای یکسان نبودن واحدهای نمایش داده ای است. مثلا فیلد وزن در یک جدول بر حسب کیلوگرم و در جدولی دیگر بر حسب گرم ذخیره شده است.
در این فاز، دادههای ورودی طی مراحل زیر به شکلی که مناسب عمل داده کاوی باشند، در میآیند:
• از بین بردن نویز داده¬ها(Smoothing)
• تجمیع داده¬ها(Aggregation)
• کلی¬سازی(Generalization)
• نرمال¬سازی(Normalization)
• افزودن فیلدهای جدید
• استفاده از مقادیر مجاور برای تعیین یک مقدار مناسب برای فیلدهای دارای نویز
• دسته بندی دادههای موجود و مقداردهی فیلد دارای داده نویزی با استفاده از دسته نزدیکتر
• ترکیب روشهای فوق با ملاحظات انسانی، در این روش، اصلاح مقادیر نویزی با استفاده از یکی از روشهای فوق انجام میگیرد اما افرادی برای بررسی و اصلاح نیز وجود دارند
4. نرمال سازی(Normalization): منظور از نرمال سازی، تغییر مقیاس دادهها است. به عنوان مثالی از نرمال سازی، میتوان به تغییر بازه یک فیلد از مقادیر موجود به بازه 0 تا 1 اشاره کرد.
5. افزودن فیلدهای جدید: گاهی اوقات برای سهولت عمل داده کاوی میتوان فیلدهایی به مجموعه فیلدهای موجود اضافه کرد. مثلا میتوان فیلد میانگین حقوق کارمندان یک شعبه را به مجموعه فیلدهای موجود اضافه نمود.
در این مرحله، عملیات کاهش دادهها انجام میگیرد که شامل تکنیکهایی برای نمایش کمینه اطلاعات موجود است
. این فاز از سه بخش تشکیل میشود:
• کاهش دامنه و بعد: فیلدهای نامربوط، نامناسب و تکراری حذف میشوند. برای تشخیص فیلدهای اضافی، روشهای آماری و تجربی وجود دارند ؛ یعنی با اعمال الگوریتمهای آماری و یا تجربی بر روی دادههای موجود در یک بازه زمانی مشخص، به این نتیجه میرسیم که فیلد یا فیلدهای خاصی کاربردی در انباره داده ای و داده کاوی نداشته و آنها را حذف میکنیم.
• فشرده سازی داده ها: از تکنیکهای فشرده سازی برای کاهش اندازه دادهها استفاده میشود.
• کدکردن داده ها: دادهها در صورت امکان با پارامترها و اطلاعات کوچکتر جایگزین میشوند.
مدل دادهای رابطهای (Relational) وچند بعدی (Multidimensional) :
1. مدل داده رابطهای (Relational data modeling) بر اساس دو مفهوم اساسی موجودیت (entity) و رابطه (relation) بنا نهاده شده است. از این رو آن را با نام مدل ER نیز میشناسند.
• موجودیت (entity) : نمایانگر همه چیزهایی که در پایگاه داده وجود خارجی دارند یا به تصور در میآیند. پدیدهها دارای مشخصاتی هستندکه به آنها صفت (attribute) گفته میشود.
• رابطه (relation) : پدیدهها را به هم میپیوندد و چگونگی در ارتباط قرار گرفتن آنها با یکدیگر را مشخص میکند.
2. مدل داده چندبعدی ( Multidimensional modeling ) یا MD بر پایه دو ساختار جدولی اصلی بنا نهاده شده است:
این ساختار امکان داشتن یک نگرش مدیریتی و تصمیمگیری به دادههای موجود در پایگاه داده را تسهیل میکند.
• جدول حقایق (Fact Table)
• جداول ابعاد (Dimension Table)
جدول حقایق : قلب حجم دادهای ما را تشکیل میدهد و شامل دو سری فیلد است : کلیدهای خارجی به ابعاد و شاخصها (Measure).
شاخصها (Measure) : معیارهایی هستند که بر روی آنها تحلیل انجام میگیرد و درون جدول حقایق قرار دارند. شاخصها قبل از شکلگیری انبار داده توسط مدیران و تحلیلگران به دقت مشخص میشوند. چون در مرحله کار با انبار اطلاعات اساسی هر تحلیل بر اساس همین شاخصها شکل میگیرد. شاخصها تقریباً همیشه مقادیر عددی را شامل میشوند. مثلا برای یک فروشگاه زنجیرهای این شاخصها میتوانند واحدهای فروختهشده کالاها و مبلغ فروش به تومان باشند.
بعد (Dimension) : هر موجودیت در این مدل میتواند با یک بعد تعریف شود. ولی بعدها با موجودیتهای مدل ER متفاوتند زیرا آنها سازمان شاخصها را تعیین میکنند. علاوه بر این دارای یک ساختار سلسله مراتبی هستند و به طور کلی برای حمایت از سیستمهای تصمیم گیری سازماندهی شدهاند.
اجزای بعدها member نام دارند و تقریباٌ همه بعدها، memberهای خود را در یک یا چند سطح سلسله مراتبی (hierarchies) سازماندهی مینمایند، که این سلسله مراتب نمایانگر مسیر تجمیع (integration) و ارتباط بین سطوح پایینتر (مثل روز) و سطوح بالاتر (مثل ماه و سال) است. وقتی یک دسته از memberهای خاص با هم مفهوم جدیدی را ایجاد میکنند، به آنها یک سطح (Level) میگوییم. ( مثلاٌ هر سی روز را ماه میگوییم. در این حالت ماه یک سطح است. )
حجمهای دادهای (Data Cube)
حجمهای دادهای یا Cube از ارتباط تعدادی بعد با تعدادی شاخص تعریف میشود. ترکیب memberهای هر بعد از حجم دادهای فضای منطقی را تعریف میکند که در آن مقادیر شاخصها ظاهر میشوند. هر بخش مجزا که شامل یکی از memberهای بعد در حجم دادهای است ، سلول (cell) نامیدهمیشود. سلولها شاخصهای مربوط به تجمیعهای مختلف را در خود نگهداری مینمایند. در واقع مقادیر مربوط به حقایق (Fact) که در جدول حقایق (Fact) تعریف میشوند در حجم دادهای (Data Cube) در سلولها (Cell) نمایان میگردند.
شماهای دادهای (Data Schema) : سه نوع Schema در طراحی Data Warehouse وجود دارد
1. Stare
2. Snowflake
3. Galaxy1. شمای ستارهای (Star Schema) : متداولترین شما، همین شمایستارهای است. که در آن انبارداده با استفاده از اجزای زیر تعریف میشود:
• یک جدول مرکزی بزرگ به نام جدول حقایق که شامل حجم زیادی از دادههای بدون تکرار است.
• مجموعهای از جدولهای کمکی کوچکتر به نام جدول بعد ، که به ازای هر بعد یکی از این جداول موجود خواهد بود.
• شکل این شما به صورت یک ستاره است که جدول حقایق در مرکز آن قرار گرفته و هر یک از جداول بعد به وسیله شعاعهایی به آن مربوط هستند.
مشکل این مدل احتمال پیشامد افزونگی در آن است.
2. شمای دانهبرفی ( Snowflake Schema ) : در واقع شمای دانهبرفی، نوعی از شمای ستارهای است که در آن بعضی از جداول بعد نرمال شدهاند. و به همین خاطر دارای تقسیمات بیشتری به شکل جداول اضافی میباشد که از جداول بعد جدا شدهاند.
تفاوت این دو شما در این است که جداول شمای دانه برف نرمال هستند و افزونگی در آنها کاهش یافته است. که این برای کار کردن با دادهها و از لحاظ فضای ذخیرهسازی مفید است. ولی در عوض کارایی را پایین میآورد، زیرا در محاسبه کوئریها به joinهای بیشتری نیاز داریم.
3. شمای کهکشانی (galaxy schema) : در کاربردهای پیچیده برای به اشتراک گذاشتن ابعاد نیاز به جداول حقایق چندگانه احساس میشود که یک یا چند جدول بعد را در بین خود به اشتراک میگذارند. این نوع شما به صورت مجموعهای از شماهای ستارهای است و به همین دلیل شمای کهکشان یا شمای منظومهای نامیدهمیشود. این شما به ما این امکان را میدهد که جداول بعد بین جداول حقایق مختلف به اشتراک گذاشته شوند.
عملیات بر روی حجمهای دادهای :
• Roll Up (یا Drill-up) : با بالا رفتن در ساختار سلسله مراتبی مفهومی یک حجم دادهای، یا با کاهش دادن بعد، یک مجموعه با جزئیات کمتر (خلاصه شده) ایجاد مینماید. بالا رفتن در ساختار سلسله مراتبی به معنای حذف قسمتی از جزئیات است. برای مثال اگر قبلاٌ بعد مکان بر حسب شهر بوده آن را با بالا رفتن در ساختار سلسله مراتبی بر حسب کشور درمیآوریم. ولی وقتی با کاهش دادن بعد سروکار داریم منظور حذف یکی از ابعاد و جایگزین کردن مقادیر کل است. در واقع همان عمل تجمیع (aggregation) است.
• Drill Down : بر عکس عملRoll-up است و از موقعیتی با جزئیات دادهای کم به جزئیات زیاد میرود. این کار با پایین آمدن در ساختار سلسله مراتبی( به سمت جزئیات بیشتر) یا با ایجاد ابعاد اضافی انجام میگیرد.
نمونهای از عملیات Drill Down و Roll Up
• Slice : با انتخاب و اعمال شرط بر روی یکی از ابعاد یک subcube به شکل یک برش دو بعدی ایجاد میکند. در واقع همان عمل انتخاب (select) است.
• Dice : با انتخاب قسمتی از ساختار سلسله مراتبی بر روی دو یا چند بعد یک subcube ایجاد مینماید.
نمونهای از عملیات Dice و Slice
• Pivot (یا Rotate) : این عملیات بردارهای بعد را در ظاهر میچرخاند.
نمونهای از عملیات pivot
• Drill-across : نتیجه اجرای کوئریهایی که نتیجه اجرای آنها حجمهای دادهایهای مرکب با بیش از یک fact-table است.
• Ranking : سلولهایی را باز میگرداند که در بالا یا پایین شرط خاصی واقع هستند. مثلاٌ ده محصولی که بهترین فروش را داشتهاند.
سرورهای OLAP :
در تکنولوژیOALP دادهها به دو صورت چندبعدی (Multidimensional OLAP) (MOLAP) و رابطهای (Relational OLAP) (ROLAP) ذخیره میشوند. OLAP پیوندی(HOLAP) تکنولوژیی است که دو نوع قبل را با هم ترکیب میکند.
MOLAP : روشی است که معمولاٌ برای تحلیلهای OLAP در تجارت مورد استفاده قرار میگیرد. در MOLAP، دادهها با ساختار یک حجم دادهای ( Data Cube ) چند بعدی ذخیره میشوند. ذخیرهسازی در پایگاهدادههای رابطهای انجام نمیگیرد، بلکه با یک فرمت خاص انجام میشود. اغلب محصولات موفق MOLAP از یک روش چندبعدی استفاده مینمایند که در آن یک سری حجمهای دادهای کوچک، انبوه و از پیش محاسبهشده، یک حجم دادهای بزرگ (hypercube ) را میسازند.
علاوه براین MOLAP به شما امکان میدهد دادههای دیدهای (View) تحلیلگران را دسته بندی کنید، که این در حذف اشتباهات و برخورد با ترجمههای پرغلط کمک بزرگی است.
گذشته از همه اینها از آنجا که دادهها به طور فیزیکی در حجمهای دادهای بزرگ چندبعدی ذخیره میشوند، سرعت انجام فعالیتها بسیار زیاد خواهد بود.
از آنجا که یک کپی از دادههای منبع در کامپیوتر Analysis server ذخیرهمیشود، کوئریها میتوانند بدون مراجعه به منابع مجدداً محاسبه شوند. کامپیوتر Analysis server ممکن است کامپیوترسرور که تقسیم بندیها در آن انجام شده یا کامپیوتر دیگری باشد. این امر بستگی به این دارد که تقسیمبندیها در کجا تعریف شدهاند. حتی اگر پاسخ کوئریها از روی تقسیمات تجمیع (integration) شده قابل دستیابی نباشند، MOLAP سریعترین پاسخ را فراهم میکند. سرعت انجام این کار به طراحی و درصد تجمیع تقسیمبندیها بستگی دارد.
مزایا : کارایی عالی- حجمهای دادهای MOLAP برای بازیابی سریع دادهها ساخته شدهاند و در فعالیتهای slice و dice به صورت بهینه پاسخ میدهند. ترکیب سادگی و سرعت مزیت اصلی MOLAP است.
در ضمنMOLAP قابلیت محاسبه محاسبات پیچیده را فراهم میکند. همه محاسبات از پیش وقتی که حجمهای دادهای ساخته میشود، ایجاد میشوند. بنابراین نه تنها محاسبات پیچیده انجام شدنی هستند بلکه بسیار سریع هم پاسخ میدهند.
معایب : عیب این روش این است که تنها برای دادههایی با مقدار محدود کارکرد خوبی دارد. از آنجا که همه محاسبات زمانی که حجمهای دادهای ساخته میشود، محاسبه میگردند، امکان این که حجمهای دادهای مقدار زیادی از دادهها را در خود جای دهد، وجود ندارد. ولی این به این معنا نیست که دادههای حجمهای دادهای نمیتوانند از مقدار زیادی داده مشتق شده باشند. دادهها میتوانند از مقدار زیادی داده مشتق شدهباشند. اما در این صورت، فقط اطلاعات level خلاصه (level ای که دارای کمترین جزئیات است یعنی سطوح بالاتر) میتوانند در حجمهای دادهای موجود باشند.
ROLAP : محدودیت MOLAP در حجم دادههای قابل پرسوجو و نیاز به روشی که از دادههای ذخیرهشده به روش رابطهای حمایت کند، موجب پیشرفت ROLAP شد.
مبنای این روش کارکردن با دادههایی که در پایگاهدادههای رابطهای ذخیرهشدهاند، برای انجام اعمال slicing و dicing معمولی است. با استفاده از این مدل ذخیرهسازی میتوان دادهها را بدون ایجاد واقعی تجمیع در پایگاهدادههای رابطهای به هم مربوط کرد.
مزایا : با این روش میتوان به حجم زیادی از دادهها را رسیدگی کرد. محدودیت حجم داده در تکنولوژی ROLAP مربوط به محدودیت حجم دادههای قابل ذخیرهسازی در پایگاهدادههای رابطهای است. به بیان دیگر، خود ROLAP هیچ محدودیتی بر روی حجم دادهها اعمال نمیکند.
معایب : ممکن است کارایی پایین بیاید. زیرا هر گزارش ROLAP در واقع یک کواِری SQL (یا چند کواِری SQL )در پایگاه دادههای رابطهای است و اگر حجم دادهها زیاد باشد ممکن است زمان پاسخ کواِری طولانی شود. در مجموع ROLAP سنگین است، نگهداری آن سخت است و کند هم هست. بخصوص زمانی که نیاز به آدرس دهی جدولهای ذخیره شده در سیستم چند بعدی داریم.
این محدودیت ناشی از عملکرد SQL است. زیرا تکنولوژی ROLAP بر پایه عبارات مولد SQL برای پرسش و پاسخ بر روی پایگاه داده رابطهای است و عبارات SQL به همه نیازها پاسخ نمیدهند (مثلاٌ محاسبه حسابهای پیچیده در SQL مشکل است)، بنابراین فعالیتهای ROLAP به آن چه SQL قادر به انجام آن است محدود میگردد.
تفاوت ROALP و MOLAP : تفاوت اصلی این دو در معماری آنها است. محصولات MOLAP دادههای مورد نیاز را در یک حافظه نهان (cache) مخصوص میگذارد. ولی ROLAP تحلیلهای خود را بدون استفاده از یک حافظه میانی انجام میدهد، بدون آن که از یک مرحله میانی برای گذاشتن دادهها در یک سرور خاص استفاده کند.
با توجه به کند بودن ROLAP در مقایسه باMOLAP ، باید توجه داشت که کاربرد این روش بیشتر در پایگاه دادههای بسیار بزرگی است که گاهگاهی پرس و جویی بر روی آنها شکل میگیرد، مثل دادههای تاریخی و کمتر جدید سالهای گذشته.
نکته: اگر از Analysis Services که به وسیله Microsoft OLE DB Provider مهیا شده استفاده میکنید، تجمیعها نمیتوانند برای تقسیمبندی از روش ROLAP استفاده نمایند.
HOLAP : با توجه به نیاز رو به رشدی که برای کارکردن با دادههای بلادرنگ (real time) در بخشهای مختلف در صنعت و تجارت احساس میشود، مدیران تجاری انتظار دارند بتوانند با دامنه وسیعی از اطلاعات که فوراً و بدون حتی لحظهای تأخیر در دسترس باشند، کار کنند. در حال حاضر شبکه اینترنت و سایر کاربردها یی که به دادههایی از منابع مختلف مراجعه دارند و نیاز به فعالیت با یک سیستم بلادرنگ هم دارند، همگی از سیستم HOLAP بهره میگیرند.
named set :
Named Set مجموعهای از memberهای بعد یا مجموعهای از عبارات است که برای استفاده مجدد ایجاد میشود.
Calculated member
Calculated Memberها memberهایی هستند که بر اساس دادهها نیستند بلکه بر اساس عبارات ارزیابی MDX هستند. آنها دقیقاَ به سبک سایر memberهای معمولی هستند. MDX یک مجموعه قوی از عملیاتی را تامین میکند که میتوانند برای ساختCalculated Memberها مورد استفاده قرار گیرند به طوری که به شما امکان داشتن انعطاف زیاد در کار کردن با دادههای چند بعدی را بدهد.
امیدوارم در این قسمت با مفاهیم نخستین OLAP آشنا شده باشید.
تلاش خواهم کرد در قسمت بعدی در خصوص نصب SQL Server Analysis Services و نصب پایگاه دادهی Adventure Work DW 2008 شرح کاملی را ارایه کنم.
معرفی ES 6
چرا باید ES 6 را آموخت؟
در طی 2 سال آینده، تمام فریم ورکهای جدید جاوا اسکریپتی، از بوت استرپ 4 تا AngularJS 2 تا Aurelia و غیره، همگی به ES 6 کوچ خواهند کرد (و این اتفاق هم اکنون در حال رخ دادن است). بنابراین به زودی بدون فراگیری و تسلط بر ES 6، در حوزهی وب، «بیسواد» محسوب خواهید شد و فراگیری آن یک «باید» است.
وضعیت پشتیبانی از ES 6 در مرورگرهای مختلف
برای مشاهدهی پیشرفتهای مرورگرهای کنونی در زمینهی پشتیبانی از ES 6، میتوان به صفحهی ES 6 compatibility table مراجعه کرد.
برای نمونه در حال حاضر، فایرفاکس بهترین پشتیبانی از ES 6 را ارائه میدهد (با پیاده سازی 85 درصد از قابلیتها) و بعد از آن مرورگر جدید مایکروسافت قرار دارد.
وضعیت IE 10,11 در این بین تغییری نخواهند کرد؛ زیرا پشتیبانی رسمی از تمام آنها به زودی خاتمه مییابد (در سه شنبه، ۲۲ دی ۱۳۹۴).
در همین صفحه، در ابتدای چارت، ستون current browser نیز قرار دارد. این ستون، وضعیت مرورگر جاری شما را از لحاظ درصد پیاده سازی قابلیتهای ES 6 نمایش میدهد.
اهمیت دریافت آخرین نگارشهای مرورگرها
با توجه به ES 6 compatibility table، اکثر مرورگرها در نسخههای شبانه و همچنین آزمایشی آنها، به مرور در حال افزودن قابلیتهای باقیماندهی ES 6 هستند. بنابراین اگر با فایرفاکس کار میکنید، نیاز است Firefox nightly builds را نصب کنید. اگر از مرورگرهای مایکروسافت استفاده میکنید، آخرین نگارش MS Edge بهترین پشتیبانی از ES 6 را ارائه میدهد و اگر از کروم استفاده میکنید، نگارشهای بتا و Dev آن را میتوانید دریافت کنید.
علاوه بر اینها، نگارشهای فعلی این مرورگرها نیز دارای امکانات آزمایشی هستند که میتوان آنها را به صورت دستی فعال کرد. برای مثال در مرورگر کروم، به آدرس chrome://flags مراجعه کنید و در صفحهی باز شده، کلمهی JavaScript را جستجو کنید. در اینجا نیاز است گزینهی «Enable Experimental JavaScript» را فعال کنید (بر روی لینک enable ذیل آن کلیک نمائید).
به این ترتیب قادر خواهید بود آخرین افزونههای ES 6 را در developer tools console آن اجرا کنید.
چنین تنظیمی به MS Edge نیز اضافه شدهاست. پس از اجرای آن، به آدرس about:flags مراجعه کنید:
در اینجا نیز میتوانید گزینهی «Enable experimental JavaScript features» را انتخاب کنید.
معرفی traceur-compiler
هرچند قابلیتهای فعلی آخرین نگارشهای مرورگرها برای اجرای بسیاری از امکانات ES 6 کفایت میکنند، اما اگر علاقمند به اجرای تمامی آنها هستید، میتوان از traceur-compiler گوگل نیز کمک گرفت (با تلفظ تریسر). این کامپایلر، قابلیتهای جدید ES 6 را تبدیل به نگارشهای فعلی قابل درک برای مرورگرهای قدیمیتر میکند. به این ترتیب امکان اجرای آزمایشات مرتبط با ES 6 را خواهید یافت.
روش استفادهی از آن هم به صورت ذیل است:
<script src="https://google.github.io/traceur-compiler/bin/traceur.js"></script> <script src="https://google.github.io/traceur-compiler/src/bootstrap.js"></script> <script type="module"> // ES 6 </script>
در نگارشهای اخیر کتابخانه jQuery (از نگارش 1.3 به بعد) متدی به نام live به آن اضافه شده است که کاربرد آنرا در ادامه مرور خواهیم کرد.
ابتدا مثال زیر را در نظر بگیرید:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="TestLive.aspx.cs" Inherits="TestJQueryAjax.TestLive" %>
<!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></title>
<script src="js/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function() {
$('a.mylink').click(function(e) {
var $a = $(this);
alert($a.attr('id'));
});
$('a#lnkLoad').click(function(e) {
$('div#dynContent').load('live.ashx');
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<a href='#' id='lnk1' class='mylink'>link1</a>
<br />
<a href='#' id='lnkLoad'>load .ashx</a>
<div id='dynContent'>
</div>
</form>
</body>
</html>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
namespace TestJQueryAjax
{
/// <summary>
/// Summary description for $codebehindclassname$
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class live : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("<a href='#' id='lnk2' class='mylink'>link2</a>");
}
public bool IsReusable
{
get
{
return false;
}
}
}
}
همچنین اگر بر روی لینکی با id مساوی lnkLoad کلیک شود، محتوایی پویا از یک generic handler به نام live.ashx دریافت شده و به div ایی با id مساوی dynContent اضافه میگردد.
این محتوای دریافتی از generic handler ما نیز کلاسی مساوی mylink دارد، اما اینبار هر چقدر بر روی لینک اضافه شده به صفحه کلیک کنیم کار نمیکند. چرا؟ چون در هنگام فراخوانی document.ready ، این لینک وجود نداشته و روال رخدادگردانی به آن bind نشده است.
به صورت خلاصه میخواهیم روال کلیک بر روی لینکهایی با کلاس mylink همیشه کار کند. (چه در مورد عناصری در صفحه که از قبل وجود داشتهاند و چه عناصری که توسط عملیاتی Ajax ایی بعدا اضافه خواهند شد)
این مشکل با معرفی متد live حل شده است. برای این منظور تنها کافی است کد ما به صورت زیر تغییر کند:
<script type="text/javascript">
$(document).ready(function() {
$('a.mylink').live("click", function() {
var $a = $(this);
alert($a.attr('id'));
});
.
.
.
اکنون jQuery کلیه لینکهایی با کلاس مساوی mylink را که از این پس اضافه خواهند شد، به صورت live و زنده تحت نظر قرار میدهد و عکس العمل نشان خواهد داد.
مثال - نمایش بلادرنگ میزان مصرف CPU و حافظه سرور بر روی کلیه کلاینتهای متصل توسط SignalR
در اینجا از Smoothie Charts برای ترسیم نمودارهای بلادرنگ سازگار با Canvas مخصوص HTML5 استفاده شده است.
پیشنیازها
پیشنیازهای این مطلب با مطلب «مثال - نمایش درصد پیشرفت عملیات توسط SignalR» یکی است. برای مثال، نحوه دریافت وابستگیها، تنظیمات فایل global.asax و افزودن اسکریپتها، تفاوتی با مثال قبلی ندارند.
تهیه منبع داده اطلاعات نمایشی
using System.Collections.Generic; using System.Diagnostics; using System.Linq; namespace SignalR04.Common { public class Counter { public string Name { set; get; } public float Value { set; get; } } public class PerformanceCounterProvider { private readonly List<PerformanceCounter> _counters = new List<PerformanceCounter>(); public PerformanceCounterProvider() { _counters.Add(new PerformanceCounter("Processor", "% Processor Time", "_Total", readOnly: true)); _counters.Add(new PerformanceCounter("Memory", "Pages/sec", readOnly: true)); _counters.Add(new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total", readOnly: true)); } public IList<Counter> GetResults() { return _counters.Select(c => new Counter { Name = c.CategoryName, Value = c.NextValue() }).ToList(); } } }
تهیه هاب ارسال دادهها به کلاینتها
using System.Threading; using Microsoft.AspNet.SignalR; using ThreadTimer = System.Threading.Timer; namespace SignalR04.Common { public class PerformanceCounterHub : Hub { private ThreadTimer _threadTimer; //keep it alive private readonly PerformanceCounterProvider _perfService = new PerformanceCounterProvider(); public PerformanceCounterHub() { _threadTimer = new ThreadTimer(timerCallback, null, Timeout.Infinite, 1000); _threadTimer.Change(dueTime: 1000, period: 2000); } private void timerCallback(object state) { var results = _perfService.GetResults(); this.Clients.All.newCounters(results); } } }
این هاب به صورت خودکار با اولین بار وهله سازی، پس از فراخوانی متد connection.hub.start در سمت کلاینت، شروع به کار میکند.
کدهای سمت کلاینت نمایش نمودارها
<html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script> <script src="Scripts/jquery.signalR-1.1.3.min.js" type="text/javascript"></script> <script type="text/javascript" src='<%= ResolveClientUrl("~/signalr/hubs") %>'></script> <script src="Scripts/smoothie.js" type="text/javascript"></script> </head> <body> <form id="form1" runat="server"> <div> <div> <h2>Processor</h2> <canvas id="Processor" width="800" height="100"></canvas> </div> <div> <h2>Memory</h2> <canvas id="Memory" width="800" height="100"></canvas> </div> <div> <h2>PhysicalDisk</h2> <canvas id="PhysicalDisk" width="800" height="100"></canvas> </div> </div> </form> <script type="text/javascript"> var ChartEntry = function (name) { var self = this; self.name = name; self.chart = new SmoothieChart({ millisPerPixel: 50, labels: { fontSize: 15} }); self.timeSeries = new TimeSeries(); self.chart.addTimeSeries(self.timeSeries, { lineWidth: 3, strokeStyle: "#00ff00" }); }; ChartEntry.prototype = { addValue: function (value) { var self = this; self.timeSeries.append(new Date().getTime(), value); }, start: function () { var self = this; self.canvas = document.getElementById(self.name); self.chart.streamTo(self.canvas); } }; $(function () { $.connection.hub.logging = true; var performanceCounterHub = $.connection.performanceCounterHub; var charts = []; performanceCounterHub.client.newCounters = function (updatedCounters) { $.each(updatedCounters, function (index, updateCounter) { var entry; $.each(charts, function (idx, chart) { if (chart.name == updateCounter.Name) { entry = chart; return; } }); if (!entry) { entry = new ChartEntry(updateCounter.Name); charts.push(entry); entry.start(); } entry.addValue(updateCounter.Value); }); }; $.connection.hub.start(); }); </script> </body> </html>
- id هر canavs به Name اطلاعات دریافتی از سرور تنظیم شده است تا نمودارها در جای صحیحی ترسیم شوند.
- سپس نحوه کپسوله سازی SmoothieChart را مشاهده میکنید؛ چطور میتوان از آن یک شیء جاوا اسکریپتی ایجاد کرد و چطور اطلاعات را به آن اضافه نمود.
- نهایتا کار هاب را آغاز میکنیم. Callback ایی به نام performanceCounterHub.client.newCounters دقیقا متصل است به فراخوانی this.Clients.All.newCounters سمت سرور. در اینجا updatedCounters دریافتی، یک آرایه جاوا اسکریپتی است که هر عضو آن دارای Name و Value است. بر این اساس، تنها کافی است این مقادیر را که هر دو ثانیه یکبار به روز میشوند، به SmoothieChart برای ترسیم ارسال کنیم.
کدهای کامل این مثال را از اینجا نیز میتوانید دریافت کنید:
SignalR04.zip