ابزارهای پیش نیاز:
در اولین قدم، برنامهی متن باز Visual Studio Code را از اینجا دانلود و نصب کنید. برنامهی Visual Studio Code که در ادامهی فعالیتهای جدید متن باز مایکروسافت به بازار عرضه شده است، سریع، سبک و کاملا قابل توسعه و سفارشی سازی است و از اکثر زبانهای معروف پشتیبانی میکند.
در قدم بعدی، شما باید NET Core. را از اینجا (64 بیتی) دانلود و نصب کنید.
.NET Core چیست؟
NET Core. در واقع پیاده سازی بخشی از NET. اصلی است که به صورت متن باز در حال توسعه میباشد و بر روی لینوکس و مکینتاش هم قابل اجراست. موتور اجرای دات نت کامل CLR نام دارد و NET Core. نیز دارای موتور اجرایی CoreCLR است و شامل فریمورک CoreFX میباشد.
در حال حاضر شما میتوانید با استفاده از NET Core. برنامههای کنسولی و تحت وب با ASP.NET 5 بنویسید و احتمالا در آینده میتوان امیدوار بود که از ساختارهای پیچیدهتری مثل WPF نیز پشتیبانی کند.
پس از آنکه NET Core. را دانلود و نصب کردید، جهت شروع پروژه، یک پوشه را در یکی از درایوها ساخته (در این مثال E:\Projects\EF7-SQLite-NETCore) و Command prompt را در آنجا باز کنید. سپس دستورات زیر را به ترتیب اجرا کنید:
dotnet restore
dotnet run
- NuGet.Config (این فایل، تنظیمات مربوط به نیوگت را جهت کشف و دریافت وابستگیهای پروژه، شامل میشود)
- Program.cs (این فایل سی شارپ حاوی کد برنامه است)
- project.json (این فایل حاوی اطلاعات پلتفرم هدف و لیست وابستگیهای پروژه است)
دستور dotnet restore بر اساس لیست وابستگیها و پلتفرم هدف، وابستگیهای لازم را از مخزن نیوگت دریافت میکند. (در صورتی که در هنگام اجرای این دستور با خطای NullReferenceException مواجه شدید از دستور dnu restore استفاده کنید. این خطا در گیت هاب در حال بررسی است)
دستور dotnet run هم سورس برنامه را کامپایل و اجرا میکند. در صورتی که پیام Hello World را مشاهده کردید، یعنی برنامهی شما تحت NET Core. با موفقیت اجرا شده است.
توسعهی پروژه با Visual Studio Code
در ادامه، قصد داریم پروژهی HelloWorld را تحت Visual Studio Code باز کرده و تغییرات بعدی را در آنجا اعمال کنیم. پس از باز کردن Visual Studio Code از منوی File گزینهی Open Folder را انتخاب کنید و پوشهی حاوی پروژه (EF7-SQLite-NETCore) را انتخاب کنید. اکنون پروژهی شما تحت VS Code باز شده و قابل ویرایش است.
سپس از لیست فایلهای پروژه، فایل project.json را باز کرده و در بخش "dependencies" یک ردیف را برای EntityFramework.SQLite به صورت زیر اضافه کنید. به محض افزودن این خط در project.json و ذخیرهی آن، در صورتیکه قبلا این وابستگی دریافت نشده باشد، Visual Studio Code با نمایش یک هشدار در بالای برنامه به شما امکان دریافت اتوماتیک این وابستگی را میدهد. در نتیجه کافیست دکمهی Restore را زده و منتظر شوید تا وابستگی EntityFramework.SQLite از مخزن ناگت دانلود و برای پروژهی شما تنظیم شود.
"EntityFramework.SQLite": "7.0.0-rc1-final"
پس از کامل شدن این مرحله، در پروژههای بعدی تمام ارجاعات به وابستگیهای دریافت شده، از طریق مخزن موجود در سیستم خود شما، برطرف خواهد شد و نیاز به دانلود مجدد وابستگیها نیست.
اکنون همهی موارد، جهت توسعهی پروژه آماده است. ماوس خود را بر روی ریشهی پروژه در VS Code قرار داده و New Folder را انتخاب کنید و نام Models را برای آن تایپ کنید. این پوشه قرار است مدل کلاسهای پروژه را شامل شود. در اینجا ما یک مدل به نام Book داریم و نام کانتکست اصلی پروژه را هم LibraryContext گذاشتهایم.
بر روی پوشهی Models راست کلیک کرده و گزینهی New File را انتخاب کنید. سپس فایلهای Book.cs و LibraryContext.cs را ایجاد کرده و کدهای زیر را برای مدل و کانتکست، در درون این دو فایل قرار دهید.
Book.cs
namespace Models { public class Book { public int ID { get; set; } public string Title { get; set; } public string Author{get;set;} public int PublishYear { get; set; } } }
using Microsoft.Data.Entity; using Microsoft.Data.Sqlite; namespace Models { public class LibraryContext : DbContext { protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { var connectionStringBuilder = new SqliteConnectionStringBuilder { DataSource = "test.db" }; var connectionString = connectionStringBuilder.ToString(); var connection = new SqliteConnection(connectionString); optionsBuilder.UseSqlite(connection); } public DbSet<Book> Books { get; set; } } }
در قدم آخر هم کافیست که فایل Program.cs را تغییر دهید و مقادیری را در دیتابیس ذخیره و بازخوانی کنید.
using System; using Models; namespace ConsoleApplication { public class Program { public static void Main(string[] args) { Console.WriteLine("EF7 + Sqlite with the taste of .NET Core"); try { using (var context = new LibraryContext()) { context.Database.EnsureCreated(); var book1 = new Book() { Title = "Adaptive Code via C#: Agile coding with design patterns and SOLID principles ", Author = "Gary McLean Hall", PublishYear = 2014 }; var book2 = new Book() { Title = "CLR via C# (4th Edition)", Author = "Jefrey Ritcher", PublishYear = 2012 }; context.Books.Add(book1); context.Books.Add(book2); context.SaveChanges(); ReadData(context); } Console.WriteLine("Press any key to exit ..."); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine($"An exception occured: {ex.Message}\n{ex.StackTrace}"); } } private static void ReadData(LibraryContext context) { Console.WriteLine("Books in database:"); foreach (var b in context.Books) { Console.WriteLine($"Book {b.ID}"); Console.WriteLine($"\tName: {b.Title}"); Console.WriteLine($"\tAuthor: {b.Author}"); Console.WriteLine($"\tPublish Year: {b.PublishYear}"); Console.WriteLine(); } } } }
جهت اجرای برنامه کافیست Command prompt را در آدرس پروژه باز کرده و دستور dotnet run را اجرا کنید. پروژهی شما کامپایل و اجرا میشود و خروجی مشابه زیر را مشاهده خواهید کرد. اگر برنامه را مجددا اجرا کنید، به جای دو کتاب اطلاعات چهار کتاب نمایش داده خواهد شد؛ چرا که در هر مرحله اطلاعات دو کتاب در دیتابیس درج میشود.
اگر به پوشهی bin که در پوشهی پروژه ایجاد شده است، نگاهی بیندازید، خبری از فایل باینری نیست. چرا که در لحظه، تولید و اجرا شده است. جهت build کردن پروژه و تولید فایل باینری کافیست دستور dotnet build را اجرا کنید، تا فایل باینری در پوشهی bin ایجاد شود.
جهت انتشار برنامه میتوانید دستور dotnet publish را اجرا کنید. این دستور نه تنها برنامه، که تمام وابستگیهای مورد نیاز آن را برای اجرای در یک پلتفرم خاص تولید میکند. برای مثال بعد از اجرای این دستور یک پوشهی win7-x64 حاوی 211 فایل در مجموع تولید شده است که تمامی وابستگیهای این پروژه را شامل میشود.
در واقع این پوشه تمام وابستگیهای مورد نیاز پروژه را همراه خود دارد و در نتیجه جهت اجرای این برنامه برخلاف برنامههای معمولی دات نت، دیگر نیازی به نصب هیچ وابستگی مجزایی نیست و حتی پروژههای نوشته شده تحت NET Core. را میتوانید در سیستمهای عاملهای دیگری مثل لینوکس و مکینتاش و یا Windows IoT بر روی سخت افزار Raspberry Pi 2 هم اجرا کنید.
جهت مطالعهی بیشتر:
درختها و گرافها قسمت اول
بنابراین آدرس شما باید چند قسمتی باشد؛ اگر عبارت فارسی یا یونیکد قرار است در آن درج شود. قسمت ابتدایی آن باید به نحوی انگلیسی باشد و قسمت نهایی آن فارسی و این قسمت فارسی باید در کار مسیریابی بیاهمیت باشد تا اگر خزنده در تفسیر آن اشتباه کرد، به خطای 404 برخورد نکند.
خواندنیهای 4 شهریور
آفیس
اس کیوال سرور
الگوهای طراحی برنامه نویسی شیءگرا
توسعه وب
دات نت فریم ورک
متفرقه
محیطهای مجتمع توسعه
مرورگرها
ویندوز
Learn FULL STACK Web Development in 2 HOURS! ASP.NET & Angular
Timestamps:
00:00:00 Welcome to our 2 hour FULL STACK Course!
00:01:12 What you will learn during the next 2 hours
00:03:29 Day 1 Multi-Page and Single-Page Applications, TypeScript, and Angular Components
00:21:57 Day 2 One-Way Binding and Event Binding in Angular
00:34:23 Day 3 Our Flight Booking Portal and routing in Angular
00:44:52 Day 4 The 'Search Flight' page, Design a HTML page, install Font Awesome using Node, and TypeScript interfaces
01:27:00 Day 5 ASP.NET Core REST API, SWAGGER for documenting and testing our API
01:55:51 Thanks for watching!
1. Attribute Routing
Config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{Controller}/{id}", defaults: new { id = RouteParameter.Optional } );
URI Pattern --> books/1/authors [Route("books/{bookId}/authors")] public IEnumerable<Author> GetAuthorByBook(int bookId) { ..... }
2. CORS - Cross Origin Resource Sharing
3. OWIN (Open Web Interface for .NET) self-hosting
OWIN یک اینترفیس استاندارد بین سرورهای دات نت و اپلیکیشنهای وب تعریف میکند. هدف این اینترفیس جداسازی (decoupling) سرور و اپلیکیشن است. تشویق به توسعه ماژولهای ساده برای توسعه اپلیکیشنهای وب دات نت. و بعنوان یک استاندارد باز (open standard) اکوسیستم نرم افزارهای متن باز را تحریک کند تا ابزار توسعه اپلیکیشنهای وب دات نت توسعه یابند.
4. IHttpActionResult
5. Web API OData
- expand$: بصورت نرمال، هنگام کوئری گرفتن از یک کالکشن OData، پاسخ سرور موجودیتهای مرتبط (related entities) را شامل نمیشود. با استفاده از expand$ میتوانیم موجودیتهای مرتبط را بصورت inline در پاسخ سرور دریافت کنیم.
- select$: از این متد برای انتخاب چند خاصیت بخصوص از پاسخ سرور استفاده میشود، بجای آنکه تمام خاصیتها بارگذاری شوند.
- value$: با این متد مقدار خام (raw) فیلدها را بدست میآورید، بجای دریافت آنها در فرمت OData.
چند مقاله خوب دیگر
آسیب پذیری SQL Injection یا به اختصار SQLi
تزریق SQL، یکی از قدیمی ترین، شایعترین و مخربترین آسیب پذیریها، برای برنامهها میباشد و در صورت برقراری شرایط مناسب جهت حمله و با اعمال نفوذ، از طریق تزریق SQL ، مهاجم میتواند با دور زدن فرآیندهای اعتبارسنجی و احراز هویت یک برنامه، به تمامی محتوای پایگاه دادهی آن و گاها کنترل سرور، دسترسی پیدا کند. این حمله برای افزودن، ویرایش و حذف رکوردهای یک پایگاه داده مبتنی بر SQL انجام میشود.
عملکرد SQL Injection
برای اجرای SQLهای مخرب در برنامههایی که از پایگاههای دادهی مبتنی بر SQL مانند (SQL Server ،MySQL ،PostgreSQL ،Oracle و ...) استفاده میکنند، هکر یا مهاجم در اولین گام باید به دنبال ورودیهایی در برنامه باشد که درون یک درخواست SQL قرار گرفته باشند (مانند صفحات لاگین، ثبت نام، جستجو و ...).
کد زیر را در نظر بگیرید:
# Define POST variables uname = request.POST['username'] passwd = request.POST['password'] # SQL query vulnerable to SQLi sql = "SELECT id FROM users WHERE username='" + uname + "' AND password='" + passwd + "'" # Execute the SQL statement database.execute(sql)
اکنون ورودی password را برای نفوذ، تست میکنیم. مهاجم بدون داشتن نام کاربری، قصد دور زدن احراز هویت را دارد. بجای password عبارت زیر را قرار میدهد:
password' OR 1=1
در نهایت در بانک اطلاعاتی دستور زیر اجرا میشود:
SELECT id FROM users WHERE username='username' AND password= 'password' OR 1=1'
میدانیم که 1=1 است. پس بدون در نظر گرفتن اینکه شما برای username و password چه چیزی را وارد نمودید، عبارت درست در نظر گرفته میشود:
شرط اول and شرط دوم = نتیجه or 1=1 چون 1=1 است همیشه شرط کوئری درست خواهد بود
معمولا در بانک اطلاعاتی، اولین کاربری که وارد میکنند Administrator برنامه میباشد. پس به احتمال قوی شما میتوانید با مجوز ادمین به برنامه وارد شوید. البته میتوان با دانستن تنها نام کاربری هم بهراحتی با گذاشتن در قسمت username بدون دانستن password، به برنامه وارد شد؛ زیرا میتوان شرط چک کردن password را کامنت نمود:
-- MySQL, MSSQL, Oracle, PostgreSQL, SQLite ' OR '1'='1' -- ' OR '1'='1' /* -- MySQL ' OR '1'='1' # -- Access (using null characters) ' OR '1'='1' %00 ' OR '1'='1' %16
ابزارهایی برای تست آسیب پذیری SQLi
2) اسکنر اکانتیکس
چگونه از SQL Injection جلوگیری کنیم
1) روی دادههایی که از کاربر دریافت میگردد، اعتبار سنجی سمت کلاینت و سرور انجام شود. اگر فقط به اعتبارسنجی سمت کلاینت اکتفا کنید، هکر بهراحتی با استفاده از پروکسی، دادهها را تغییر میدهد. ورودیها را فیلتر و پاکسازی و با لیست سفید یا سیاه بررسی کنید ( ^ , ^, ^, ^ ).
2) از کوئریهایی که بدون استفاده از پارامتر از کاربر ورودی گرفته و درون یک درخواستSQL قرار میگیرند، اجتناب کنید:
[HttpGet] [Route("nonsensitive")] public string GetNonSensitiveDataById() { using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString"))) { connection.Open(); SqlCommand command = new SqlCommand($"SELECT * FROM NonSensitiveDataTable WHERE Id = {Request.Query["id"]}", connection); using (var reader = command.ExecuteReader()) { if (reader.Read()) { string returnString = string.Empty; returnString += $"Name : {reader["Name"]}. "; returnString += $"Description : {reader["Description"]}"; return returnString; } else { return string.Empty; } } } }
با استفاده از پارامتر: (بهتر است نوع دیتا تایپ پارامتر و طول آن ذکر شود)
[HttpGet] [Route("nonsensitivewithparam")] public string GetNonSensitiveDataByNameWithParam() { using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString"))) { connection.Open(); SqlCommand command = new SqlCommand($"SELECT * FROM NonSensitiveDataTable WHERE Name = @name", connection); command.Parameters.AddWithValue("@name", Request.Query["name"].ToString()); using (var reader = command.ExecuteReader()) { if (reader.Read()) { string returnString = string.Empty; returnString += $"Name : {reader["Name"]}. "; returnString += $"Description : {reader["Description"]}"; return returnString; } else { return string.Empty; } } } }
3) از Stored Procedureها استفاده کنید و بصورت پارامتری دادههای مورد نیاز را به آنها پاس دهید: (بهتر است نوع دیتا تایپ پارامتر و طول آن ذکر شود)
[HttpGet] [Route("nonsensitivewithsp")] public string GetNonSensitiveDataByNameWithSP() { using (SqlConnection connection = new SqlConnection(_configuration.GetValue<string>("ConnectionString"))) { connection.Open(); SqlCommand command = new SqlCommand("SP_GetNonSensitiveDataByName", connection); command.CommandType = System.Data.CommandType.StoredProcedure; command.Parameters.AddWithValue("@name", Request.Query["name"].ToString()); using (var reader = command.ExecuteReader()) { if (reader.Read()) { string returnString = string.Empty; returnString += $"Name : {reader["Name"]}. "; returnString += $"Description : {reader["Description"]}"; return returnString; } else { return string.Empty; } } } }
4) اگر از داینامیک کوئری استفاده میکنید، دادههای مورد استفادهی در کوئری را بصورت پارامتری ارسال کنید:
فرض کنید چنین جدولی دارید
CREATE TABLE tbl_Product ( Name NVARCHAR(50), Qty INT, Price FLOAT ) GO INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Shampoo', 200, 10.0); INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Hair Clay', 400, 20.0); INSERT INTO tbl_Product (Name, Qty, Price) VALUES (N'Hair Tonic', 300, 30.0);
یک پروسیجر را دارید که عملیات جستجو را انجام میدهد و از داینامیک کوئری استفاده میکند.
ALTER PROCEDURE sp_GetProduct(@Name NVARCHAR(50)) AS BEGIN DECLARE @sqlcmd NVARCHAR(MAX); SET @sqlcmd = N'SELECT * FROM tbl_Product WHERE Name = ''' + @Name + ''''; EXECUTE(@sqlcmd) END
با اینکه از Stored Procedure استفاده میکنید، باز هم در معرض خطر SQLi میباشید. فرض کنید هکر چنین درخواستی را ارسال میکند:
Shampoo'; DROP TABLE tbl_Product; --
نتیجه، تبدیل به دستور زیر میشود:
SELECT * FROM tbl_Product WHERE Name = 'Shampoo'; DROP TABLE tbl_Product; --'
برای جلوگیری از SQLi در کوئریهای داینامیک SP بشکل زیر عمل میکنیم:
ALTER PROCEDURE sp_GetProduct(@Name NVARCHAR(50)) AS BEGIN DECLARE @sqlcmd NVARCHAR(MAX); DECLARE @params NVARCHAR(MAX); SET @sqlcmd = N'SELECT * FROM tbl_Product WHERE Name = @Name'; SET @params = N'@Name NVARCHAR(50)'; EXECUTE sp_executesql @sqlcmd, @params, @Name; END
5) میتوان از تنظیمات IIS یا وب سرورهای دیگر برای جلوگیری از SQLi استفاده نمود.
6) استفاده از چند کاربرِ دیتابیس در برنامه و بکارگیری سطح دسترسی محدود و مناسب( ^ , ^ ).
7) از ORM استفاده کنید و اگر نیاز به سرعت بیشتری دارید از یک Micro ORM استفاده کنید؛ با در نظر داشتن نکات لازم.
در مطلب آشنایی با Directiveها در AngularJS با نحوهی ایجاد Directive آشنا شدیم. هدف از این مطلب، آشنایی بیشتر با Directive در AngularJS است؛ یکی از بهترین فریم ورکهای جاوااسکریپتی، با قابلیت ایجاد کتابخانههایی از کامپوننتها که میتوانند به HTML اضافه شوند .
کتابخانههای جاوااسکریپتی زیادی وجود دارند. به عنوان مثال Bootstrap یکی از محبوبترین "front-end
framework" ها است که امکان تغییر در ظاهر المنتها را فراهم میکند و شامل
تعدادی کامپوننت جاوااسکریپتی نیز میباشد. مشکل کار، در هنگام استفاده از کامپوننت ها است. شخصی که در حال توسعهی HTML است
باید در کد جاوااسکریپتی خود از jQuery استفاده کند و بعنوان مثال یک Popover را فعال یا غیر فعال کند و این، یک فرآیند خسته کننده و مستعد خطا
است.
یک مثال ساده از Directives AngularJS و بررسی آن
var m = angular.module("myApp"); myApp.directive("myDir", function() { return { restrict: "E", scope: { name: "@", amount: "=", save: "&" }, template: "<div>" + " {{name}}: <input ng-model='amount' />" + " <button ng-click='save()'>Save</button>" + "</div>", replace: true, transclude: false, controller: [ "$scope", function ($scope) { … }], link: function (scope, element, attrs, controller) {…} } });
به الگوی نامگذاری directive دقت کنید. پیشوند my شبیه به یک namespace است. بنابراین اگر یک Application از دایرکتیوهای قرار گرفته در Module های متفاوت استفاده کند، به راحتی میتوان محل تعریف یک directive را تشخیص داد. این نام میتواند نشان دهندهی این باشد که این directive را خودتان توسعه دادهاید یا از یک directive توسعه داده شده توسط شخص دیگری در حال استفاده هستید. به هر حال این نحوهی نام گذاری یک اجبار نیست و به عنوان یک پیشنهاد است.
سازنده directive یک شیء را با تعدادی خاصیت باز میگرداند که تمامی آنها در سایت AngularJS توضیح داده شدهاند. در اینجا قصد داریم تا توضیحی مختصر در مورد کاری که این خصوصیات انجام میدهند داشته باشیم.
· restrict : تشخیص میدهد که آیا directive در HTML استفاده خواهد شد. گزینههای قابل استفاده ‘A’ ، ‘E’ ، ‘C’ برای attribute ، element ، class و یا comment است . پیش فرض ‘A’ برای attribute است. اما ما بیشتر علاقه به استفاده از ویژگی element برای ایجاد المنتهای UI داریم.
· scope : ایجاد یک scope ایزوله که متعلق به directive است و موجب ایزوله شدن آن از scope صدا زننده directive میشود. متغیرهای scope پدر از طریق خصوصیات تگ directive ارسال میشوند. این ایزوله کردن زمانی کاربردی است که در حال ایجاد کامپوننت هایی با قابلیت استفاده مجدد هستیم، که نباید متکی به scope پدر باشند. شیء scope در directive نام و نوع متغیرهای scope را تعیین میکنند. در مثال بالا سه متغیر برای scope تعریف شده است:
- name: "@" (by value, one-way) : علامت @ مشخص میکند که مقدار متغیر ارسال میشود. Directive یک رشته را دریافت میکند که شامل مقدار ارسال شده از scope پدر میباشد. Directive میتواند از آن استفاده کند، اما نمیتواند مقدار آن را در scope پدر تغییر دهد.
- amount: "=" (by reference, two-way) : علامت = مشخص میکند این متغیر با ارجاع ارسال میشود. Directive یک ارجاع به مقدار متغیر در scope اصلی دریافت میکند. مقدار میتواند هر نوع داده ای، شامل یک شیء complex یا یک آرایه باشد. Directive میتواند مقدار را در scope پدر تغییر دهد. این نوع متغیر، زمانیکه نیاز باشد directive مقدار را در scope پدر تغییر دهد، استفاده میشود.
- save: "&" (expression) : علامت & مشخص میکند این متغیر یک expression را که در scope پدر اجرا میشود، نگهداری میکند. اکنون directive قابلیت انجام کارهایی فراتر از تغییر یک مقدار را دارد. به عنوان مثال میتوان یک تابع را از scope پدر فراخوانی و نتیجهی اجرا را دریافت کرد.
· template : الگوی رشته ای که جایگزین المنت تعریف شده میشود. فرآیند جایگزینی تمامی خصوصیات را از المنت قدیمی به المنت جدید انتقال میدهد. به نحوه استفاده از متغیرهای تعریف شده در scope ایزوله دقت کنید. این مورد به شما امکان تعریف directive های macro-style را میدهد که نیاز به کد اضافهای، ندارند. اگرچه در بیشتر موارد الگو یک تگ ساده <div> است که از کدهای link که در زیر توضیح داده شده است استفاده میکند.
· replace : تعیین میکند که آیا الگوی directive باید جایگزین المنت شود. مقدار پیش فرض false است.
· transclude : تعیین کننده این است که محتوای directive باید در المنت کپی شود یا خیر. در مثال زیر المنت tab شامل المنتهای HTML دیگر است پس transclude برابر true است.
<body ng-app="components"> <h3>BootStrap Tab Component</h3> <tabs> <pane title="First Tab"> <div>This is the content of the first tab.</div> </pane> <pane title="Second Tab"> <div>This is the content of the second tab.</div> </pane> </tabs> </body>
· link : این تابع بیشتر منطق directive را شامل میشود. Link وظیفه دستکاری DOM ، ایجاد event listener ها و... را دارد. تابع Link پارامترهای زیر را دریافت میکند:
- scope : ارجاع به scope ایزوله شده directive دارد.
- element : ارجاع به المنتهای DOM که directive را تعریف کرده اند. تابع link معمولا برای دستکاری المنت از jQuery استفاده میکند. (یا از Angular's jqLite در صورتی که jQuery بارگذاری نشده باشد)
- controller : در مواقعی که از دایرکتیوهای تو در تو استفاده میشود کاربرد دارد. این پارامتر یک directive فرزند با ارجاعی به پدر را فراهم میکند، بنابراین موجب ارتباط directive ها میشود.
به عنوان مثال، این directive که پیاده سازی bootstrap tab را انجام داده است، میتوانید مشاهده نمایید.
موفق باشید
در این پست قصد دارم به نحوه بارگزاری یک PartialView با استفاده از ASP.NET MVC بپردازم.
ابتدا یک پروژه جدید ایجاد کنید. حال میخواهیم زمانیکه صفحه اصلی سایت بارگزاری میشود، لیست تمام محصولات را نمایش دهد. برای نمایش محصولات یک PartialView جدید را ایجاد میکنیم؛ همانند شکل ذیل:
حال برای ساده کردن مثال، متن ثابتی را درون این PartialView مینویسیم:
product List Partial
$(function () { $.ajax({ //مشخص کردن اکشنی که باید فراخوانی شود url: '/Home/Details', contentType: 'application/html; charset=utf-8', type: 'GET', //نوع نتیجه بازگشتی dataType: 'html' }) .success(function (result) { //زمانی که کدهای سمت سرور بدون خطا اجرا شده اند //این قسمت فراخوانی میشود و نتیجه اکشن درون متغیر //result //قرار میگیرد $('#sectionContents').html(result); }) .error(function (xhr, status) { alert(xhr.responseText); }); });
<div id="sectionContents"></div>
public ActionResult Details() { return PartialView("partial/_ProductList"); }
نتیجه اجرا به صورت زیر است: