مطالب
استفاده از LocalDb در IIS، قسمت دوم: مالکیت وهله ها
در قسمت قبلی این مقاله گفتیم که دو خاصیت از LocalDb هنگام استفاده از Full IIS باعث بروز خطا می‌شوند:

  • LocalDb نیاز دارد که پروفایل کاربر بارگذاری شده باشد
  • بصورت پیش فرض وهله LocalDb متعلق به یک کاربر بوده، و خصوصی است

در قسمت قبل دیدیم چگونه باید پروفایل کاربر را بدرستی بارگذاری کنیم. در این مقاله به مالکیت وهله‌ها (instance ownership) می‌پردازیم.


مشکل وهله خصوصی

در پایان قسمت قبلی، اپلیکیشن وب را در این حالت رها کردیم:

همانطور که مشاهده می‌کنید با خطای زیر مواجه هستیم:

System.Data.SqlClient.SqlException: Cannot open database "OldFashionedDB" requested by the login. The login failed.
Login failed for user 'IIS APPPOOL\ASP.NET v4.0'. 

این بار پیغام خطا واضح و روشن است. LocalDb با موفقیت اجرا شده و اپلیکیشن وب هم توانسته به آن وصل شود، اما این کانکشن سپس قطع شده چرا که دسترسی به وهله جاری وجود نداشته است. اکانت ApplicationPoolIdentity (در اینجا IIS APPPOOL\ASP.NET v4.0) نتوانسته به دیتابیس LocalDb وارد شود، چرا که دیتابیس مورد نظر در رشته اتصال اپلیکیشن (OldFashionedDB) وجود ندارد. عجیب است، چرا که وصل شدن به همین دیتابیس با رشته اتصال جاری در ویژوال استودیو با موفقیت انجام می‌شود.

همانطور که در تصویر بالا مشاهده می‌کنید از ابزار SQL Server Object Explorer استفاده شده است. این ابزار توسط SQL Server Data Tools معرفی شد و در نسخه‌های بعدی ویژوال استودیو هم وجود دارد و توسعه یافته است. چطور ممکن است ویژوال استودیو براحتی بتواند به دیتابیس وصل شود، اما اپلیکیشن وب ما با همان رشته اتصال نمی‌تواند دیتابیس را باز کند؟ در هر دو صورت رشته اتصال ما بدین شکل است:

Data Source=(localdb)\v11.0;Initial Catalog=OldFashionedDB;Integrated Security=True

پاسخ این است که در اینجا، دو وهله از LocalDb وجود دارد. بر خلاف وهله‌های SQL Server Express که بعنوان سرویس‌های ویندوزی اجرا می‌شوند، وهله‌های LocalDb بصورت پروسس‌های کاربری (user processes) اجرا می‌شوند. هنگامی که کاربران مختلفی سعی می‌کنند به LocalDb متصل شوند، برای هر کدام از آنها پروسس‌های مجزایی اجرا خواهد شد. هنگامی که در ویژوال استودیو به localdb)\v11.0) وصل می‌شویم، وهله ای از LocalDb ساخته شده و در حساب کاربری ویندوز جاری اجرا می‌شود. اما هنگامی که اپلیکیشن وب ما در IIS می‌خواهد به همین دیتابیس وصل شود، وهله دیگری ساخته شده و در ApplicationPoolIdentity اجرا می‌شود. گرچه ویژوال استودیو و اپلیکیشن ما هر دو از یک رشته اتصال استفاده می‌کنند، اما در عمل هر کدام به وهله‌های متفاوتی از LocalDb دسترسی پیدا خواهند کرد. پس مسلما دیتابیسی که توسط وهله ای در ویژوال استودیو ساخته شده است، برای اپلیکیشن وب ما در IIS در دسترس نخواهد بود.

یک مقایسه خوب از این وضعیت، پوشه My Documents در ویندوز است. فرض کنید در ویژوال استودیو کدی بنویسیم که در این پوشه یک فایل جدید می‌سازد. حال اگر با حساب کاربری دیگری وارد ویندوز شویم و به پوشه My Documents برویم این فایل را نخواهیم یافت. چرا که پوشه My Documents برای هر کاربر متفاوت است. بهمین شکل، وهله‌های LocalDb برای هر کاربر متفاوت است و به پروسس‌ها و دیتابیس‌های مختلفی اشاره می‌کنند.

به همین دلیل است که اپلیکیشن وب ما می‌تواند بدون هیچ مشکلی روی IIS Express اجرا شود و دیتابیس را باز کند. چرا که IIS Express درست مانند LocalDb یک پروسس کاربری است. IIS Express توسط ویژوال استودیو راه اندازی می‌شود و روی حساب کاربری جاری اجرا می‌گردد، پس پروسس آن با پروسس خود ویژوال استودیو یکسان خواهد بود و هر دو زیر یک اکانت کاربری اجرا خواهند شد.


راه حل ها

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


رویکرد 1: اجرای IIS روی کاربر جاری ویندوز

اگر مشکل، حساب‌های کاربری مختلف است، چرا خود IIS را روی کاربر جاری اجرا نکنیم؟ در این صورت ویژوال استودیو و اپلیکیشن ما هر دو به یک وهله از LocalDb وصل خواهند شد و همه چیز بدرستی کار خواهد کرد. ایجاد تغییرات لازم نسبتا ساده است. IIS را اجرا کنید و Application Pool مناسب را انتخاب کنید، یعنی همان گزینه که برای اپلیکیشن شما استفاده می‌شود.

قسمت Advanced Settings را باز کنید:

روی دکمه سه نقطه کنار خاصیت Identity کلیک کنید تا پنجره Application Pool Identity باز شود:

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

خوب، معایب این رویکرد چیست؟ مسلما اجرای اپلیکیشن وب روی اکانت کاربری جاری، ریسک‌های امنیتی متعددی را معرفی می‌کند. اگر کسی بتواند اپلیکیشن وب ما را هک کند، به تمام منابع سیستم که اکانت کاربری جاری به آنها دسترسی دارد، دسترسی خواهد داشت. اما اجرای اپلیکیشن مورد نظر روی ApplicationPoolIdentity امنیت بیشتری را ارائه می‌کند، چرا که اکانت‌های ApplicationPoolIdentity دسترسی بسیار محدود‌تری به منابع سیستم محلی دارند. بنابراین استفاده از این روش بطور کلی توصیه نمی‌شود، اما در سناریو‌های خاصی با در نظر داشتن ریسک‌های امنیتی می‌تواند رویکرد خوبی باشد.


رویکرد 2: استفاده از وهله مشترک

یک راه حال دیگر استفاده از قابلیت instance sharing است. این قابلیت به ما این امکان را می‌دهد تا یک وهله LocalDb را بین کاربران یک سیستم به اشتراک بگذاریم. وهله به اشتراک گذاشته شده، توسط یک نام عمومی (public name) قابل دسترسی خواهد بود.

ساده‌ترین راه برای به اشتراک گذاشتن وهله‌های LocalDb استفاده از ابزار SqlLocalDB.exe است. بدین منظور Command Prompt را بعنوان مدیر سیستم باز کنید و فرمان زیر را اجرا نمایید:

sqllocaldb share v11.0 IIS_DB
این فرمان وهله خصوصی LocalDb را با نام عمومی IIS_DB به اشتراک می‌گذارد. حال تمام کاربران سیستم می‌توانند با آدرس localdb)\.\IIS_DB) به این وهله وصل شوند. این فرمت آدرس دهی سرور دیتابیس، مشخص می‌کند که از یک وهله shared استفاده می‌کنیم. رشته اتصال جدید مانند لیست زیر خواهد بود:

Data Source=(localdb)\.\IIS_DB;Initial Catalog=OldFashionedDB;Integrated Security=True

پیش از آنکه اپلیکیشن وب ما بتواند به این وهله متصل شود، باید لاگین‌های مورد نیاز برای ApplicationPoolIdentity را ایجاد کنیم. راه اندازی وهله ساده است، کافی است دیتابیس را در SQL Server Object Explorer باز کنید. این کار اتصالی به دیتابیس برقرار می‌کند و آن را زنده نگاه می‌دارد. برای ایجاد لاگین مورد نظر، می‌توانیم در SQL Server Object Explorer یک کوئری اجرا کنیم:

create login [IIS APPPOOL\ASP.NET v4.0] from windows;
exec sp_addsrvrolemember N'IIS APPPOOL\ASP.NET v4.0', sysadmin

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

