نظرات مطالب
ایجاد alert,confirm,prompt هایی متفاوت با jQuery Impromptu
سلام
با تشکر از راهنمایی شما برای کنترل‌ها من از این کنترل می‌خواستم استفاده کنم ولی اجرا نشد اگه راهنماییم کنید ممنون میشم .
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />
<title></title>

<link href="jquery-impromptu.css" media="all" rel="stylesheet" type="text/css" />
<script src="jquery-1.8.3.min.js" type="text/javascript"></script>
<script src="jquery-impromptu.js" type="text/javascript"></script>
<script type="text/javascript">

$(function(){
$show.click(function(e){
$.prompt("Hello World!");
});
});
});

</script>
</head>

<body>
<button class="show">ShowPrompt</button>
</body>
</html>
ممنون
مطالب
کاهش حجم قابل ملاحظه‌ی برنامه‌های Angular با استفاده از RxJS 5.5
Angular 5.x به همراه پشتیبانی از RxJS 5.5.x منتشر شده‌است. RxJS 5.5 نیز به همراه تغییر قابل ملاحظه‌ای در نحوه‌ی import اجزای آن توسط ویژگی جدید lettable operators است. در این مطلب نحوه‌ی ارتقاء برنامه‌های قبلی به این نگارش جدید و همچنین اثر آن‌را بر اندازه‌ی برنامه‌ی نهایی تولید شده، بررسی می‌کنیم.


روش جدید import اجزای RxJS در نگارش 5.5 آن

تغییرات تعاریف عملگرها:
تا پیش از Angular 5 و RxJS 5.5 (و یا Angular CLI versions <1.5.0)، اگر نیاز به عملگری (operator/function) مانند map وجود داشت، روش import آن به صورت زیر بود:
import 'rxjs/add/operator/map';
اما پس از RxJS 5.5 امکان import آن‌ها با روش مخصوص ES 6 میسر شده‌است (به نام جمع operators دقت داشته باشید؛ چون مسیر rxjs/observable نیز وجود دارد):
import { map } from 'rxjs/operators';
بنابراین در این حالت دیگر روش import یکجای این تعاریف در فایلی مانند «rxjs-operators.ts» وجود ندارد و این تعاریف باید به ازای هر فایلی که از آن‌ها استفاده می‌کنند، مانند سایر importهای ES 6 یکبار دیگر مجددا ذکر شوند؛ مانند:
import { map, catchError, tap } from 'rxjs/operators';
در حالت کلی مسیر node_modules/rxjs/operators را برای یافتن متدهای جدید بررسی کنید.

همچنین در این نگارش، Observable بجای rxjs/Rx :
import { Observable } from 'rxjs/Rx';
از rxjs/Observable دریافت می‌شود:
import { Observable } from 'rxjs/Observable';
تا بتوان از قابلیت‌های جدید آن استفاده کرد.

تغییرات تعاریف statics:
برای صدور خطاها بجای throw قبلی:
import 'rxjs/add/observable/throw';

Observable.throw('error');
خواهیم داشت:
import { ErrorObservable } from 'rxjs/observable/ErrorObservable';

ErrorObservable.create('error');

و برای ایجاد تایمر، بجای timer پیشین:
import "rxjs/add/observable/timer";

const timerSource$ = Observable.timer(initialDelay);
خواهیم داشت:
import { timer } from 'rxjs/observable/timer';  

const timerSource$ = timer(initialDelay);
و به طور کلی مسیر node_modules\rxjs\observable را برای یافتن تعاریف static قبلی جستجو کنید.


معرفی lettable operators

Lettable Operators توابعی هستند که یک observable را دریافت و یک observable را بازگشت می‌دهند؛ به آن‌ها pipeable operators هم می‌گویند. از این جهت که در اینجا متد جدید pipe، برای ترکیب چندین تابع عملگر بر روی مقادیر observable توسط آن، ارائه شده‌است.
مزیت این روش این است که pipeable/lettable operators، یک سری تابع محض هستند و اگر مورد استفاده قرار نگیرند، به سادگی توسط سیستم و ابزار ساخت برنامه، از فایل نهایی حذف خواهند شد؛ یا اصطلاحا tree-shakable هست. اما روش پیشین تعریف این عملگرها، tree-shakable نبوده و حتی اگر توسط برنامه مورد استفاده قرار نگیرند، در بسته‌ی نهایی تولید شده، حضور خواهند داشت. Tree-shaking به معنای پروسه‌ی حذف کدهای مرده است. روش جدید استفاده‌ی از importهای ES 6، امکان تشخیص عملگرهای استفاده نشده را توسط ابزارهایی مانند TS-Lint و تنظیمات کامپایلر TypeScript به سادگی میسر می‌کنند و به این ترتیب با حذف متدها و ماژول‌های استفاده نشده، می‌توان به حجم نهایی بسیار کمتری رسید.


روش قبلی تعریف عملگرهای Observable، اصطلاحا Patching نامیده می‌شود. به این معنا که هر متد جدید import شده‌ی در برنامه، به Observable.prototype اصلی اضافه و وصله می‌شود. اما در این روش جدید، تنها متد وصله شده‌ی از پیش موجود، Observable.prototype.pipe است و تمام متدهای دیگر import شده، توابع محض هستند و نه وصله‌ای به Observable.prototype اصلی. زمانیکه وصله‌ای به Observable.prototype متصل می‌شود، دیگر امکان حذف آن توسط ابزارهای ساخت برنامه وجود ندارد (حتی اگر استفاده نشده باشند)؛ اما اگر این متدها به صورت خالص و مجزای از Observable.prototype ارائه شوند، امکان حذف کدهای مرده و استفاده نشده، به سادگی میسر خواهد شد؛ چون توابعی خالص و متکی به خود هستند.

یک نمونه مثال استفاده‌ی از pipeable/lettable operators را در کد زیر مشاهده می‌کنید:
import { from} from 'rxjs/observable/from';
import { map, scan, filter } from 'rxjs/operators';

const source$ = range(1,10);

const sumOfSquaredOddNumbers$ = source$.pipe(
   filter(n => n % 2 !== 0), 
   map(n => n * n),
   scan((acc,s) => acc + s, 0)
);
sumOfSquaredOddNumbers$.subscribe(v => console.log(v));

