Bootstrap 5.1.0 منتشر شد
The first minor release of Bootstrap 5 is here! v5.1.0 has arrived and is packed with exciting new features and improvements. There’s experimental support for CSS Grid, offcanvas in the navbar, a new placeholders component, horizontal collapse support, new helpers, new CSS variables in our utilities, refactored JavaScript, and more.
همان طور که میدونید مکانیزم عملکرد اکثر پلاگینهای lightbox به صورت زیر است:
<a href="orginal size of image directory"><img src="thumb(smaller size) image directory" /></a>
خب معلوم میشه که آدرس عکسی که به صورت کوچیک)اصطلاحا بند انگشتی) به نمایش در میاد باید داخل تگ img ، وآدرس عکس با سایز اصلی ، داخل تگ a قرار بگیره.
پس تقریبا معلوم شد که چه باید بکنیم.
ابتدا باید عکسی که آپلود شده را به صورت خودکار به اندازه کوچکتر تغییر ابعاد داده و سپس آدرس عکس تغییر ابعاد داده شده ، را به عنوان آدرس عکس آپلود شده به ckeditor باز گردانیم که در شکل زیر آن را نشان داده ام:
ولی ما فقط آدرس عکس تغییر ابعاد داده شده متعلق به تگ img را ، به ckeditor داده ایم و برای اینکه با lightbox به خوبی کار کند، احتیاج داریم که آدرس عکس با سایز اصلی را داخل تگ a قرار دهیم، که در ckeditor میتوانیم از قسمت پیوندها این کار را انجام دهیم، و همهی این عملیات باید به صورت خودکار انجام شود.خب تا اینجا خلاصه ای از آنچه باید انجام شود را گفتم.
در کل منطقی که باید پیاده شود بدین گونه است:
1- پیاده سازی ckeditor
2- فعال کردن قسمت آپلود عکس ckeditor
3- آپلود کردن عکس و تغییر اندازه آن به کمک کلاس WebImage
4- برگرداندن آدرس عکسهای آپلود شده به ckeditor و روشهای پیاده سازی آن
نکات:
الف) من در اینجا از ASP.NET MVC استفاده میکنم .شما نیز میتوانید منطق پیاده سازی شده را به راحتی و با کمی تغییرات به پروژه خود اعمال کنید.
ب) کدهایی که من نوشتم 100% بهینه نیستند و کاملا هم بدون اشکال نیستند ولی نیازهای شما را برآورده میکند.
ج)آدرس دادن فایلهای من کاملا صحیح نیستند و بهتر است شما از T4MVC استفاده کنید.
مرحله اول: دانلود و پیاده سازی ckeditor در صفحه
ابتدا به سایت ckeditor.com مراجعه و از قسمت دانلود، آن را دانلود کرده و سپس از حالت فشرده درآورده، در فولدری مثلا به نام Scripts در پروژهی خود بریزید.
همان طور که میدانید ckeditor با یک textarea یکپارچه میشود ، که من سادهترین آن را برای شما شرح میدهم.
اول از همه شما باید یک فایل جاوا اسکریپت متعلق به ckeditor را در صفحه ای که از آن میخواهید استفاده کنید به صفحه ضمیمه کنید. نام این فایل ckeditor.js هست که در فایل دانلودی در داخل پوشهی ckeditor دیده میشود.
<script src="/Scripts/ckeditor/ckeditor.js" type="text/javascript"></script>
خب فرض کنید که یک textarea به شکل زیر داریم. برای اینکه این textarea با ckeditor یکپارچه شود کافیست که class آن را بر روی ckeditor قرار دهید.
<textarea id="content" name="content" class="ckeditor" ></textarea>
تا به اینجای کار توانستیم ckeditor را اجرا کنیم.
در مرحله بعد سراغ فعال سازی آپلود عکس در آن میرویم.
مرحله دوم: فعال سازی آپلود عکس در ckeditor
از شواهد این طور به نظر میاد که به صورت پیشفرض این امکان غیر فعال است و باید به صورت دستی آن را فعال کنیم.
برای این کار کافیست که از مستندات ckeditor کمک بگیریم.
خب یکی از راحتترین این روشها این است که قبل از بسته شدن تگ بادی فایل جاوا اسکریپت زیر را بنویسیم:
<script type="text/javascript"> CKEDITOR.replace( 'content' , { filebrowserImageUploadUrl: '/Admin/UploadImage' } ); </script>
توضیحات:
آرگومان اول CKEDITOR.replace که در اینجا content است ، در واقع id همان textarea ای هست که میخواهیم ckeditor روی آن اعمال شود.
آرگومان دوم نام کنترلر و اکشن را برای آپلود فایل مشخص میکنه.(از منطق ASP.Net MVC استفاده کردم)
خب تا اینجا اگر تست بگیرید میبینید که قسمت زیر برایتان فعال شده.
مرحله سوم: آپلود کردن عکس و تغییر اندازه آن به کمک کلاس WebImage
برای این که ببینم که این فرم آپلود ckeditor ، چه پارامترهایی را به اکشن متد من ارسال میکنه ، از فایرباگ کمک گرفتم:
همان طور که مییبینید به خوبی آدرس post شدن اطلاعات به اکشن متدی که من برایش مشخص کردم را فهمیده.
اما سه پارامتر دیگر نیز به اکشن متد ما ارسال میکنه: CKEditor و CKeditorFuncNum و langCod
برای اینکه با این پارامترهای ارسالی بیشتر آشنا شوید ، توصیه میکنم این صفحه را ببینید.
آنچه که از این پارامترها برای ما مهم هست ، من در اکشن متد تعریفی خود لحاظ کرده ام.
خب همون طور که یپش از این گفته بودم ما نیاز داریم که عکس آپلود شده را به ابعاد کوچکتر تغییر اندازه داده و اصطلاحا از آن به عنوان تصویر بند انگشتی استفاده کنیم. آدرس این عکس کوچک شده ، همانیست که در آدرس تگ img قرار میگیره و در ابتدا به کاربر نمایش داده میشه.
برای انجام این عمل من کلاسی را برای کار کردن با عکس برایتان معرفی میکنم، به نام WebImage که در داخل فضای نامی System.Web.Helpers قرار گرفته است.
از طریق این کلاس میتوان کلیه عملیات دریافت فایل آپلود شده، ویرایش ، تغییر اندازه ، چرخاندن ، بریدن و حتی watermark کردن و در نهایت ذخیره عکس را به آسانی انجام داد.
من کدهای متد UploadImage را برایتان قرار میدهم که زیاد هم بهینه نیست و سپس برایتان توضیح میدهم.
public ActionResult UploadImage(string CKEditorFuncNum, string CKEditor, string langCode) { string message; // message to display when file upload successfully(optional) string thumbPath = ""; // the directory for thumb file that should resize var db = new MyDbContext(); // make new instance from my context // here logic to upload image // and get file path of the image var file = WebImage.GetImageFromRequest(); // get the uploaded file from request var ext = Path.GetExtension(file.FileName); // get the path of file //get the file name without extension var fileName = Path.GetFileNameWithoutExtension(file.FileName); //add time to file name to avoid same name file overwrite, and then add extension to it fileName += DateTime.Now.ToFileTime() + ext; //choose the path for the original size of image var path = Path.Combine(Server.MapPath("~/Content/UploadedImages/Default"), fileName); file.Save(path); //save the original size of the image db.Images.Add(new Image { RealName = file.FileName, FileName = fileName, UploadDate = DateTime.Now }); // save image info to db db.SaveChanges(); // submit changes to db string defaultPath = "/Content/UploadedImages/Default/" + fileName; //path for original size of //images if (file.Width > 400) // if width of image bigger than 400 px do resize { file.Resize(400, 400, true); //resize the image , third argument is aspect ratio string thumbName = "Thumb-" + fileName; // resized image name //path for resized image file string path2 = Server.MapPath("~/Content/UploadedImages/Thumbs/" + thumbName); thumbPath = "/Content/UploadedImages/Thumbs/" + thumbName; //save resized image file file.Save(path2); } else { thumbPath = defaultPath; // if the size not bigger than 400px the thumb, path = default path } // passing message success/failure message = "Image was saved correctly"; // since it is an ajax request it requires this string //java script that return files path to ckeditor string output = @"<script>window.parent.CKEDITOR.tools.callFunction(" + CKEditorFuncNum + ", \"" + thumbPath + "\", \"" + message + "\");window.parent.document.getElementById('cke_145_textInput').value='" + defaultPath + "';window.parent.document.getElementById('cke_125_textInput').value=0;</script>"; return Content(output); }
توضیحات:
ابتدا یه رشته به نام message در نظر گرفتم ، برای هنگامی که آپلود شد، ckeditor به کاربر نشان بده.
سپس منطق من به این صورت بوده که مسیری برای ذخیره سازی فایلهای تغییر اندازه داده شده ، و نیز مسیری برای فایلهای با اندازه اصلی در نظر گرفتم.
همچنین من در اینجا من از بانک اطلاعاتی برای ذخیره سازی اطلاعاتی از عکس استفاده کردم، که در اینجا بحث اصلی ما نیست.
سپس به کمک WebImage.GetImageFromRequest فایل آپلود شده را دریافت کردم.این متد به اندازه کافی باهوش هست که بفهمد ، چه فایلی آپلود شده.
سپس پسوند فایل را از نام فایل جدا کردم، و تاریخ کنونی را به شکل رشته در آورده و به انتهای نام عکس اضافه کرده تا از تکراری نبودن نام عکسها مطمئن باشم.
سپس پسوند فایل را نیز دوباره به نام فایل اضافه کردم و به کمک متد Save کلاس WebImage عکس را ذخیره کردم.
سپس چک کردم که اگر عرض عکس بیشتر از 400 پیکسل هست ، آن را تغییر اندازه بده و ذخیره کنه، و در غیر این صورت آدرس عکسی که قرار بود تغییر اندازه داده بشه با آدرس عکس اصلی یکی میشه.
قسمت مهم:
نکته مهم اینه که ما آدرسهای عکسهای آپلود شده را چگونه به ckeditor برگردانیم.
همان طوری که در قسمت آخر هم مشاهده میکنید ، ما سه دستور جاوا اسکریپت به مرورگر برگردوندیمم:
اولیش:
window.parent.CKEDITOR.tools.callFunction(" + CKEditorFuncNum + ", \"" + thumbPath + "\", \"" + message + "\");
در حقیقت ما در اینجا ما از apiهای ckeditor و همچنین پارامترهای ارسالی از طرف ckeditor استفاده کردیم ، تا قسمت آدرس عکس را با آدرس عکس تغییر اندازه داده شده و کوچک شده پر میکنیم.
سوال؟
حالا چگونه قسمت پیوند را پر کنیم؟ این را دیگر من پیدا نکردم ، تا دست به دامن دوست و یا شایدم دشمن قدیمیمون جاوا اسکریپت شدم.
اول رفتم به کمک فایرباگ دیدم که id فیلد پیوندها چیه؟
همان طور که معلومه id این فیلد cke_145_textInput هست و به کمک یه خط js میتوان این فیلد را با آدرس عکس آپلود شده با سایز اصلی پر کرد.
اولش من این را نوشتم:
document.getElementsById("cke_145_textInput").value = defaultPath;
اما بازم js شروع کرد به بدقلق شدن. هرچی توی کنسول دیباگش کردم خطای null بودن را میداد. بعد از یه ساعت سرو کله زدن و تقریبا ناامید شدن ، چشمم به قسمت اول کد api خود ادیتور که اولش را با window.parent شروع کرده افتاد ، و من هم کد خودم را به شکل زیر تغییر دادم:
window.parent.document.getElementsById("cke_145_textInput").value = defaultPath;
موفقیت در این قسمت از کد باعث شد که من دست به کدتر شوم و مشکل border عکس ها، که به صورت دیفالت در IE یا همون دشمن همیشگی وجود داره ، را حل کنم ومقدار border را به صورت پیش فرض صفر کنم.
window.parent.document.getElementsById('cke_125_textInput').value=0;
خب همهی این دردسرها را ما تحمل کردیم تا به سادهترین شکل ممکن هر عکسی را که آپلود شد ، برای مکانیزم lightbox آماده کنیم و به راحتی یه گالری عکس خوب داشته باشیم.
خب حتما میپرسید که از چه پلاگینی برای ایجاد lightbox استفاده کنیم:
من به شخصه پلاگین colorbox را پیشنهاد میدم.
با انجام یک سرچ ساده سایتش را پیدا کنید و با مستندات و ویژگیهای آن آشنا شوید.
یک پیشنهاد:
برای انجام سلکت زدن برای عناصری که باید پلاگین colorbox روی آنها اعمال شوند من سلکت زدن به شیوهی زیر را پیشنهاد میکنم:
$(".container [href$='.jpg']").colorbox({ maxWidth: 800, opacity: 0.5, rel: 'gal' }); $(".container [href$='.png']").colorbox({ maxWidth: 800, opacity: 0.5, rel: 'gal' }); $(".container [href$='.gif']").colorbox({ maxWidth: 800, opacity: 0.5, rel: 'gal' });
فرض کنید div ی که متن و عکسهای ما را شامل میشه ، کلاسش container باشه . با کمک [href$='.jpg'] میتوان گفت هر لینکی که، پسوند فایلی که به آن اشاره میکند، .jpg هست، ویژگی colorbox را به خود بگیرید.
یک پیشنهاد برای تشکیل گالری عکس:
همان طور که من در بالا اشاره کردم ، rel را بر روی gal قرار دادم، تا هر تگی که ویژگی rel را داشته باشد، تشکیل یک گروه برای گالری عکس را بدهد.
برای اینکه بتوانیم این ویژگی را به عناصر مورد نظر خود اعمال کنیم ، بازم دست به دامان jQuery میشویم:
$(".container [href$='.jpg']").attr("rel", "gal");
خب مثل اینکه دیگر کار تمام شده و امیدوارم برای شما مفید بوده باشه.
موفق باشید...
برای مثال در صورتیکه در برنامه خود از اعتبار سنجی مبتنی بر توکن (Token Base Authentication) استفاده میکنید، قبل از ارسال هر درخواست (request)، کدهایی مشابه کد زیر باید نوشته شوند:
let headers = new Headers(); let token = localStorage.getItem('token'); headers.append('Authorization', 'bearer ' + token); this.http.get('/api/controller/action', { headers: headers })
همچنین فرض کنید بعد از رسیدن جواب هر درخواست، میخواهید response code را چک کنید و خطاهای احتمالی را مدیریت کنید. مثلا درصورت دریافت کد 401، کاربر را به صفحه «ورود» و با دریافت کد 404 آنرا را به صفحه «یافت نشد» هدایت کنید و یا با دریافت کد 403 یا 500 پیغام مناسبی را نمایش دهید. بدیهی است در این صورت بعد از هر آمدن پاسخ از سمت سرور (response)، این کدها بایستی تکرار شوند.
جهت پرهیز از این کدهای تکراری، میتوان برای ماژول Http، یک interceptor واحد درنظر گرفت که تمامی کدهای تکراری را تنها یکبار داخل آن پیاده سازی کرد. مزیت این روش، مدیریت راحت کد، کاهش پیچیدگیها و همچنین حذف کدهای تکراری و یکسان سازی آنها است.
هرچند در Angular دیگر به مانند Angular 1.x مفهوم intercept بر روی Http را به صورت توکار نداریم، ولی به دلایل زیر ما نیاز به پیاده سازی interceptor برای ماژول Http را داریم:
- تنظیم هدرهای سفارشی و اصلاح آدرس، قبل از ارسال درخواست به سمت سرور
- تنظیم token در هدر درخواست، جهت اعتبار سنجی
- مدیریت سراسری خطاهای Http
- انجام هرگونه عملیات crosscutting
حالا که Angular مفهموم intercept را برای ماژول Http خود به صورت توکار درنظر نگرفته است، راهحل چیست؟ بهترین راهحل برای پیاده سازی موارد مطرح شده در بالا، ارث بری و یا گسترش (extend) مستقیم ماژول Http است:
import { Injectable } from "@angular/core"; import { ConnectionBackend, RequestOptions, Request, RequestOptionsArgs, Response, Http, Headers } from "@angular/http"; import { Observable } from "rxjs/Rx"; import 'rxjs/add/operator/catch'; import 'rxjs/add/observable/throw'; @Injectable() export class InterceptedHttp extends Http { constructor(backend: ConnectionBackend, defaultOptions: RequestOptions) { super(backend, defaultOptions); } request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> { // اصلاح url if (typeof (url) === 'string') url = this.updateUrl((url as string)); else url.url = this.updateUrl((url as Request).url); return super.request(url, this.getRequestOptionArgs(options)).catch((err: Response) => { // Exception handling switch (err.status) { case 400: console.log('interceptor: 400'); console.log(err); break; case 404: console.log('interceptor: 404'); console.log(err); break; case 500: console.log('interceptor: 500'); console.log(err); break; case 401: console.log('interceptor: 401'); console.log(err); break; case 403: console.log('interceptor: 403'); console.log(err); break; default: console.log('interceptor: ' + err.status); console.log(err); } return Observable.throw(err); }); } private updateUrl(req: string) { return `http://localhost:61366/api/${req}` } private getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs { if (options == null) { options = new RequestOptions(); } if (options.headers == null) { options.headers = new Headers(); } // هدر درخواست تنظیم let token = localStorage.getItem('token'); options.headers.append('Authorization', 'bearer ' + token); return options; } }
نکته: به عنوان مثال، در صورتیکه قصد دارید، برای درخواستهایی از جنس get، هدر متفاوتی نسبت به دیگر درخواستها داشته باشید، آنگاه پیاده سازی عملیات اصلاح هدر در متد request جواب کار را نخواهد داد. برای حل این موضوع میتوانید به جای اصلاح header در متد request، تمامی متدهای get ،post، put ،delete ،patch ،head و options را باز نویسی کرده و در هرکدام از این متدها اینکار را انجام دهید.
حالا با تغییر قسمت providers در ماژول اصلی برنامه به شکل زیر، Angular را مجبور میکنیم بجای استفاده از ماژول Http توکار خود، از ماژول جدید InterceptedHttp استفاده کند:
//… providers: [{ provide: Http, useFactory: (backend: XHRBackend, options: RequestOptions) => { return new InterceptedHttp(backend, options); }, deps: [XHRBackend, RequestOptions], }], //…
همه چیز آماده است. اکنون کافی است ماژول Http را در سرویس یا کامپوننتهای خود تزریق کرده و درخواستهای Http را بدون هیچگونه نوشتن کد اضافی برای تنظیم هدر و غیره (با فرض اینکه تمامی آنها در متد request از ماژول http نوشته شدهاند)، به مانند قبل صادر کنید. برای نمونه کد زیر را ببینید.
import { Http, URLSearchParams } from '@angular/http'; //… constructor(private _http: Http) { } ngOnInit() { let urlSearchParams: URLSearchParams = new URLSearchParams(); urlSearchParams.append('page', page.toString()); urlSearchParams.append('count', count.toString()); let params = urlSearchParams.toString(); this._http.get(`/cars`, { params: params }) .subscribe(result => { console.log('service: Succ'); this.cars = result.json(); }, err => { console.log('service: error'); }); } //…
لیست جلسات Microsoft Build 2020
دوره 4 ساعته TypeScript
<img [src]="...." />
<img [ngClass]='..' />
import { Directive, ElementRef, OnInit } from '@angular/core'; @Directive({ selector: '[appHighlight]', }) export class HighlightDirective implements OnInit { _dval = 'green'; constructor(private _ref: ElementRef) { } ngOnInit(): void { this._ref.nativeElement.style.backgroundColor = this._dval; } }
<span appHighlight>Attibute Directive</span>
حال ممکن است که بخواهید به این ویژگی مقداری را نسبت دهید و از طریق این مقدار، عملیات مورد نظر را انجام دهید. به عنوان نمونه در اینجا میخواهیم رنگ پس زمینه را در همان تگ معرفی کنیم:
پس کلاس دایرکتیو را به شکل زیر بازنویسی میکنیم:
import { Directive, ElementRef, OnInit } from '@angular/core'; @Directive({ selector: '[appHighlight]', inputs: ["hc"] }) export class HighlightDirective implements OnInit { hc: string; _dval = 'green'; constructor(private _ref: ElementRef) { } ngOnInit(): void { this._ref.nativeElement.style.backgroundColor = this.hc || this._dval; } }
معرفی کردن یک فیلد به عنوان ورودی در انگیولار، از دو طریق امکان پذیر است:
1. در اولین حالت شما متغیری را تعریف میکنید و آن متغیر را همانند کد بالا داخل ویژگی inputs متادیتای Directive معرفی میکنید.
2. در شیوه بعد که در این مقاله هم ذکر شده است میتوانید از طریق متادیتایی به نام Input@ اینکار را انجام دهید:
@Input() hc:string;
اینکه از کدام شیوه استفاده کنید تفاوتی ندارد و به خودتان بستگی دارد. ولی شیوهی اول به دلیل اینکه همه یکجا تعریف میشوند، نظم بهتری داشته و در یک نگاه میتوان ورودیها را تشخیص داد؛ ولی در شیوهی دوم باید کل کلاس را برای یافتن آنها مشاهده کرد.
مزیت روش دوم این است که در حین کدنویسی بسیار راحت است تا در همانجا ورودی را تعریف کنیم؛ به جای اینکه مرتب به ابتدای کلاس بازگردیم تا آن را تعریف کنیم.
this._ref.nativeElement.style.backgroundColor=this.hc || this._dval;
<h1 appHighlight [hc]="'red'"> َApp Works! </h1>
<h1 appHighlight [hc]="'red'" [hc2]="....." [hc3]="....." ....> App Works! </h1>
گاهی اوقات ممکن است بخواهید عمل مورد نظر را بر اساس رویدادهای یک المان انجام دهید. پس کلاس را مجددا بازنویسی کرده و کدهای جدید را به آن اضافه میکنیم:
import { Directive, ElementRef, OnInit } from '@angular/core'; @Directive({ selector: '[appHighlight]', inputs: ["hc"], host: { '(mouseenter)': 'onMouseEnter()', '(mouseleave)': 'onMouseLeave()', } }) export class HighlightDirective implements OnInit { hc: string; _dval = 'green'; constructor(private _ref: ElementRef) {} ngOnInit(): void { this._ref.nativeElement.style.backgroundColor = this.hc || this._dval; } onMouseEnter() { this._ref.nativeElement.style.backgroundColor = 'blue'; } onMouseLeave() { this._ref.nativeElement.style.backgroundColor = 'pink'; } }
سورس نگارش کامل دات نت
The referencesource repository contains sources from Microsoft .NET Reference Source that represent a subset of the .NET Framework. This subset contains similar functionality to the class libraries that are being developed in .NET Core. We intend to consult the referencesource repository as we develop .NET Core. It is also for the community to leverage to enable more scenarios for .NET developers.
یکی از قابلیتهای جالب SQL Server در یک شبکه محلی امکان link و اتصال آنها به یکدیگر است. به این صورت امکان کوئری گرفتن (و یا اعمال متداول SQL ایی) از دو یا چند سرور مختلف با دستورات T-SQL میسر میشود؛ به نحوی که حس یکپارچگی دیتابیسهای این سرورها را حین کوئری نوشتن خواهیم داشت.
برای مثال فرض کنید دو سرور SQL1 و SQL2 را در شبکه داریم. میخواهیم در سرور SQL1 اتصالی را به سرور SQL2 ایجاد کنیم.
USE master
EXEC sp_addlinkedserver
'SQL2',
N'SQL Server'
sp_addlinkedsrvlogin @useself='false ', @rmtsrvname = 'SQL2',
@rmtuser = 'sa',
@rmtpassword = 'pass#'
دستورات T-SQL فوق کار ثبت یک liked server جدید و اعمال مشخصات کاربری که توسط آن قرار است به سرور SQL2 دسترسی داشت، انجام میدهند.
اکنون جهت بررسی این اتصال در سرور SQL1 کوئری زیر را اجرا میکنیم:
select * from sql2.faxManager.dbo.tblErja
که نحوهی فراخوانی جدول مورد نظر باید به صورت Server.DatabaseName.dbo.TableName در آن رعایت شود.
تا اینجا همه چیز خوب است. مشکل از زمانی شروع میشود که بخواهیم تراکنشها را نیز دخالت دهیم و اصولی کار کنیم. برای مثال:
begin distributed tran
select * from sql2.faxManager.dbo.tblErja
commit tran
خطایی که در ویندوز سرور 2003 با آخرین به روز رسانیها ظاهر میشود به صورت زیر است:
OLE DB provider for linked server returned message "The partner transaction manager has disabled its support for remote/network transactions.".
به صورت پیش فرض این نوع تراکنشهای توزیع شده غیرفعال هستند مگر اینکه فعال شوند و روش حل مشکل نیز به صورت زیر میباشد:
قبل از هر کاری به کنسول سرویسهای ویندوز مراجعه کرده و از در حال اجرا بودن سرویس Distribute Transaction Coordinator اطمینان حاصل کنید.
سپس به قسمت زیر مراجعه نمائید:
نود مربوط به Component Service را گشوده و سپس بر روی My Computer کلیک راست کرده و گزینهی خواص را انتخاب کنید.
در صفحهی بازه شده به برگهی MSTDC مراجعه کرده و بر روی دکمهی Security Configuration کلیک نمائید.
اکنون تنظیمات آنرا مطابق شکل زیر تغییر دهید.
این تنظیم باید بر روی هر دو سرور SQL1 و SQL2 انجام شود.
پس از این تغییرات که شامل راه اندازی مجدد سرویس Distribute Transaction Coordinator نیز خواهد شد، مشکل خطای فوق برطرف شده و امکان استفاده از تراکنشها در linked servers نیز میسر میشود.
مشکل دیگری که به آن برخوردم خطای زیر است:
OLE DB provider for linked server returned message "Cannot start more transactions on this session.".
برای حل این مشکل یک سطر زیر را باید به ابتدای کوئری خود اضافه کرد که جزو الزامات تراکنشهای توزیع شده است و به این صورت از rollback کامل تمامی دستورات موجود فراخوانی شده T-SQL در صورت بروز کوچکترین خطایی اطمینان حاصل میکند:
SET XACT_ABORT ON
برای مطالعه بیشتر:
MSDTC Troubleshooting
AngularJS
- به اشتراک گذاری دادهها بین کنترلرها در AngularJs
- آشنایی با Directiveها در AngularJs
- ارتباط بین Controller و Directive در AngularJs
- inject$ در AngularJs
- روش Controller as در AngularJs
- ارث بری کنترلرها در AngularJs
- پیاده سازی کنترلرهای Angular با استفاده از Typescript
- واکشی اطلاعات سرویس Web Api با استفاده از TypeScript و AngularJs
- تفاوت AngularJS با KnockoutJS
- آشنایی با Promises در جاوا اسکریپت
- بررسی angular.bootstrap
- خواندن اطلاعات از سرور و نمایش آن توسط Angular در ASP.NET MVC
- ساختار پروژههای Angular
- یک نکته درباره Angular routeProvider
- مسیریابی تو در تو در Angularjs با استفاده از UI-Router
- Lazy Loading در AngularJS
- بررسی خروجی IsAjaxRequest در درخواستهای http$ توسط AngularJS
- بررسی سرویسهای on$ و emit$ و broadcast$ در AngularJs
- آشنایی بیشتر با AngularJS Directive
- چگونگی استفاده از افزونه Isotope در AngularJS
- نمایش تاریخ شمسی توسط JavaScript در AngularJS
- توسعه سرویسهای Angular به روش OOP
- Angular Interceptors
- پیاده سازی Template تو در تو در AngularJS و ASP.NET MVC
- ارث بری prototype ای در جاوا اسکریپت به زبان خیلی ساده
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت اول
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت دوم
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت سوم
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت چهارم
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت پنجم
- زیرنویس فارسی ویدئوهای مقدمات AngularJS - قسمت ششم (قسمت آخر)