معایب این روش چیست؟ مشکل اصلی در این رویکرد این است که پیش از آنکه اپلیکیشن ما بتواند به وهله مشترک دسترسی داشته باشد، باید وهله مورد نظر را راه اندازی و اجرا کنیم. بدین منظور، حساب کاربری ویندوزی که مالکیت وهله را دارد باید به آن وصل شود و کانکشن را زنده نگه دارد، در غیر اینصورت وهله LocalDb قابل دسترسی نخواهد بود.


رویکرد 3: استفاده از SQL Server Express

از آنجا که نسخه کامل SQL Server Express بعنوان یک سرویس ویندوزی اجرا می‌شود، شاید بهترین راه استفاده از همین روش باشد. کافی است یک نسخه از SQL Server Express را نصب کنیم، دیتابیس مورد نظر را در آن بسازیم و سپس به آن متصل شویم. برای این کار حتی می‌توانید از ابزار جدید SQL Server Data Tools استفاده کنید، چرا که با تمام نسخه‌های SQL Server سازگار است. در صورت استفاده از نسخه‌های کامل تر، رشته اتصال ما بدین شکل تغییر خواهد کرد:

Data Source=.\SQLEXPRESS;Initial Catalog=OldFashionedDB;Integrated Security=True
مسلما در این صورت نیز، لازم است اطمینان حاصل کنیم که ApplicationPoolIdentity به وهله SQL Server Express دسترسی کافی دارد. برای این کار می‌توانیم از اسکریپت قبلی استفاده کنیم:

create login [IIS APPPOOL\ASP.NET v4.0] from windows;
exec sp_addsrvrolemember N'IIS APPPOOL\ASP.NET v4.0', sysadmin

حال اجرای مجدد اپلیکیشن باید با موفقیت انجام شود. استفاده از این روش مسلما امکان استفاده از LocalDb را از ما می‌گیرد. ناگفته نماند که وهله‌های SQL Server Express همیشه در حال اجرا خواهند بود چرا که بصورت سرویس‌های ویندوزی اجرا می‌شوند. همچنین استفاده از این روش ممکن است شما را با مشکلاتی هم مواجه کند. مثلا خرابی رجیستری ویندوز می‌تواند SQL Server Express را از کار بیاندازد و مواردی از این دست. راهکار‌های دیگری هم وجود دارند که در این مقاله به آنها نپرداختیم. مثلا می‌توانید از AttachDbFilename استفاده کنید یا از اسکریپت‌های T-SQL برای استفاده از وهله خصوصی ASP.NET کمک بگیرید. اما این روش‌ها دردسر‌های زیادی دارند، بهمین دلیل از آنها صرفنظر کردیم.


مطالعه بیشتر درباره LocalDb

نظرات مطالب
کار با Docker بر روی ویندوز - قسمت دوم - نصب Docker
سلام، 
من Docker ورژن 2.4 را روی Windows 10 Enterprise LTSC ورژن 1809 نصب کردم، متاسفانه پیش فرض روی Container Linux قرار می‌گیره، هر وقت بخوام Switch کنم روی Container Windows با خطا مواجه می‌شم، خطایی که در Event Viewer ویندوز می‌بینم، به شرح زیر :
failed to start daemon: Error initializing network controller: Error creating default network: failed during hnsCallRawResponse: hnsCall failed in Win32: There are no more endpoints available from the endpoint mapper. (0x6d9) 
مشخصات کامپیوتر من، 
Ram: 32 G
CPU: 7i-8565U
مشخصات داکر:
Client: Docker Engine - Community
 Cloud integration  0.1.18
 Version:           19.03.13
 API version:       1.40
 Go version:        go1.13.15
 Git commit:        4484c46d9d
 Built:             Wed Sep 16 17:00:27 2020
 OS/Arch:           windows/amd64
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          19.03.13
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.13.15
  Git commit:       4484c46d9d
  Built:            Wed Sep 16 17:07:04 2020
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          v1.3.7
  GitCommit:        8fba4e9a7d01810a393d5d25a3621dc101981175
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683 
اشتراک‌ها
کدام پروایدر MySQL با EF Core 3x سازگار است؟

There are two MySQL providers for Entity Framework Core:
- The official one from MySQL: MySql.Data.EntityFrameworkCore. As of now, the latest version is 8.0.19, and works with Entity Framework Core 2.1 (and probably also 2.2). Since EF Core 3.0 is a major version with breaking changes, you cannot use it with this provider.
- The Pomelo provider: Pomelo.EntityFrameworkCore.MySql. There is a 3.1 version of this provider.
In other words, if you want to use EF Core 3.0/3.1 with MySQL, at this point you need to use the Pomelo provider (or wait for the official MySQL one to get released).