/*** Output ****/ 
1
10
35
84
165
این مثال، جمع به توان 2 اعداد را در یک بازه‌ی مشخص، محاسبه می‌کند. برای این منظور ابتدا یک منبع Observable توسط متد range ایجاد شده‌است.
در اینجا روش تعریف Observableها نیز تغییر کرده‌است و از متد of جهت کار با تعدادی ورودی مشخص و یا متد range برای کار با بازه‌ای از اعداد، استفاده می‌شود:
import { of } from 'rxjs/observable/of';
import { from } from 'rxjs/observable/from';
import { range } from 'rxjs/observable/range';

const source$ = of(1,2,3);
const rangeSource$ = range(0,5);
سپس توسط متد pipe، ترکیبی از متدهای RxJS را مشاهده می‌کند که بر روی منبع Observable اصلی کار می‌کنند.
متد filter، اعداد فرد بازه را انتخاب می‌کند. متد map این اعداد انتخابی را به توان 2 می‌رساند و سپس متد scan آن‌ها را با هم جمع می‌زند و نتیجه توسط متد pipe به صورت یک Observable دیگر بازگشت داده می‌شود که می‌توان مشترک آن شد و برای مثال خروجی فوق را در console درج کرد.


تغییر نام عملگرهای قبلی RxJS

تا اینجا دریافتیم که هدف اصلی pipeable/lettable operators، عدم معرفی آن‌ها به صورت یک وصله‌ی جدید جدانشدنی از Observable.prototype، به صورت توابع خالص است. اکنون که این عملگرها، تبدیل به متدهای خالص و متکی به خود شده‌اند، نباید با متدهای اصلی جاوا اسکریپت تداخل نام پیدا کنند؛ به همین جهت برای ارتقاء کدهای قدیمی خود، به این تغییر نام‌ها نیاز خواهید داشت: متد do به tap تغییر نام یافته‌است. متد switch شده‌است switchAll. بجای catch اینبار catchError داریم و finally شده‌است finalize.


مثالی از ارتقاء کدهای قدیمی به روش جدید RxJS 5.5

اگر مثال روش قدیمی مبتنی بر وصله کردن Observable.prototype، به صورت زیر باشد:
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/filter';

names = allUserData.
         map(user => user.name).
         filter(name => name);
معادل جدید آن به این صورت تغییر می‌کند:
import { Observable } from 'rxjs/Observable';
import { map, filter } from 'rxjs/operators';

names = allUserData.pipe(
   map(user => user.name),
   filter(name => name),
);
زمانیکه تعریف Observable از مسیر rxjs/Observable درخواست می‌شود، به همراه عملگر وصله شده‌ی pipe نیز هست. به همین جهت نیازی به تعریف مجدد آن نیست. پس از آن متدهای map و filter، به داخل pipe منتقل می‌شوند. در این بین نیاز است تغییر نام متدها را که پیشتر نیز ذکر شد، مدنظر داشته باشید.
به عنوان یک مثال تکمیلی، کدهای سری «احراز هویت و اعتبارسنجی کاربران در برنامه‌های Angular» جهت استفاده‌ی از pipeable/lettable operators به روز رسانی شده‌اند. لیست تغییرات آن‌ها را در اینجا می‌توانید مشاهده کنید.
نظرات مطالب
تاریخ شمسی برای blogger !
سلام من این رو بین head و /head قرار دادم ولی کار نکرد.
آدرس من :
mortalfun.blogspot.com
نظرات مطالب
تغییر عملکرد و یا ردیابی توابع ویندوز با استفاده از Hookهای دات نتی
با برنامه‌های دات نت هم کار می‌کنه. مثلا متد  new WebClient().DownloadData را در برنامه دات نتی خودتون فراخوانی کنید. بعد در برنامه API Monitor تیک قسمت مربوط به شبکه و اینترنت را قرار دهید (تصویر اول مقاله فوق). تمام فراخوانی‌های شبکه برنامه را مونیتور می‌کند.
ضمنا برنامه API Monitor قابل بسط است. یعنی اگر به پوشه API آن مراجعه کنید یک سری فایل XML در آن قرار دارد که تعاریف توابع DLLهای مختلف در آن ارائه شده‌اند. اگر تعریفی یا DLL ایی در آن نیست، قابل افزودن است. یا حتی اگر خودتان نمی‌توانید اینکار را انجام دهید، فایل هدر آن‌را در انجمن این برنامه ارسال کنید تا به شما کمک کنند.
مطالب
ارتباط بین کامپوننت ها در Vue.js - قسمت چهارم کاربرد Vuex - بخش اول
در قسمت‌های قبلی (^ ,^ ,^ ) نحوه‌ی ارتباط بین کامپوننت‌ها بررسی شد؛ روش دیگری هم برای به اشتراک گذاری داده‌ها بین کامپوننت‌ها وجود دارد که با استفاده از کتابخانه‌ای بنام Vuex پیاده سازی میشود. وقتی برنامه‌ی شما وسعت پیدا میکند و ارتباط بین کامپوننت‌ها بیشتر و پیچیده‌تر می‌شود، روشهای قبلی (^ ,^ ,^ ) کارایی لازم را ندارند و یا اینکه به سختی میشود داده‌های به اشتراک گذاشته شده‌ی بین کامپوننت‌ها را مدیریت نمود. در اینجا میتوان از Vuex  استفاده کرد و به‌راحتی ارتباط‌های پیچیده‌ی بین کامپوننت‌ها را مدیریت کرد.


کد زیر را در نظر بگیرید:
new Vue({
  // state
  // داده‌ها در اینجا قرار میگیرند
  data () {
    return {
      count: 0
    }
  },
  // view
  // ویوها برای نمایش داده‌ها مورد استفاده قرار میگیرند
  template: `<div>{{ count }}</div>`,
  // actions
  // برای تغییر داده‌ها از متدها استفاده میکنیم
  methods: {
    increment () {
      this.count++
    }
  }
})


