LINQ در JavaScript
- 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
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
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
آموزش مقدماتی NET Aspire.
Build Better Apps with .NET Aspire - Complete Beginner's Guide & Tutorial
Let's start building better apps with .NET Aspire! Find out how adding .NET Aspire to your existing apps can help them be more observable, resilient, scalable, and manageable. All in just a few lines of code enable these features and at the same time boost developer productivity with features to help you build apps faster including orchestration and service discovery. It also gives you deep insight into your application with OpenTelemetry and a developer dashboard on your local development machine or in the cloud. We will also take a look at how to deploy your projects that use .NET Aspire and how it works under the hood. Finally, we will look at how to use some of these great features in non-.NET projects such as JavaScript and Python!
وبلاگها ، سایتها و مقالات ایرانی (داخل و خارج از ایران)
- تنظیم Http Proxy در CVS
- URL Rewrite Module for IIS 7.0
- تریگرها در SQL Server
- گستره سیاست ها در Group Policy
- لینوس توروالدز به سوی میزکار گنوم باز می گردد
- ابر برچسبها و مقایسهی سخنرانیهای بوش و اوباما
- اندیسهای فیلتر شده
ASP. Net
- ASP.NET MVC 1.0 Release Candidate
- ویدیوی معرفی ASP.NET MVC و ویدیویی دیگر
- GridView and CommandArguments
طراحی و توسعه وب
PHP
- PDT 2.0 : ابزارهای جدیدی برای برنامه نویسهای PHP
- NetBeans ، PHP و کار با دیتابیس
- بررسی سرعت و میزان مصرف حافظهی متدهای مختلف در PHP
سی شارپ
عمومی دات نت
ویندوز
(ایکاش بجای تمام اینکارها یک سیستم سادهتر توسعهی پلاگین برای آن طراحی میکردند ... یا به عبارتی یکی از مهمترین دلیلهای اقبال مردم به فایرفاکس را به صورت بسیار کم رنگی دارد)
مسایل اجتماعی و انسانی برنامه نویسی
- داستان استفاده از برنامههای خود پیش از استفاده دیگران
- راههایی برای افزایش بهره وری
- راههایی برای کاهش بهره وری!
متفرقه
سفر به Angular بخش اول
In the eighteen years that I’ve been doing Web development, a lot has changed. We started out creating HTML pages to present static information to our users. We then used classic ASP to get database data and incorporate that into our pages. To use both of these technologies, we had to know a lot about HTML, CSS, and JavaScript. Along came .NET and we started rendering everything on the server-side. We forgot a lot about HTML, CSS, and JavaScript as Web Forms wrapped up a lot of that for us. Web Forms’ architecture closely mimicked the way developers created desktop applications. This was great for helping developers move to the Web, but unfortunately hid a lot of the power of the Web, and also tended to be a little slow.
اکثر کنترلهای تعیین اعتبار ASP.Net بر اساس جاوا اسکریپت کار میکنند (مانند RangeValidator و امثال آن). حال اگر کاربری افزونه no script فایرفاکس را نصب کرده بود چه باید کرد؟
با استفاده از این افزونه، این نوع کنترلها از کار خواهند افتاد (چون دیگر کدهای جاوا اسکریپتی آنها اجرا نخواهند شد).
خوشبختانه برای بررسی صحت عملکرد این کنترلها در ASP.Net امکان بررسی خاصیت Page.IsValid نیز وجود دارد که در ادامه به آن خواهیم پرداخت.
صفحهی بسیار ساده ASP.Net زیر را در نظر بگیرید:
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx.cs" Inherits="testWebForms87.WebForm3" %>
<!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>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:TextBox ID="txtData" runat="server"></asp:TextBox>
<asp:RangeValidator ID="RangeValidator1" runat="server" ControlToValidate="txtData"
ErrorMessage="لطفا یک عدد وارد کنید" MaximumValue="100000" MinimumValue="0" SetFocusOnError="True"
Type="Integer"></asp:RangeValidator>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="txtData"
ErrorMessage="لطفا مقداری را وارد نمائید" SetFocusOnError="True"></asp:RequiredFieldValidator>
<br />
<asp:Button ID="btnSubmit" runat="server" OnClick="btnSubmit_Click" Text="Submit" />
<br />
<asp:Label ID="lblValue" runat="server"></asp:Label>
</div>
</form>
</body>
</html>
سپس برای بررسی سمت سرور عملکرد کنترلهای تعیین اعتبار در ASP.Net میتوان به صورت زیر عملکرد:
protected void btnSubmit_Click(object sender, EventArgs e)
{
if (btnSubmit.CausesValidation)
{
// Validate the Page
Page.Validate();
// Ensure Page is Valid
if (!Page.IsValid)
{
lblValue.Text = "لطفا جاوا اسکریپت را در مرورگر خود فعال نمائید";
return;
}
}
lblValue.Text = txtData.Text;
}
راه دیگر بررسی غیرفعال بودن جاوا اسکریپت در یک صفحه استفاده از روش سنتی تگ noscript است:
<noscript>
<meta http-equiv="refresh" content="0;url=http://www.google.com">
</noscript>
در پایان باید خاطر نشان کرد که هیچگاه به کنترلهای تعیین اعتبار سمت کاربر اطمینان نکنید و حتما یا از روش فوق استفاده نمائید، یا در روال submit صفحه به سرور، یکبار دیگر دادهها را به صورت دستی نیز بررسی کنید. برای مثال اگر کاربر قرار است آدرس ایمیلی را وارد کند، حتما یکبار دیگر با استفاده از regular expressions ، در سمت سرور نیز عبارت ورودی را بررسی کنید.
- dotnet-ignore : این ابزار جهت دریافت فایلهای gitignore. کاربرد داشته و از یک مخزن عمومی گیت هاب جهت دریافت این فایلها استفاده میکند. این مخزن شامل انواع قالبهای gitignore در پروژههای متفاوت میباشد. با استفاده از این ابزار، ایجاد فایل gitignore راحتتر و سریعتر امکانپذیر میباشد.
- dotnet-serve : میزبانی و نمایش لیست فایلهای استاتیک محلی و اجرای آنها را در بستر http، فراهم مینماید.
- dotnet-cleanup : جهت پاکسازی محیط بیلد مانند دایرکتوریهای bin و obj میباشد. همان کار گزینه clean در منوی بیلد را بازی میکند.
- dotnet-warp : این ابزار در واقع پروژه Warp است که برای ایجاد یک تک فایل اجرایی جهت انتقال راحتتر فایل پروژه صورت میگیرد که همه وابستگیهای آن در همان تک فایل قرار میگیرد.
- Amazon.ECS.Tools , Amazon.ElasticBeanstalk.Tools و Amazon.Lambda.Tools : این ابزارها که به صورت رسمی از طرف آمازون ارائه شدهاند که جهت deploy شدن راحتتر پروژه به محیطهای توسعه وب آمازون مورد استفاده قرار میگیرند.
dotnet tool install -g dotnet-ignore
dotnet tool list -g
dotnet tool update -g dotnet-ignore
dotnet tool uninstall -g dotnet-ignore
<PropertyGroup> <PackAsTool>true</PackAsTool> <ToolCommandName>dotnet-mytool</ToolCommandName> <PackageOutputPath>./nupkg</PackageOutputPath> </PropertyGroup>
dotnet tool install --global --add-source ./nupkg globaltools
dotnet-mytool
https://www.nuget.org/packages/McMaster.Extensions.CommandLineUtils
[Command(Description="Add a new note")] public class NewNote { [Required] [Option(Description="title of note")] public string Title{ get; set; } [Option(Description="content of note")] public string Body{ get; set; } }
[Command(Description="Add a new note")] public class NewNote:BaseClass { [Required] [Option(Description="title of note")] public string Title{ get; set; } [Option(Description="content of note")] public string Body{ get; set; } public void OnExecute(IConsole console) { var dir = GetBaseDirectory(); if(!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } var filePath = Path.Combine(dir, Title + ".txt"); File.WriteAllText(filePath, Body); console.WriteLine("the note is saved"); } }
public class BaseClass { protected string GetBaseDirectory(){ var baseDirectory = Environment.CurrentDirectory; return (Path.Combine(baseDirectory, "notes")); } }
public class List:BaseClass { [Option(Description="search a phrase in notes title")] public string Grep{ get; set; } public void OnExecute(IConsole console) { try { var baseDirectory = GetBaseDirectory(); var dir = new DirectoryInfo(baseDirectory); var files = dir.GetFiles(); foreach(var file in files) { if(!String.IsNullOrEmpty(Grep) && !file.Name.Contains(Grep)) continue; console.WriteLine(Path.GetFileNameWithoutExtension(file.Name)); } } catch (Exception e) { console.WriteLine(e.Message); } } }
[Command(Description="show contnet of note")] public class Show:BaseClass { [Required] [Option(Description="title of note")] public string Title{ get; set; } public void OnExecute(IConsole console){ var baseDirectory = GetBaseDirectory(); var file = Path.Combine(baseDirectory, Title+".txt"); if(!File.Exists(file)) { console.WriteLine("The Note NotFound..."); return; } console.WriteLine(File.ReadAllText(file)); } }
[Command(Description="An Immediate Note Saver")] [Subcommand(typeof(NewNote),typeof(List),typeof(Show))] class Program { static int Main(string[] args) { return CommandLineApplication.Execute<Program>(args); } public int OnExecute(CommandLineApplication app, IConsole console) { console.WriteLine("You must specify a subcommand."); console.WriteLine(); app.ShowHelp(); return 1; } }
static int Main(string[] args) { return CommandLineApplication.Execute<Program>(args); }
PS D:\projects\Samples\globaltools> dotnet-notes new-note -t "sample1" -b "this is body" the note is saved PS D:\projects\Samples\globaltools> dotnet-notes new-note -t "test1" -b "this is body of another note" the note is saved PS D:\projects\Samples\globaltools> dotnet-notes list sample1 test1 PS D:\projects\Samples\globaltools> dotnet-notes list -g sa sample1 PS D:\projects\Samples\globaltools> dotnet-notes show -t sample1 this is body