کدام پروایدر MySQL با EF Core 3x سازگار است؟
نظرات مطالب
سیلورلایت 5 و تاریخ شمسی
سلام جناب نصیری
من تو پروژه سیلور از OData استفاده کردم. وقتی می خواستم Max یک ستون رو برگردونم با پیغام زیر مواجه شدم.
.NotSupportedException: The method 'Max' is not supported
ظاهرا بعضی از متدها موقع کوئری نوشتن (LINQ to Entities) با OData و WCF سازگار نیستن و ساپورت نمیشوند.(البته تا جایی که من سرچ کردم و یه چیزایی فهمیدم).
This topic provides information about the way in which LINQ queries are composed and executed when you are using the WCF Data Services client and limitations of using LINQ to query a data service that implements the Open Data Protocol (OData). For more information about composing and executing queries against an OData-based data service, see Querying the Data Service (WCF Data Services).
Composing LINQ Queries
LINQ enables you to compose queries against a collection of objects that implements IEnumerable. Both the Add Service Reference dialog box in Visual Studio and the DataSvcUtil.exe tool are used to generate a representation of an OData service as an entity container class that inherits from DataServiceContext, as well as objects that represent the entities returned in feeds. These tools also generate properties on the entity container class for the collections that are exposed as feeds by the service. Each of these properties of the class that encapsulates the data service return a DataServiceQuery. Because the DataServiceQuery class implements the IQueryable interface defined by LINQ, the WCF Data Services you can compose a LINQ query against feeds exposed by the data service, which are translated by the client library into a query request URI that is sent to the data service on execution.
 Note:
The set of queries expressible in the LINQ syntax is broader than those enabled in the URI syntax that is used by OData data services. A NotSupportedException is raised when the query cannot be mapped to a URI in the target data service. For more information, see the Unsupported LINQ Methods in this topic.
لطفا اگر امکانش هست راهنمائی بفرمائید و اینکه حالا که ساپورت نمیشه چه راه حلی وجود داره برای Max گرفتن.
با تشکر

مطالب
آشنایی اولیه با gRPC
در مقاله‌ی قبلی بطور کلی با Protocol ‌Buffers آشنا شدیم. در این قسمت با gRPC  آشنا شده و همچنین به پیاده سازی یک سرور و کلاینت، با استفاده از gRPC پرداخته که توسط آن به تبادل اطلاعات با یکدیگر میپردازند. 
gRPC یک فریم ورک مدرن و متن باز با کارآیی بالاست. توسط گوگل پیاده سازی شده و جزء انجمن CNCF میباشد (مثل Docker & Kubernetes) که بر روی سیستم عامل‌های متعددی اجرا میشود. به صورت خیلی کارا میتواند سرویس‌های متعددی را به یکدیگر متصل کرده و همچنین از امکاناتی همچون load balancing, monitoring, tracing, health checking, authentication به صورت خیلی ساده پشتیبانی میکند. بسایر سریع و همچنین Low Latency است. مستقل از یک زبان برنامه نویسی خاص هست و برای streaming بسیار مناسب است و همچنین برای سیستم‌های توزیع شده پیشنهاد میشود و به راحتی قابل توسعه و نگهداری است.
راجع به مزایای gRPC بسیار صحبت کردیم. برای طراحی سرویس‌های متعددی که با یکدیگر در ارتباط هستند، مناسب میباشد. از HTTP/2 به صورت پیشفرض استفاده میکند (راجع به تفاوت HTTP/2 و HTTP1 اینجا  را مطالعه بفرمایید).
شاید بزرگترین مشکلی که در حال حاضر دارد این است که REST را پشتیبانی نمیکند. بدین معنا که شما از طریق browser نمیتوانید یک در خواست را به یک سرور پیاده سازی شده توسط gRPC بصورت مستقیم ارسال کنید. راه حل اول برای حل این مشکل، پیاده سازی یک restful gateway با ابزار دلخواه خود و بقیه سرویس‌ها بعد از آن به هم از طریق gRPC ارتباط برقرا میکنند، یا راه حل بهتر اینکه از grpc-gateway  استفاده شود. ابزاری است که به کمک آن میتوانید سیستم خود را با REST یکپارچه سازی نمایید (هر چند راه‌های دیگری برای وصل شدن از مرورگر به یک سرور gRPC با استفاده از کتابخانه‌های third party میسر شده، اما خارج از موضوع بحث است و مطالعه‌ی بیشتر را به خواننده واگذار میکنم)
قدم اول در پیاده سازی یک سرور/کلاینت با استفاده از gRPC، آشنایی با protocol buffers هست. برای آشنایی، به مقاله‌ی قبلی رجوع فرمایید. تمامی پیاده سازی‌های ما از روی کد‌های تولید شده از تعاریف protocol bufferهایی هست که نوشته‌ایم.
حال فرض کنید میخواهیم یک سرور gRPC را با استفاده از #C نوشته و پیاده سازی نماییم:
۱) قدم اول قطعا نوشتن protobuf می‌باش‍د‍‍. همانطور که در مقاله‌ی قبلی ذکر شده است، به صورت زیر، مدل و همچنین متد‌های لازم را معرفی مینماییم و نام آن را helloworld.proto قرار میدهیم.
syntax = "proto3";