در یک کامپوننت ساده، از طریق Actionها، داده‌ها (State) تغییر داده میشوند و سپس این تغییر در view مشاهده میشود. اما فرض کنید بیش از صد کامپوننت در برنامه دارید که بسیاری از آنها از داده‌های واحدی استفاده میکنند. روشهای قبلی (^ ,^ ,^) برای چنین سناریویی جوابگو نخواهند بود (آن‌را به سختی میتوان مدیریت کرد و بسیار طاقت فرسا خواهد بود).

راه حل Vuex:
با استفاده از Vuex میتوان برای داده‌ها (State)، یک منبع در نظر گرفت تا کامپوننت‌ها قادر باشند از داده‌های واحدی استفاده کنند و اشتراک گذاری داده‌ها ساده شود.


یک برنامه ساده با استفاده از Vuex:

یک پروژه Vuejs را ایجاد کنید و مطابق تصویر زیر، گزینه دوم را انتخاب و Enter را فشار دهید:


سپس گزینه Vuex را طبق تصویر زیر با دکمه‌ی space انتخاب کنید و برای مابقی گزینه‌های بعدی با زدن Enter، پیش فرض‌ها را بپذیرید تا پروژه ساخته شود:


دو کامپوننت را به برنامه اضافه میکنیم.

کامپوننت اول با نام increase-counter-component.vue  

<template>
  <div>
    <!--  نمایش شمارشگر  -->
    <h1>{{count}}</h1>
    <!--  افزودن یک واحد به شمارشگر  -->
    <button @click="add">Add 1</button>
    <!--  افزودن مقداری دلخواه به شمارشگر  -->
    <button @click="add2">Add 2</button>
  </div>
</template>

<script>
// یا همان منبع ذخیره داده‌ها store کردن  import
import store from "../store";

export default {
  // You can consider computed properties another view into your data.
  // https://css-tricks.com/methods-computed-and-watchers-in-vue-js/
  computed: { count: () => store.state.count },

  // به دو طریق فراخوانی شده  add تابع
  methods: {
    // بدون پارامتر
    add: () => store.commit("add"),
    // با  پارامتر
    // برای مقدار مورد نظر استفاده کنیم input میتوانیم بجای مقدار ثابت از یک
    add2: () => store.commit("add", 2)
  }
};
</script>


کامپوننت دوم با نام decrease-counter-component.vue  

<template>
  <div>
    <h1>{{count}}</h1>
    <button @click="subtract">Subtract 1</button>
    <button @click="subtract(3)">Subtract 3</button>
  </div>
</template>

<script>
import store from "../store";

export default {
  computed: { count: () => store.state.count },

  methods: {
    subtract: payload => store.commit("subtract", +payload)
  }
};
</script>
درون کامپوننت اصلی برنامه App.vue، هر دو کامپوننت را فراخوانی میکنیم:
<template>
  <div id="app">
    <img alt="Vue logo" src="./assets/logo.png" />
    <counter-plus></counter-plus>
    <hr />
    <hr />
    <counter-minus></counter-minus>
  </div>
</template>

<script>
import counterPlus from "./components/increase-counter-component";
import counterMinus from "./components/decrease-counter-component";
export default {
  name: "app",
  components: {
    "counter-plus": counterPlus,
    "counter-minus": counterMinus
  }
};
</script>
محتویات فایل  store.js  که تنظیمات Vuex در آن لحاظ شده‌است به شکل زیر می‌باشد:
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  //  داده‌های به اشتراک گذاشته شده
  state: {
    count: 0
  },
  // تعریف متدها
  mutations: {
    add(state, payload) {
      // If we get a payload, add it to count
      // Else, just add one to count
      payload ? (state.count += payload) : state.count++;
    },
    subtract(state, payload) {
      payload ? (state.count -= payload) : state.count--;
    }
  }
});
در Terminal دستور زیر را تایپ و اجرا کنید تا نتیجه رویت گردد:
npm run serve
در این برنامه از دو کامپوننت مجزا با داده‌ی واحد، استفاده میکنیم و دیگر خبری از emit$ و on$ و EventBus و تزریق وابستگی نخواهد بود.

چگونه کار میکند؟

در Vuex، متدها در قسمت mutation در فایل store.js نوشته میشوند و در methods  درون کامپوننت‌ها فراخوانی میشوند. اگر با سی شارپ آشنا باشید، این فراخوانی تقریبا  شبیه delegate می‌باشد. داده‌ها در store.js تعریف میشوند و در سراسر برنامه در تمام کامپوننت‌ها قابل دسترس می‌باشند. بدین ترتیب اشتراک گذاری داده‌ها بین کامپوننت‌ها بسیار ساده می‌باشد.


نکته:    برای دریافت پکیج‌های مورد استفاده در مثال جاری، نیاز است دستور زیر را اجرا کنید:  
 
npm install
سپس برنامه را با دستور زیر اجرا کنید: 
npm run serve

مطالب
وادار کردن IIS به استفاده از ASP.Net 3.5

همانطور که مطلع هستید در تنظیمات یک دایرکتوری مجازی در IIS6 یا 5، حتی پس از نصب دات نت فریم ورک سه و نیم، گزینه انتخاب نگارش 3.5 ظاهر نمی‌شود و همان تنظیمات ASP.Net 2.0 کافی است (شکل زیر) (دات نت 3 و سه و نیم را می‌توان بعنوان افزونه‌هایی با مقیاس سازمانی (WF ، WCF و ...) برای دات نت 2 درنظر گرفت).




هنگام استفاده از VS.Net 2008 و تنظیم نوع پروژه به دات نت فریم ورک 3.5 ، به صورت خودکار تنظیمات لازم به وب کانفیگ برنامه جهت استفاده از کامپایلرهای مربوطه نیز اضافه می‌شوند که شاید از نظر دور بمانند.
برای آزمایش این مورد، فرض کنید صفحه زیر را بدون استفاده از code behind و VS.Net ایجاد کرده ایم (جهت آزمایش سریع یک قطعه کد Linq ).

<%@ Page Language="C#" %>

<%@ Import Namespace="System" %>
<%@ Import Namespace="System.Linq" %>

<form id="Form1" method="post" runat="server">
<asp:GridView ID="GridView1" runat="server" />
</form>


<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
string[] cities = {
"London", "Amsterdam", "San Francisco", "Las Vegas",
"Boston", "Raleigh", "Chicago", "Charlestown",
"Helsinki", "Nice", "Dublin"
};