package helloworld;

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

message HelloRequest {
  string name = 1;
}

message HelloReply {
  string message = 1;
}
مدل و سرویس‌ها بصورت واضحی نوشته شده‌اند؛ SayHello با ورودی HelloRequest و خروجی HelloReply تعیین شده‌است.
۲) حالا کافی است یک پروژه‌ی Console را ساخته و ابتدا پکیج‌های زیر را نصب نماییم.
Google.Protobuf
grpc
Grpc.Tools
از طریق Grpc.Tools میتوانیم protobuf‌های خود را بصورت خودکار بعد از build تولید نماییم. در csproj آیتم زیر را اضافه کرده و آدرس protobuf را تعیین مینماییم.
<ItemGroup>
      <Protobuf Include="helloworld.proto" />
  </ItemGroup>
حال کافی است کد‌های زیر را جایگزین نماییم:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Helloworld;
using Grpc.Core;

namespace ServerGrpc
{
    class GreeterImpl : Greeter.GreeterBase
    {
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            System.Console.WriteLine("request made!");
            return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
        }
    }

    class Program
    {
       const int Port = 50051;

        public static void Main(string[] args)
        {
            Server server = new Server
            {
                Services = { Greeter.BindService(new GreeterImpl()) },
                Ports = { new ServerPort("localhost", Port, ServerCredentials.Insecure) }
            };
            server.Start();

            Console.WriteLine("Greeter server listening on port " + Port);
            Console.WriteLine("Press any key to stop the server...");
            Console.ReadKey();

            server.ShutdownAsync().Wait();
        }
    }
}
همانطور که مشاهده میکنید، مدل‌ها و سریس‌ها بصورت خودکار تولید شده‌اند (ضمن اینکه میتوانستیم بصورت دستی نیز protobuf را برای زبان دلخواه خود تولید نماییم).
سرور را بر روی پورت مشخصی ایجاد کرده و همچنین سرویس مورد نظرمان را پیاده سازی کرده‌ایم؛ به صورت فوق همه چیز به ساده‌ترین صورت در نظر گرفته شده است.
gRPC به صورت خودکار از پروتکل امن ssl استفاده میکند؛ اما برای راحتی کار ما از آن استفاده نکرده‌ایم.
نکته: فایل‌های generate شده را از طریق آدرس زیر میتوانید پیدا کنید:
obj/Debug/netcoreapp2.2(یا نسخه‌ی دیگری که استفاده میکنید)

حالا بنا داریم یک کلاینت را با یک زبان برنامه نویسی کاملا مجزا نوشته و به سرور grpc متصل شویم. این کلاینت را با زبان Go خواهیم نوشت (بدیهی است می‌توان جای زبان‌های برنامه نویسی کلاینت و سرور را تغییر داد).
نکته: خیلی وارد جزیات زبان Go نمی‌شویم و فقط اشاره‌ای به موارد کلی خواهیم کرد.
ابتدا باید از روی protobuf کد مربوط به Go را تولید نماییم؛ به صورت زیر:
protoc helloworld.proto --go_out=plugins=grpc:.
فرض کنید فایل generate شده در پوشه‌ی proto قرار گرفته به نام "helloworld.pb.go"
یک فایل به نام main.go ساخته و کد‌های زیر را وارد مینماییم.
package main
import (
        "fmt"
        "golang.org/x/net/context"
        "google.golang.org/grpc"
        "gosample/proto"
)
func main() {
    initial()
}