GridView1.DataSource = from city in cities
where city.Length > 4
orderby city
select city.ToUpper();

GridView1.DataBind();
}
</script>

بلافاصله پس از اجرا با خطای زیر روبرو خواهیم شد.



این قطعه کد چون از قابلیت‌های کامپایلر جدید سی شارپ استفاده می‌کند، با کامپایلر پیش فرض و تنظیم شده دات نت 2 کار نخواهد کرد و باید برای رفع این مشکل، فایل web.config جدیدی را نیز به پوشه برنامه اضافه کنیم:

<?xml version="1.0"?>
<configuration>

<system.codedom>
<compilers>
<compiler language="c#;cs;csharp" extension=".cs" warningLevel="4" type="Microsoft.CSharp.CSharpCodeProvider, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<providerOption name="CompilerVersion" value="v3.5"/>
<providerOption name="WarnAsError" value="false"/>
</compiler>
</compilers>
</system.codedom>

<system.web>
<compilation defaultLanguage="c#">
<assemblies>
<add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
</assemblies>
</compilation>
</system.web>


</configuration>

در اینجا قید اسمبلی System.Core ضروری است و همچنین نگارش کامپایلر نیز به صورت صریح قید شده است تا IIS را وادار کند که از قابلیت‌های جدید دات نت فریم ورک استفاده نماید.

همانطور که ذکر شد اگر از VS.Net 2008 استفاده کنید، هیچ وقت درگیر این مباحث نخواهید شد و همه چیز از پیش تنظیم شده است.

مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت اول - نصب پیشنیازها
AngularJS یک فریم ورک جاوا اسکریپتی، برای ساخت برنامه‌های تک صفحه‌ای سمت کاربر، توسط HTML ،CSS و جاوا اسکریپت است. این فریم ورک، حاوی اجزایی برای data binding، طراحی ماژولار، کار با سرویس‌های سمت سرور وب و امثال آن است. Angular 2 بازنویسی کامل نگارش 1 آن است و اهداف زیر را دنبال می‌کند:
- سرعت بالاتر بارگذاری و اجرای کدها
- استفاده از آخرین فناوری‌های وب مانند ES 6 و وب کامپوننت‌ها با پشتیبانی تا IE 9.
- سطح API آن با طراحی جدید آن، به شدت کاهش یافته و خلاصه شده‌است. همین امر یادگیری آن‌را نیز ساده‌تر می‌کند.

برای یادگیری Angular 2 نیازی به فراگیری Angular 1 نیست. در اینجا با آشنایی با TypeScript، به این نتیجه خواهید رسید که برنامه‌های Angular 2 چیزی بیشتر از یک مثال عملی TypeScript نیستند. زبان TypeScript، زبان اول و توصیه شده‌ی کار با Angular 2 است و مزیت آن دسترسی به تمام قابلیت‌های ES 6 است؛ با این تفاوت که کامپایلر TypeScript قادر است آن‌ها را به ES 5 یا نگارش فعلی جاوا اسکریپت که توسط تمام مرورگرها پشتیبانی می‌شود، ترجمه و تبدیل کند. به این نحو به یک طراحی شیءگرا، مدرن و با قابلیت نگهداری بالا خواهید رسید که با تمام مرورگرهای جدید نیز سازگار است.
بنابراین پیشنیاز‌های اصلی کار با Angular 2، فراگیری ES 6 و TypeScript هستند که دو سری ویژه و مختص به آن‌ها در سایت جاری تهیه شده‌اند:
«مبانی ES 6»
«مبانی TypeScript»

در این قسمت قصد داریم پیشنیازهای دریافت و نصب اجزاء و وابستگی‌های AngularJS 2 را به همراه TypeScript، در ویژوال استودیو 2015 بررسی کنیم. البته استفاده از ویژوال استودیو در اینجا ضروری نیست و اساسا AngularJS وابستگی به ویژوال استودیو ندارد. اگر به دنبال پشتیبانی بهتری از TypeScript هستید، VSCode رایگان، سورس باز و چند سکویی، گزینه‌ی بسیار بهتری است نسبت به ویژوال استودیوی کامل. البته این مورد تعجبی هم ندارد؛ از این جهت که VSCode با TypeScript نوشته شده‌است.


اهمیت آشنایی با npm

اگر در طی سال‌های اخیر با ویژوال استودیو کار کرده باشید، به طور قطع با NuGet نیز آشنا هستید. NuGet به عنوان یک package manager دات نتی شناخته می‌شود و کار آن دریافت وابستگی‌های یک پروژه، از مخزنی مشخص و نصب و به روز رسانی خودکار آن‌ها است. اما این روزها خارج از محیط توسعه‌ی مایکروسافت، مدیرهای بسته‌های دیگری مانند Bower نیز برای نصب و به روز رسانی بسته‌های front end مانند کتابخانه‌های CSS ایی و جاوا اسکریپتی، بسیار رواج پیدا کرده‌اند. Bower یکی از ابزارهای NodeJS است که توسط NPM یا NodeJS Package Manager نصب می‌شود. به این معنا که استفاده از Bower به معنای استفاده از NPM است. پیش از این از NPM صرفا جهت نصب بسته‌های مرتبط با NodeJS استفاده می‌شد، اما در طی یکسال اخیر، استفاده از NPM نیز برای مدیریت بسته‌های front end رواج پیدا کرده‌است و در صدر مدیر بسته‌های نصب کتابخانه‌های front end قرار دارد. همچنین در این حالت شما تنها نیاز به یک ابزار و یک فایل تنظیمات آن خواهید داشت، بجای استفاده از چندین ابزار و چندین فایل تنظیمات جداگانه. به علاوه این روزها انجام کارهای جدی جاوا اسکریپتی بدون دانش NPM دیگر میسر نیست. بهترین ابزارها، کامپایلرها، فشرده کننده‌های front end و امثال آن‌ها، تحت NodeJS اجرا می‌شوند. برای کار با AngularJS 2.0 و دریافت وابستگی‌های آن نیز استفاده از npm، روش پیش فرض و توصیه شده‌است.


کار با npm جهت دریافت وابستگی‌های کتابخانه‌های front end