func initial(){
    conn, _ := grpc.Dial("localhost:50051", grpc.WithInsecure())
    defer conn.Close()
    client := helloworld.NewGreeterClient(conn)
    data, _ := client.SayHello(context.Background(), &helloworld.HelloRequest{Name : "Ali"})

    fmt.Println(data)
}

 به سرور به صورت insecure متصل شده ایم؛ آخر برنامه connection را می‌بندیم و SayHello را فراخوانی کرده و جواب را بر روی خروجی نمایش میدهیم.
نکته: gosample اسم پروژه‌ای است که من ساخته‌ام و proto آدرس پوشه‌ای است که فایل تولید شده‌ی grpc داخل آن قرار گرفته‌است؛ بقیه نیز کتابخانه‌های لازم برای کار با grpc میباشد.
نکته: gRPC برای streaming دیتا بسیار مناسب است (هم یکطرفه و همینطور دو طرفه).
نکته: به دلیل سادگی کار با ابزار‌های مختلف، انتخاب خیلی خوبی برای سیستم‌های توزیع شده‌است؛ همانطور که مشاهده کردید به راحتی قابلیت تعامل بین زبان‌های برنامه نویسی متعددی برقرار است.
نکته‌ی آخر: از وارد شدن به موارد ریز اجتناب کرده‌ام و صرفا این مقاله جهت آشنایی و دید کلی نسبت به این موضوع در نظر گرفته شده‌است.
مطالب
متغیرها در ES 6
در ES 6 تغییراتی جهت ساده سازی خواندن، نوشتن و همچنین بالا بردن امنیت متغیرها و پارامترها صورت گرفته‌اند، تا دیگر شاهد یک سری رفتارهای عجیب و غریب، در حین کار با متغیرهای جاوا اسکریپتی نباشیم.


واژه‌ی کلیدی let

تاکنون به کمک واژه‌ی کلیدی var امکان تعریف متغیرها در جاوا اسکریپت مهیا بودند. برای نمونه در مثال زیر، متغیر x داخل بدنه‌ی if با استفاده از var تعریف شده‌است:
var doWork = function(flag){
   if(flag){
     var x = 3;
   }
   return x;
};
در اینجا اگر متد doWork را با پارامتر true اجرا کنیم، خروجی 3  و اگر آن‌را با پارامتر false اجرا کنیم، خروجی undefined را دریافت خواهیم کرد:


زمانیکه از var استفاده می‌شود، برای یک متغیر دو نوع میدان دید را می‌توان متصور شد:
- اگر خارج از بدنه‌ی تابع تعریف شود، این متغیر عمومی خواهد بود.
- اگر داخل بدنه‌ی تابع تعریف شود، میدان دید آن محدود به همان بدنه‌ی تابع می‌شود. در این حالت چیزی به نام block scope بی‌مفهوم است. در متد doWork فوق، هرچند متغیر x داخل بدنه‌ی بلاک if تعریف شده‌است، اما این x در کل بدنه‌ی تابع در دسترس است و نه صرفا داخل بلاک if. این مورد تا پیش از ES 6 منشاء بسیاری از باگ‌ها بوده‌است.
بنابراین در اینجا چون x تعریف شده، میدان دیدی در سطح متد دارد، return x معتبر بوده و در حالت دریافت پارامتر true، مقدار 3 را بر می‌گرداند و در حالت false هم همچنان مقداری را دریافت خواهیم کرد و این مقدار undefined است (اما پیام خطای عدم دسترسی به x را دریافت نمی‌کنیم).
به این رفتار اصطلاحا hoisting می‌گویند. در این حالت موتور جاوا اسکریپت، تمام متغیرهای تعریف شده‌ی توسط var را به صورت ضمنی به ابتدای تعریف متد منتقل کرده و آن‌ها را در آن‌جا تعریف می‌کند. به همین جهت است که return x تعریف شده‌ی در انتهای متد، قابلیت دسترسی به x داخل بدنه‌ی if را دارد.

در ES 6 برای رفع این مشکل، واژه‌ی کلیدی جدیدی به نام let معرفی شده‌است و هدف آن مهیا کردن block scoping تعریف متغیرها است:
var doWork = function(flag){
    if(flag){
      let x = 3;
    }
    return x;
};
اینبار اگر متد doWork را با پارامتر true فراخوانی کنیم، به خروجی ذیل خواهیم رسید:


بله. همانطور که مشاهده می‌کنید، اینبار میدان دید x به if block تعریف شده‌ی در آن محدود گشته و دیگر خارج از آن مفهومی ندارد و تعریف نشده‌است. به همین جهت زمانیکه به return x می‌رسیم، پیام تعریف نشده بودن x را دریافت خواهیم کرد. برای اینکه قطعه کد فوق کار کند، نیاز است return x را به داخل بدنه‌ی قطعه‌ی if تعریف شده، انتقال داد.

این block scoping مهیا شده‌ی توسط let، با حلقه‌ی for نیز کار می‌کند:
var doWork = function(){
   for(let i = 0; i< 10; i++){
   }

   /* return i won't work */
  return 0;
};
در مثال فوق اگر return i را در انتهای متد قرار دهیم، با همان خطای Uncaught ReferenceError پیشین مواجه خواهیم شد؛ از این جهت که برخلاف var، متغیر تعریف شده‌ی با let، میدان دیدی در سطح قطعه و بلاک تعریف شده‌ی در آن دارد و در اینجا بلاک متغیر i همان حلقه‌ی for است.


یک نکته

مفهوم block scoping با تعریف {} معنا پیدا می‌کند. بنابراین می‌توانید یک قطعه‌ی دلخواه را با تعریف {} نیز مشخص کنید:

و یا در مثال ذیل چندین قطعه‌ی تو در تو را مشاهده می‌کنید:
let outer = 'I am so eccentric!'
{
  let inner = 'I play with neighbors in my block and the sewers'
  {
    let innermost = 'I only play with neighbors in my block'
  }
  // accessing innermost here would throw
}
// accessing inner here would throw
// accessing innermost here would throw
در اینجا میدان دید متغیرهای تعریف شده، محدود است به قطعه‌ی آن‌ها. به همین جهت است که نمی‌توان به متغیر innermost در خارج از بلاک آن دسترسی یافت.

نمونه‌ی دیگر آن تعریف یک متد داخل یک بلاک است:
{
  let _nested = 'secret'
  function nested () {
    return _nested
  }
}
console.log(nested())
اگر این قطعه کد را اجرا کنیم، به خطای ذیل خواهیم رسید:


در ES 6 نمی‌توان به متغیرهای تعریف شده‌ی توسط let داخل یک بلاک، در خارج از آن دسترسی یافت. اگر می‌خواهید سطح دسترسی به متد را افزایش دهید، نیاز است به شکل ذیل عمل کنید و متد را خارج از بدنه‌ی بلاک با سطح دسترسی بیشتری تعریف نمائید:
var nested;
{
  let _nested = 'secret'
  nested = function () {
    return _nested
  }
}
console.log(nested())
// <- 'secret'


واژه‌ی کلیدی const

در ES 6 برای ایجاد و مقدار دهی متغیرهای فقط خواندنی، واژه‌ی کلیدی const افزوده شده‌است. در اینجا const نیز مانند let دارای block scoping است.
doWork = function()
{
   const value = 10;
   value = 11;
   return value;
}
در این مثال ابتدا متغیر value به صورت یک ثابت تعریف شده‌است و سپس مقدار 11 به آن نسبت داده شده‌است. اگر آن‌را در کروم 47 اجرا کنید، از مقدار 11 صرفنظر شده و خروجی 10 را بازگشت می‌دهد. اما اگر آن‌را در فایرفاکس 43 اجرا کنید، خطای متناظر با ES 6 را بازگشت می‌دهد:


در ES 6، انتساب یک مقدار به یک const، پس از تعریف آن، منجر به بروز خطای syntax error خواهد شد. همچنین تعریف مجدد آن نیز چنین خطایی را سبب خواهد شد.

یک نکته
هر چند const سبب read only شدن یک متغیر می‌شود، اما آن‌را immutable نمی‌کند:
const items = { people: ['you', 'me'] }
items.people.push('test')
console.log(items)
با این خروجی:

همانطور که مشاهده می‌کنید، هنوز هم می‌توان به شیء تعریف شده، آیتمی را اضافه کرد (در اینجا test به آرایه‌ی people اضافه شده‌است).


آشنایی با مفهوم shadowing