برای کار با npm یا می‌توان از دستورات خط فرمان آن به صورت مستقیم استفاده کرد و یا از امکانات یکپارچگی آن با ویژوال استودیو نیز بهره گرفت که ما در ادامه از این روش استفاده خواهیم کرد. البته توانمندی‌های خط فرمان npm فراتر است از امکانات توکار VS.NET، اما در اینجا نیازی به آن‌ها نیست و هدف صرفا دریافت و به روز رسانی وابستگی‌های مرتبط است.
ویژوال استودیوی 2015 به همراه ابزارهای NodeJS ارائه می‌شود. اما مشکل اینجا است که این ابزارها هم اکنون قدیمی شده‌اند و تطابقی با آخرین نگارش ابزارهای NodeJS ندارند. برای نمونه حین نصب وابستگی‌‌های AngularJS 2.0 که یکی از آن‌ها RxJS است، یک چنین خروجی را در پنجره‌ی output ویژوال استودیو مشاهده می‌کنید:
 npm WARN engine rxjs@5.0.0-beta.6: wanted: {"npm":">=2.0.0"} (current: {"node":"v0.10.31","npm":"1.4.9"})
به این معنا که نگارش‌های اخیر RxJS نیاز به npm با نگارشی بیشتر از 2 را دارند؛ اما نگارش npm پیش فرض ویژوال استودیو 1.4.9 است (البته باید دقت داشت که من به روز رسانی دوم VS 2015 را هم نصب کرده‌ام). برای رهایی از این مشکل، تنها کافی است تا به ویژوال استودیو اعلام کنیم از نسخه‌ی اصلی خط فرمان npm، بجای نسخه‌ی پیش فرض خودش استفاده کند:


همانطور که در تصویر نیز ملاحظه می‌کنید، به مسیر Tools->Options->Projects and Solutions->External Web Tools مراجعه کرده و متغیر محیطی PATH ویندوز را به ابتدای لیست منتقل کنید. به این صورت ابزارهای به روز شده‌ی خط فرمان، مقدم خواهند شد بر ابزارهای قدیمی به همراه نگارش فعلی ویژوال استودیو.

البته فرض بر این است که آخرین نگارش nodejs را از آدرس https://nodejs.org/en دریافت و نصب کرده‌اید. با نصب آن، برنامه npm، در خط فرمان ویندوز به صورت مستقیم قابل استفاده خواهد بود؛ از این جهت که مسیر آن به PATH ویندوز اضافه شده‌است:



افزودن فایل project.json به پروژه

تا اینجا فرض بر این است که nodejs را از سایت آن دریافت و نصب کرده‌اید. همچنین متغیر PATH را در External Web Tools ویژوال استودیو به ابتدای لیست آن منتقل کرده‌اید تا همواره از آخرین نگارش npm نصب شده‌ی در سیستم، استفاده شود.
پس از آن همانند نیوگت که از فایل xml ایی به نام packages.config برای ثبت آخرین تغییرات خودش استفاده می‌کند، npm نیز از فایلی به نام package.json برای ذکر وابستگی‌های مورد نیاز پروژه بهره می‌برد. برای افزودن آن، از منوی Project گزینه‌ی Add new item را انتخاب کرده و سپس npm را در آن جستجو کنید:


در اینجا نام پیش فرض package.json را پذیرفته و این فایل را به پروژه و ریشه‌ی آن اضافه کنید.
اگر گزینه‌ی فوق را در لیست Add new item مشاهده نمی‌کنید، مهم نیست. یک فایل متنی را به نام package.json به ریشه‌ی پروژه‌ی جاری اضافه کنید.
در ادامه محتوای این فایل را به نحو ذیل تغییر دهید:
{
    "name": "asp-net-mvc5x-angular2x",
    "version": "1.0.0",
    "author": "DNT",
    "description": "",
    "scripts": {},
    "license": "Apache-2.0",
    "dependencies": {
        "jquery": "2.2.3",
        "angular2": "2.0.0-beta.15",
        "systemjs": "^0.19.26",
        "es6-promise": "^3.1.2",
        "es6-shim": "^0.35.0",
        "reflect-metadata": "0.1.2",
        "rxjs": "5.0.0-beta.2",
        "zone.js": "^0.6.12",
        "bootstrap": "^3.3.6"
    },
    "devDependencies": {
        "typescript": "^1.8.9",
        "typings": "^0.8.1"
    },
    "repository": {
    }
}
این فایل تنظیمات، سبب بارگذاری خودکار وابستگی‌های مورد نیاز AngularJS 2.0 در ویژوال استودیو می‌شود.

چند نکته:
- هر زمانیکه این فایل را ذخیره کنید، بلافاصله کار دریافت این بسته‌ها از اینترنت آغاز خواهد شد. جزئیات آن‌را می‌توان در پنجره‌ی output ویژوال استودیو مشاهده کرد (و حتما این‌کار را جهت دیباگ کار انجام دهید. بسیاری از مشکلات و خطاها، در اینجا لاگ می‌شوند). بنابراین اگر قصد دارید کار همگام سازی تغییرات را انجام دهید، فقط کافی است دکمه‌های ctrl+s یا save را بر روی این فایل اعمال کنید.
- کاری که دکمه‌ی ctrl+s در این فایل انجام می‌دهد، اعمال خودکار دستور npm install بر روی پوشه‌ای است که package.json در آن قرار دارد. بنابراین برای دریافت این بسته‌ها، روش خط فرمان آن، ابتدا وارد شدن به ریشه‌ی پروژه‌ی جاری و سپس صدور دستور npm install است (که نیازی به آن نیست و ویژوال استودیو این‌کار را به صورت خودکار انجام می‌دهد).
- بسته‌های دریافت شده، در پوشه‌ای به نام node_modules در ریشه‌ی پروژه ذخیره می‌شوند:


برای مشاهده‌ی آن‌ها می‌توان بر روی دکمه‌ی show all files در solution explorer کلیک نمائید.

- درون فایل package.json، پشتیبانی کاملی از intellisense وجود دارد. برای مثال اگر علاقمند بودید تا آخرین نگارش AngularJS را مشاهده کنید، پس از خاصیت angular2 در تنظیمات فوق، " را تایپ کنید تا منوی تکمیل کننده‌ای ظاهر شود:


بدیهی است این منو جهت دریافت آخرین اطلاعات، نیاز به اتصال به اینترنت را دارد.

البته همیشه آخرین شماره نگارش AngularJS 2.0 را در این آدرس نیز می‌توانید مشاهده کنید: CHANGELOG.md

- در این فایل شماره نگارش آغاز شده‌ای با ^ مانند "3.1.2^" به این معنا است که اجازه‌ی نصب نگارش‌های جدیدتری از 3.1.2 نیز داده شده‌است.


به روز رسانی کامپایلر TypeScript

نیاز است یکبار مطلب «مبانی TypeScript؛ تنظیمات TypeScript در ویژوال استودیو» را جهت آشنایی با نحوه‌ی به روز رسانی اجزای مرتبط با TypeScript مطالعه کنید.


افزودن فایل tsconfig.json به پروژه

مرحله‌ی بعد شروع به کار با AngularJS و TypeScript، انجام تنظیمات کامپایلر TypeScript است. برای این منظور از منوی پروژه، گزینه‌ی Add new item، عبارت typescript را جستجو کرده و در لیست ظاهر شده، گزینه‌ی TypeScript JSON Configuration File را با نام پیش فرض آن انتخاب کنید:


اگر این گزینه‌ی ویژه را در لیست add new items ندارید، مهم نیست. یک فایل متنی را به نام tsconfig.json به ریشه‌ی پروژه‌ی جاری اضافه کنید.
پس از افزودن فایل tsconfig.json به ریشه‌ی سایت، تنظیمات آن‌را به نحو ذیل تغییر دهید:
{
    "compileOnSave": true,
    "compilerOptions": {
        "target": "es5",
        "module": "system",
        "moduleResolution": "node",
        "noImplicitAny": false,
        "noEmitOnError": true,
        "removeComments": false,
        "sourceMap": true,
        "emitDecoratorMetadata": true,
        "experimentalDecorators": true
    },
    "exclude": [
        "node_modules",
        "wwwroot",
        "typings/main",
        "typings/main.d.ts"
    ]
}
در مورد جزئیات این تنظیمات در سری «مبانی TypeScript» و «تنظیمات کامپایلر TypeScript» بیشتر بحث شده‌است. فایل ویژه‌ی tsconfig.json تنظیمات پیش فرض ویژوال استودیو را جهت کار با TypeScript بازنویسی می‌کند. بنابراین زمانیکه از این فایل استفاده می‌شود، دیگر نیازی نیست به گزینه‌ی مختلف پروژه، جهت تنظیم TypeScript مراجعه کرد.
برای نمونه خاصیت compileOnSave سبب خواهد شد تا پس از ذخیره سازی یک فایل ts، بلافاصله فایل js معادل آْن تولید شود. نوع ماژول‌ها در اینجا به system.js تنظیم شده‌است و خروجی کدهای js آن از نوع ES 5 درنظر گرفته شده‌است. همچنین فعال سازی decorators نیز در اینجا صورت گرفته‌است. از این جهت که AngularJS2 استفاده‌ی گسترده‌ای را از این مفهوم، انجام می‌دهد.
در قسمت excludes به کامپایلر TypeScript اعلام شده‌است تا از یک سری از مسیرها مانند پوشه‌ی node_modules که پیشتر آن‌را تنظیم و دریافت کردیم، صرفنظر کند.


خلاصه‌ی بحث

تا اینجا با نحوه‌ی نصب پیشنیازهای AngularJS 2 و همچنین TypeScript آشنا شدیم. به صورت خلاصه:
- nmp اصلی را از سایت nodejs دریافت و نصب کنید.
- متغیر PATH را در ویژوال استودیو، به ابتدای لیست ابزارهای خارجی وب آن منتقل کنید تا از npm اصلی استفاده کند.
- فایل project.json را با محتوای ذکر شده، به ریشه‌ی پروژه اضافه کنید. سپس یکبار آن‌را save کنید تا وابستگی‌ها را از اینترنت دریافت کند.
- اطمینان حاصل کنید که آخرین کامپایلر TypeScript را نصب کرده‌اید.
- فایل tsconfig.json را با محتوای ذکر شده، به ریشه‌ی پروژه اضافه کنید.
مطالب
جلوگیری از ورود نام Area های یکسان، در هنگام درج اطلاعات در برنامه‌های ASP.NET MVC 5x
در وب‌سایتی مثل آپارات، چنین آدرسی aparat.com/reporting به منزله‌ی آدرس دهی به کانال شخصیِ فردی است. حال اگر وب‌سایت ما نیز چنین سیستم آدرس دهی را داشته باشد و همچنین پیشتر یک Area با نام Reporting را نیز داشته باشیم، توسط چنین آدرسی (درحالت پیش فرض) به آن Area دسترسی خواهیم داشت:
mysite.com/reporting
حال اگر یکی از کاربران هنگام ساخت کانالی جدید (برای سناریوی بالا)، بخواهد آدرس کانالش Reporting باشد، با توجه به اینکه هم مسیر دسترسی به Area گزارشات (Reporting) و هم مسیر دسترسی به کانال این شخص از طریق Url بالا است، قطعا به مشکل خواهیم خورد.
برای رفع این مشکل میتوان یک فایل xml، txt و ... درست کرد و نام تمامی Area‌‌ها را در آن فایل ثبت کرد و بعد، هنگام ثبت کانال جدید (برای سناریوی بالا) توسط کاربر، فایل مذکور را خوانده و در صورتیکه نام آدرس وارد شده معادل یکی از Area‌‌های سایتمان بود و در لیست Area‌‌های از پیش ثبت شده در آن فایل قرار داشت، پیغام لازم را به کاربر نشان می‌دهیم و از ثبت و یا ویرایش اطلاعات، جلوگیری می‌کنیم.
روش فوق به درستی کار می‌کند و مشکلی ندارد، اما ضعف آن این است که به صورت دستی این عملیات باید انجام شود و در صورتیکه یک Area جدید اضافه شود، باید آن فایل ویرایش شود. اما می‌توان با استفاده از یک Attribute، این کار را انجام و تمامی عملیات را به صورت داینامیک انجام داد.
برای شروع، یک مدل برای کانال و یک منبع داده را برای آن در نظر می‌گیریم:
using System.ComponentModel.DataAnnotations;

namespace SampleProject.Models
{
    public class Channel
    {
        public string ChannelTitle { get; set; }
        [Required]
        public string ChannelUrl { get; set; }
    }
}
using System.Collections.Generic;

namespace SampleProject.Models
{
    public static class ChannelDataSource
    {
        static ChannelDataSource() => Channels = new List<Channel>();
        public static List<Channel> Channels { get; private set; }
        public static void Add(Channel channel) => Channels.Add(channel);
    }
}
منبع داده، شامل یک خاصیت است که لیست تمامی کانال‌های از قبل اضافه شده را بر می‌گرداند و یک متد افزودن که به این لیست، یک کانال را اضافه می‌کند.
حال یک کنترلر به نام Channel را اضافه می‌کنیم:
using SampleProject.Models;
using System.Linq;
using System.Web.Mvc;

namespace SampleProject.Controllers
{
    public class ChannelController : Controller
    {
        // GET: Channel
        public ActionResult Index()
        {
            var channels = ChannelDataSource.Channels;
            return View(channels);
        }

        public ActionResult Channel(string channelUrl)
        {
            if (string.IsNullOrWhiteSpace(channelUrl))
            {
                return new HttpNotFoundResult("channel not found!");
            }
            var channel = ChannelDataSource.Channels.SingleOrDefault(ch => ch.ChannelUrl == channelUrl.ToLower());
            if (channel == null)
            {
                return new HttpNotFoundResult("channel not found!");
            }
            return View(channel);
        }

        public ActionResult Create() => View();

        [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(Channel channel)
        {
            if (!ModelState.IsValid)
            {
                ModelState.AddModelError(string.Empty, "Please check your inputs!");
                return View(channel);
            }
            ChannelDataSource.Add(channel);
            TempData["Message"] = "Channel added successfully!";
            return RedirectToAction(nameof(Index));
        }
    }
}
در اکشن Index، لیستی از تمامی کانال‌های موجود را نمایش می‌دهیم. در اکشن Channel، آدرسی را که وارد شده است، در منبع داده به دنبال آن می‌گردیم و یک ویوو با Template جزئیات (Details)، از مدل کانال را به کاربر نمایش می‌دهیم؛ در غیر اینصورت صفحه 404 را نمایش می‌دهیم. در اکشن‌های Create، صفحه افزودن را به کاربر نمایش داده و در آن یکی اکشن، عمل افزودن را در صورتیکه اطلاعات وارد شده صحیح باشند، انجام می‌دهیم.
با توجه به اینکه میخواهیم سیستم مسیر دهی سایت برای کانال‌ها تغییر کند، فایل RouteConfig در پوشه‌ی App_Start را به شکل ذیل تغییر می‌دهیم:
using System.Web.Mvc;
using System.Web.Routing;

namespace SampleProject
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "ChannelUrls",
                url: "{channelurl}",
                defaults: new { controller = "Channel", action = "Channel", id = UrlParameter.Optional }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Channel", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}
در مسیر دهی بالا اگر "نام سایت، اسلش، نام کانال" را وارد کند اولین سیستم مسیریابی فعال می‌شود و او را به اکشن Channel کنترلر Channel، راهنمایی می‌کند.
حال برای اینکه هنگام ساخت کانال جدید، نام تکراری یکی از Area‌ها را وارد نکند، به این ترتیب عمل می‌کنیم:
ابتدا یک متد کمکی را نوشته که لیست Area‌‌های پروژه‌مان را برگشت دهد ( + ):
using System.Collections.Generic;
using System.Linq;
using System.Web.Routing;

namespace SampleProject.Models
{
    public static class Utility
    {
        public static List<string> GetAllAreaNames()
        {
            var areaNames = RouteTable.Routes.OfType<Route>()
                            .Where(d => d.DataTokens != null)
                            .Where(d=> d.DataTokens.ContainsKey("area"))
                            .Select(r => r.DataTokens["area"].ToString().ToLower())
                            .ToList();
            return areaNames;
        }
    }
}
و بعد Attribute مورد نظر را ایجاد میکنیم:
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web.Mvc;
using SampleProject.Models;

namespace SampleProject.CustomValidators
{
    public class CheckForAreaExisting : ValidationAttribute, IClientValidatable
    {
        public List<string> AreaNames
        {
            get
            {
                return Utility.GetAllAreaNames();
            }
        }
        public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            var rule = new ModelClientValidationRule
            {
                ValidationType = "checkforareaexisting",
                ErrorMessage = FormatErrorMessage(metadata.GetDisplayName())
            };
            rule.ValidationParameters.Add("areanames", string.Join(",", AreaNames));
            yield return rule;
        }

        public override bool IsValid(object value)
        {
            if (value != null)
            {
                return Utility.GetAllAreaNames()
                   .SingleOrDefault(area => area == value.ToString().ToLower()) == null;
            }
            return true;
        }
    }
}
در کلاس بالا توسط متد IsValid بررسی میکنیم که آیا مقدار وارد شده ( Channel Url ) با یکی از نام‌های Area‌‌های پروژه‌مان تطابق دارد یا خیر، که اگر این چنین بود، مقدار false برگشت داده می‌شود.
توسط واسط IClientValidatable و متود GetClientValidationRules کارهای اعتبارسنجی سمت کلاینت را نیز انجام می‌دهیم ( + ). مقدار خاصیت ValidationType نام متدی است که در سمت کلاینت این کار را انجام می‌دهد. مقدار خاصیت ValidationParameters، مقداری است که به سمت کلاینت به عنوان param فرستاده می‌شود تا از آن جهت اینکه آیا مقدار وارد شده توسط کاربر، یکی از Area‌های سایت هست یا خیر، استفاده کرد. در اینجا نام Area‌‌‌ها را با یک رشته و با یک جداکننده، توسط این خاصیت به سمت کلاینت می‌فرستیم. 
حال در سمت کلاینت یک فایل Js را با نام CustomValidation و محتوای زیر ایجاد می‌کنیم:
jQuery.validator.addMethod("checkforareaexisting",
    function (value, element, param) {
        var isValueOneOfTheAreaNames = $.inArray(value.toLowerCase(), param.areaNames) === -1;
        return isValueOneOfTheAreaNames;
    });