همان مثال ابتدای بحث را در نظر بگیرید:
var doWork = function(flag){
   if(flag){
        let x = 10;
        var x = 3;
        return x;
   }
};
داخل بدنه‌ی if، متغیر x یکبار توسط let و بار دیگر توسط var تعریف شده‌است.  در این حالت خطای Uncaught SyntaxError: Identifier 'x' has already been declared را دریافت خواهیم کرد (اگر let اول را به var تغییر دهید، مشکلی نخواهد بود و برنامه کامپایل می‌شود). اما اگر let x را به پیش از متد انتقال دهیم، اینبار مثال کامپایل می‌شود و خروجی متد (doWork(true مساوی 3 خواهد بود:
let x = 10;
var doWork = function(flag){
    if(flag){
      var x = 3;
      return x;
   }
};
در این حالت x تعریف شده‌ی داخل بلاک توسط var (یا حتی let) مقدار x تعریف شده‌ی در بلاک بالاتر را مخفی می‌کند که به آن shadowing نیز می‌گویند. در این حالت اگر در خارج از متد doWork، به x دسترسی پیدا کنیم، مقدار آن همان 10 است.
مثال ذکر شده، با مثال ذیل که یک بلاک را توسط {} ایجاد کرده‌ایم، یکی است:
let x = 10;
{
   let x = 3;
   console.log(x);
}
console.log(x);


در اینجا نیز ابتدا مقدار 3 که مرتبط با بلاک داخلی است چاپ خواهد شد و سپس مقدار 10 که مرتبط است به بلاک خارجی‌تر.
اشتراک‌ها
پشتیبانی از Markdown توسط ckeditor

It provides all the features available in the GitHub plain-text editor, including Markdown input. For features like tables, it offers a much easier experience in comparison to plain-text Markdown and allows users to be more productive.  

پشتیبانی از Markdown توسط ckeditor
اشتراک‌ها
پشتیبانی کامل webkit از ES 6

As of r202125, JavaScriptCore supports all of the new features in the ECMAScript 6 (ES6) language specification. All of the new ES6 features are available in the latest WebKit Nightly and Safari Technology Preview.  

پشتیبانی کامل webkit از ES 6
مطالب
جستجوی کاراکترهای wildcards توسط ماده اختیاری ESCAPE
syntax کامل LIKE:
match_expression [ NOT ] LIKE pattern [ ESCAPE escape_character ]

چهار کاراکتر وجود دارد که الگوهای جستجو را توسط آنها تعریف می‌کنند. این کاراکترها wildcard نام دارند.
زمانی که کاراکترهای wildcard موجود در الگوی ما به عنوان کاراکترهای عادی در نظر گرفته شده اند نه wildcard آنگاه باید به SQL اطلاع دهیم که آنها را با کاراکترهای wildcard اشتباه نگیرد، برای این منظور چندین راه حل وجود دارد که در ادامه شرح خواهم داد.

فرض کنید الگوی شما این مقدار باشد:
"تنها دو کاراکتر % کاراکترهای wildcard هستند"
%[abcde_ ]%

روش اول: ESCAPE
WHERE string_value LIKE '%@[abcde@_ ]%' ESCAPE '@'
دو کاراکتر ] و _ علامت گذاری (بوسیله @) و توسط ماده ESCAPE به عنوان کاراکترهای معمولی شناخته شدند.

روش دوم: Bracket
WHERE string_value LIKE '%[[]abcde[_] ]%'
دو کاراکتر ] و _ را داخل [] قرار دادیم.

روش سوم: CHARINDEX
WHERE CHARINDEX('[abcde_ ]', string_value) > 0
عبارت را بدون هیچ گونه تغییری در تابع استفاده کردیم. این روش تنها زمانی مورد استفاده می‌تواند قرار گیرد که کاراکتر % در ابتدا یا انتهای (یا هر دو) آن قرار گرفته باشد.


تمرین:
عباراتی را پیدا کنید که الگوی زیر در آن پیدا شود، فقط آخرین کاراکتر wildcard می‌باشد یعنی کاراکتر %
[[[%^ab'c'de]]]%
برای تست راه حلتان از متغیر جدولی زیر استفاده کنید:

declare @t table (s varchar(50))
insert @t values ('[[[%^ab''c''de]]]%'),
('[[[ %^ab''cde]]%'), ('[[%^ab''c''de]]%'),
('[[[%^abc''de]]]%');