$.validator.unobtrusive.adapters.add('checkforareaexisting', ['areanames'], function (options) {
    options.rules['checkforareaexisting'] = { areaNames: options.params.areanames.split(',') };
    options.messages['checkforareaexisting'] = options.message;
});
در بخش اول، نام متد که در بالا (Attribute) به آن اشاره شده است آمده است، و بعد بررسی می‌کنیم که آیا مقدار آمده توسط کاربر، یکی از نام‌های Area‌‌های موجود سایت است یا خیر که اگر این طور باشد، false برگشت داده می‌شود و پیغام خطا به کاربر نمایش داده می‌شود. در بخش Onubtrusive توسط پارامتری که در Attribute برای فرستادن نام Area‌ها نوشته بودیم (areanames)، نام‌های Area‌ها را می‌گیریم و بعد آن را Split و به Rule انتساب می‌دهیم و ErrorMessage ـی را که به خاصیت ChannelUrl مدلمان نسبت می‌دهیم، به عنوان پیغام خطا در نظر می‌گیریم.
فایل‌های Js در Layout باید به این صورت باشند:
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>_Layout</title>
    <style>

    </style>
</head>
<body>
    <div>
        @RenderBody()
    </div>
    <script src="~/Scripts/Jquery.js"></script>
    <script src="~/Scripts/jquery.validate.min.js"></script>
    <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
    <script src="~/Scripts/CustomValidation.js"></script>
</body>
</html>

حال کافی است به خاصیت ChannelUrl مدلمان این Attribute را نسبت دهیم:
using SampleProject.CustomValidators;
using System.ComponentModel.DataAnnotations;

namespace SampleProject.Models
{
    public class Channel
    {
        public string ChannelTitle { get; set; }
        [Required]
        [CheckForAreaExisting(ErrorMessage = "You can't use this url for your channel!")]
        public string ChannelUrl { get; set; }
    }
}
اکنون نوبت آزمایش برنامه است. کافی است که یک یا چند Area جدید را با نام‌های متفاوت، اضافه کنید و الان اگر به صفحه افزودن کانال مراجعه کنید و نام یکی از Area‌‌های سایت را در قسمت Channel Url وارد کنید، پیغام خطا نمایش داده می‌شود.
نکته: در این حالت اسامی تمامی Area‌‌های سایت به کلاینت ارسال می‌شود. اگر از این بابت احساس رضایت نمی‌کنید، میتوانید از خاصیت Remote توکار MVC بهره ببرید.
برای اینکار این اکشن را به کنترلر Channel اضافه می‌کنیم:
[HttpPost]
public ActionResult CheckForAreaExisting(string channelUrl)
{
    var isValueOneOfTheAreaNames = Utility.GetAllAreaNames()
                                   .SingleOrDefault(area => area == channelUrl.ToLower()) == null;
    return Json(isValueOneOfTheAreaNames);
}  
و بعد مدل نیز به این صورت تغییر می‌کند:
using System.ComponentModel.DataAnnotations;
using System.Web.Mvc;

namespace SampleProject.Models
{
    public class Channel
    {
        public string ChannelTitle { get; set; }
        [Required]
        [Remote("CheckForAreaExisting", "Channel",
            ErrorMessage = "You can't use this url for your channel!",
            HttpMethod = "Post")]
        public string ChannelUrl { get; set; }
    }
}
به این ترتیب هر بار درخواستی به سمت سرور ارسال و طی آن بررسی می‌شود که مقدار وارد شده یکی از Area‌‌‌‌های سایت هست یا خیر؟ بدیهی است که در این حالت، دیگر نیازی به واسط IClientValidatable در کلاس CheckForAreaExisting موجود در پوشه CustomValidators وجود ندارد.
مطالب
گرفتن خروجی XML از جداول در SQL Server 2012
فرض کنید که می‌خواهیم خروجی از جدول خود را به صورت XML نمایش یا از طریق وب سرویس در برنامه مان استفاده نماییم. اولین راهی که به ذهنمان می‌رسد خودمان  رشته xml را با حلقه ای ایجاد نماید یا استفاده از فضای نام System.Xml و کلاس‌های نوشته شده برای این کار . اما خود Sql Server امکانات ویژه ای برای کار با ساختار xml مهیا نموده که براحتی می‌توانید خروجی xml از داده هایتان ایجاد نمایید.

برای این کار از عبارت For XML در Select می‌توان استفاده نمود. برای مثال برای بدست آوردن ساختار ساده از For Xml Auto استفاده نمایید
SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName
FROM Person
WHERE BusinessEntityID = 10001
FOR XML AUTO
که خروجی بصورت node attribute زیر می‌باشد:

اما اگر بخواهیم خروجی به صورت node Elements باشد کافیست از پارامتر Elements استفاده نمایید 

SELECT BusinessEntityID, PersonType, Title, FirstName, MiddleName, LastName
FROM Person
WHERE BusinessEntityID = 10001
FOR XML AUTO, ELEMENTS

خروجی بصورت زیر می‌باشد:

اگر بخواهیم node attributes و node elements با هم ترکیب کنیم بصورت زیر عمل می‌کنیم:

SELECT BusinessEntityID AS '@ID', PersonType, Title,  FirstName, MiddleName, LastName
FROM Person
WHERE BusinessEntityID = 10001
FOR XML ELEMENTS

خروجی بصورت زیر است:

حال می‌خواهیم همه node‌ها را یک node ریشه قرار دهیم برای این کار از پارامتر ROOT در کنار AUTO به صورت زیر استفاده نمایید:

SELECT *
FROM Person
WHERE BusinessEntityID = 15291
FOR XML AUTO , ROOT('Persons')

اما اگر بخواهیم نام جدول را با نام دلخواه خود تغییر دهیم از پارامتر PATH به جای  AUTO به صورت زیر استفاده نمایید:

SELECT *
FROM Person
WHERE BusinessEntityID = 15291
FOR XML PATH('P') , ROOT('Persons')