PostgreSQL Tutorial Full Course 2022
I provide here in this PostgreSQL tutorial a full course you can use to master PostgreSQL. Postgres is an object relational database that is just as fast as MySQL that adheres more closely to SQL standards and excels at concurrency. Postgres is also superior at avoiding data corruption.
TABLE OF CONTENTS
00:00 Intro
00:30 Why Use Postgres?
01:13 What is a Database
03:12 Change Database Theme
03:53 Create a Database
04:46 Design a Database
05:50 Turn Invoice into a Database
07:04 Make a Table
12:13 Data Types
16:36 Adding Data to Table
18:15 To See Data
18:25 SELECT
19:19 Create Custom Type
20:48 Change Column Data Type
22:58 Thinking About Tables
25:37 Breaking Up Tables
27:03 Primary & Foreign Keys
32:40 Foreign & Primary Keys
33:28 Altering Tables Many Examples
53:00 Getting Data from One Table
53:40 Where
54:30 Conditional Operators
55:48 Logical Operators
58:12 Order By
59:32 Limit
1:01:45 GROUP BY
1:03:11 Distinct
1:05:00 Getting Data from Multiple Tables
1:05:21 Inner Join
1:08:50 Join 3 Tables
1:13:15 Arithmetic Operators
1:13:45 Join with Where
1:14:55 Outer Joins
1:17:03 Cross Joins
1:18:16 Unions
1:19:27 Extract
1:21:05 IS NULL
1:22:03 SIMILAR LIKE & ~
1:29:25 GROUP BY
1:31:14 HAVING
1:32:18 AGGREGATE FUNCTIONS
1:34:22 WORKING WITH VIEWS
1:45:01 SQL Functions
1:49:00 Dollar Quotes
1:50:06 Functions that Return Void
1:52:38 Get Maximum Product Price
1:53:39 Get Total Value of Inventory
1:54:26 Get Number of Customers
1:56:15 Named Parameters
2:01:30 Return a Row / Composite
2:03:38 Get Multiple Rows
2:07:08 PL/pgSQL
2:11:35 Variables in Functions
2:15:55 Store Rows in Variables
2:19:17 IN INOUT and OUT
2:21:01 Using Multiple Outs
2:25:56 Return Query Results
2:33:42 IF ELSEIF and ELSE
2:38:48 CASE Statement
2:42:01 Loop Statement
2:45:20 FOR LOOP
2:48:34 Result Sets, Blocks & Raise Notice
2:51:11 For Each and Arrays
2:53:20 While Loop
2:54:54 Continue
3:01:34 Stored Procedures
3:09:35 Triggers
3:29:25 Cursors
3:39:45 Installation
آشنایی با NHibernate - قسمت هشتم
NHProf
کار کردن با آن هم بسیار ساده است. فایل How to use.txt آنرا مطالعه کنید..
آپلود همزمان چندین فایل در Asp.Net Web Forms
چون وقتی مینویسیم btnFileUpload.PostedFiles خطا میگیره
System.Web.UI.HtmlControls.HtmlInputFile' does not contain a definition for 'PostedFiles' and no extension method 'PostedFiles' accepting a first argument of type 'System.Web.UI.HtmlControls.HtmlInputFile' could be found (are you missing a using directive or an assembly reference?)
مدلهای برنامه
using System.Collections.Generic; namespace jQueryMvcSample05.Models { public class Survey { public int Id { set; get; } public string Title { set; get; } public virtual ICollection<SurveyItem> SurveyItems { set; get; } } }
namespace jQueryMvcSample05.Models { public class SurveyItem { public int Id { set; get; } public string Title { set; get; } public int Order { set; get; } //[ForeignKey("SurveyId")] public virtual Survey Survey { set; get; } public int SurveyId { set; get; } } }
تعدادی نظر سنجی به همراه گزینههای آنها تعریف خواهند شد (یک رابطه one-to-many است). سپس توسط افزونه sortable میخواهیم ترتیب قرارگیری گزینههای آنرا مشخص کنیم یا تغییر دهیم.
منبع داده فرضی برنامه
using System.Collections.Generic; using jQueryMvcSample05.Models; namespace jQueryMvcSample05.DataSource { /// <summary> /// یک منبع داده فرضی جهت دموی سادهتر برنامه /// </summary> public static class SurveysDataSource { private static IList<Survey> _surveysCache; static SurveysDataSource() { _surveysCache = createSurveys(); } public static IList<Survey> SystemSurveys { get { return _surveysCache; } } private static IList<Survey> createSurveys() { var results = new List<Survey>(); for (int i = 1; i < 6; i++) { results.Add(new Survey { Id = i, Title = "نظر سنجی " + i, SurveyItems = new List<SurveyItem> { new SurveyItem{ Id = 1, SurveyId = i, Title = "گزینه 1", Order = 1 }, new SurveyItem{ Id = 2, SurveyId = i, Title = "گزینه 2", Order = 2 }, new SurveyItem{ Id = 3, SurveyId = i, Title = "گزینه 3", Order = 3 }, new SurveyItem{ Id = 4, SurveyId = i, Title = "گزینه 4", Order = 4 } } }); } return results; } } }
کدهای کنترلر برنامه
using System.Collections.Generic; using System.Linq; using System.Web.Mvc; using System.Web.UI; using jQueryMvcSample05.DataSource; using jQueryMvcSample05.Security; namespace jQueryMvcSample05.Controllers { public class HomeController : Controller { [HttpGet] public ActionResult Index() { var surveysList = SurveysDataSource.SystemSurveys; return View(surveysList); } [HttpPost] [AjaxOnly] [OutputCache(Location = OutputCacheLocation.None, NoStore = true)] public ActionResult SortItems(int? surveyId, string[] items) { if (items == null || items.Length == 0 || surveyId == null) return Content("nok"); updateSurvey(surveyId, items); return Content("ok"); } /// <summary> /// این متد جهت آشنایی با پروسه به روز رسانی ترتیب گزینهها در اینجا قرار گرفته است /// بدیهی است محل قرارگیری آن باید در لایه سرویس برنامه اصلی باشد /// </summary> private static void updateSurvey(int? surveyId, string[] items) { var itemIds = new List<int>(); foreach (var item in items) { itemIds.Add(int.Parse(item.Replace("item-row-", string.Empty))); } var survey = SurveysDataSource.SystemSurveys.FirstOrDefault(x => x.Id == surveyId.Value); if (survey == null) return; int order = 0; foreach (var itemId in itemIds) { order++; var surveyItem = survey.SurveyItems.FirstOrDefault(x => x.Id == itemId); if (surveyItem == null) continue; surveyItem.Order = order; } //todo: call save changes .... } } }
و کدهای View متناظر
@model IList<jQueryMvcSample05.Models.Survey> @{ ViewBag.Title = "Index"; var sortUrl = Url.Action(actionName: "SortItems", controllerName: "Home"); } <h2> نظر سنجیها</h2> @foreach (var survey in Model) { <fieldset> <legend>@survey.Title</legend> <div id="sortable-@survey.Id"> @foreach (var surveyItem in survey.SurveyItems.OrderBy(x => x.Order)) { <div id="item-row-@surveyItem.Id"> <span class="handles">::</span> @surveyItem.Title </div> } </div> </fieldset> } <div> لطفا برای تغییر ترتیب آیتمهای تعریف شده، از امکان کشیدن و رها کردن تعریف شده بر روی آیکونهای :: در کنار هر آیتم استفاده نمائید. </div> @section JavaScript { <script type="text/javascript"> $(document).ready(function () { $('div[id^="sortable"]').sortable({ handle: 'span' }).bind('sortupdate', function (e, ui) { var sortableItemId = $(ui.item).parent().attr('id'); var surveyId = sortableItemId.replace('sortable-', ''); var items = []; $('#' + sortableItemId + ' div').each(function () { items.push($(this).attr('id')); }); //alert(items.join('&')); $.ajax({ type: "POST", url: "@sortUrl", data: JSON.stringify({ items: items, surveyId: surveyId }), contentType: "application/json; charset=utf-8", dataType: "json", complete: function (xhr, status) { var data = xhr.responseText; if (xhr.status == 403) { window.location = "/login"; } else if (status === 'error' || !data || data == "nok") { alert('خطایی رخ داده است'); } else { alert('انجام شد'); } } }); }); }); </script> }
در اینجا نیاز بود تا ابتدا کدهای کنترلر و View ارائه شوند، تا بتوان در مورد ارتباطات بین آنها بهتر بحث کرد.
در ابتدای نمایش صفحه Home، رکوردهای نظرسنجیها از منبع داده دریافت شده و به View ارسال میشوند. در View برنامه یک حلقه تشکیل گردیده و این موارد رندر خواهند شد.
هر نظر سنجی با یک div بیرونی که با id مساوی sortable شروع میشود، آغاز گردیده و گزینههای آن نظر سنجی نیز توسط divهایی با id مساوی item-row شروع خواهند گردید. هر کدام از این idها حاوی id رکوردهای متناظر هستند. از این idها در کدهای برنامه جهت یافتن یک نظر سنجی یا یک ردیف مشخص برای به روز رسانی ترتیب آنها استفاده خواهیم کرد.
ادامه کار، به تنظیمات و اعمال افزونه sortable مرتبط میشود. توسط تنظیم ذیل به jQuery اعلام خواهیم کرد، هرجایی یک div با id شروع شده با sortable یافتی، افزونه sortable را به آن متصل کن:
$('div[id^="sortable"]').sortable
var sortableItemId = $(ui.item).parent().attr('id'); var surveyId = sortableItemId.replace('sortable-', ''); var items = []; $('#' + sortableItemId + ' div').each(function () { items.push($(this).attr('id')); });
data: JSON.stringify({ items: items, surveyId: surveyId })
public ActionResult SortItems(int? surveyId, string[] items)
اطلاعاتی که در اینجا دریافت میشوند در متد updateSurvey مورد استفاده قرار خواهند گرفت. بر اساس surveyId دریافتی، نظرسنجی مرتبط را یافته و سپس به گزینههای آن دست خواهیم یافت. اکنون نوبت به پردازش آرایه items دریافت شده است. این آرایه بر اساس انتخاب کاربر مرتب شده است.
دریافت کدها و پروژه کامل این قسمت
jQueryMvcSample05.zip
ارسال فایل Ajax ایی آن توسط HTML5 File API صورت میگیرد که در تمام مرورگرهای جدید پشتیبانی خوبی از آن وجود دارد. در مرورگرهای قدیمیتر، به صورت خودکار همان حالت متداول ارسال همزمان فایلها را فعال میکند (یا همان post back معمولی).
فعال سازی مقدماتی kendoUpload
ابتداییترین حالت کار با kendoUpload، فعال سازی حالت post back معمولی است؛ به شرح زیر:
<form method="post" action="submit" enctype="multipart/form-data"> <div> <input name="files" id="files" type="file" /> <input type="submit" value="Submit" class="k-button" /> </div> </form> <script> $(document).ready(function() { $("#files").kendoUpload(); }); </script>
فعال سازی حالت ارسال فایل Ajax ایی kendoUpload
برای فعال سازی ارسال Ajax ایی فایلها در Kendo UI نیاز است خاصیت async آنرا به نحو ذیل مقدار دهی کرد:
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { // async configuration saveUrl: "@Url.Action("Save", "Home")", // the url to save a file is '/save' removeUrl: "@Url.Action("Remove", "Home")", // the url to remove a file is '/remove' autoUpload: false, // automatically upload files once selected removeVerb: 'POST' }, multiple: true, showFileList: true }); }); </script>
[HttpPost] public ActionResult Save(IEnumerable<HttpPostedFileBase> files) { if (files != null) { // ... // Process the files and save them // ... } // Return an empty string to signify success return Content(""); } [HttpPost] public ContentResult Remove(string[] fileNames) { if (fileNames != null) { foreach (var fullName in fileNames) { // ... // delete the files // ... } } // Return an empty string to signify success return Content(""); }
دو دکمهی حذف با کارکردهای متفاوت در ویجت kendoUpload وجود دارند. در ابتدای کار، پیش از ارسال فایلها به سرور:
کلیک بر روی دکمهی حذف در این حالت، صرفا فایلی را از لیست سمت کاربر حذف میکند.
پس از ارسال فایلها به سرور:
اما پس از پایان عملیات ارسال، اگر کاربر بر روی دکمهی حذف کلیک کند، توسط آدرس مشخص شده توسط خاصیت removeUrl، نام فایلهای مورد نظر، برای حذف از سرور ارسال میشوند.
چند نکتهی تکمیلی
- تنظیم خاصیت autoUpload به true سبب میشود تا پس از انتخاب فایلها توسط کاربر، بلافاصله و به صورت خودکار عملیات ارسال فایلها به سرور آغاز شوند. اگر به false تنظیم شود، دکمهی ارسال فایلها در پایین لیست نمایش داده خواهد شد.
- شاید علاقمند باشید تا removeVerb را به DELETE تغییر دهید؛ بجای POST. به همین منظور میتوان خاصیت removeVerb در اینجا مقدار دهی کرد.
- با تنظیم خاصیت multiple به true، کاربر قادر خواهد شد تا توسط صفحهی دیالوگ انتخاب فایلها، قابلیت انتخاب بیش از یک فایل را داشته باشد.
- showFileList نمایش لیست فایلها را سبب میشود.
تعیین پسوند فایلهای صفحهی انتخاب فایلها
هنگامیکه کاربر بر روی دکمهی انتخاب فایلها برای ارسال کلیک میکند، در صفحهی دیالوگ باز شده میتوان پسوندهای پیش فرض مجاز را نیز تعیین کرد.
برای این منظور تنها کافی است ویژگی accept را به input از نوع فایل اضافه کرد. چند مثال در این مورد:
<!-- Content Type with wildcard. All Images --> <input type="file" id="demoFile" title="Select file" accept="image/*" /> <!-- List of file extensions --> <input type="file" id="demoFile" title="Select file" accept=".jpg,.png,.gif" /> <!-- Any combination of the above --> <input type="file" id="demoFile" title="Select file" accept="audio/*,application/pdf,.png" />
نمایش متن کشیدن و رها کردن، بومی سازی برچسبها و نمایش راست به چپ
همانطور که در تصاویر فوق ملاحظه میکنید، نمایش این ویجت راست به چپ و پیامهای آن نیز ترجمه شدهاند.
برای راست به چپ سازی آن مانند قبل تنها کافی است input مرتبط، در یک div با کلاس k-rtl محصور شود:
<div class="k-rtl k-header"> <input name="files" id="files" type="file" /> </div>
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { //... }, //... localization: { select: 'انتخاب فایلها برای ارسال', remove: 'حذف فایل', retry: 'سعی مجدد', headerStatusUploading: 'در حال ارسال فایلها', headerStatusUploaded: 'پایان ارسال', cancel: "لغو", uploadSelectedFiles: "ارسال فایلها", dropFilesHere: "فایلها را برای ارسال، کشیده و در اینجا رها کنید", statusUploading: "در حال ارسال", statusUploaded: "ارسال شد", statusWarning: "اخطار", statusFailed: "خطا در ارسال" } }); }); </script>
<style type="text/css"> div.k-dropzone { border: 1px solid #c5c5c5; /* For Default; Different for each theme */ } div.k-dropzone em { visibility: visible; } </style>
تغییر قالب نمایش لیست فایلها
لیست فایلها در ویجت kendoUpload دارای یک قالب پیش فرض است که امکان بازنویسی کامل آن وجود دارد. ابتدا نیاز است یک kendo-template را بر این منظور تدارک دید:
<script id="fileListTemplate" type="text/x-kendo-template"> <li class='k-file'> <span class='k-progress'></span> <span class='k-icon'></span> <span class='k-filename' title='#=name#'>#=name# (#=size# bytes)</span> <strong class='k-upload-status'></strong> </li> </script>
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { // ... }, // ... template: kendo.template($('#fileListTemplate').html()), // ... }); }); </script>
رخدادهای ارسال فایلها
افزونهی kendoUpload در حالت ارسال Ajax ایی فایلها، رخدادهایی مانند شروع به ارسال، موفقیت، پایان، درصد ارسال فایلها و امثال آنرا نیز به همراه دارد که لیست کامل آنها را در ذیل مشاهده میکنید:
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { // async configuration //... }, //... localization: { }, cancel: function () { console.log('Cancel Event.'); }, complete: function () { console.log('Complete Event.'); }, error: function () { console.log('Error uploading file.'); }, progress: function (e) { console.log('Uploading file ' + e.percentComplete); }, remove: function () { console.log('File removed.'); }, select: function () { console.log('File selected.'); }, success: function () { console.log('Upload successful.'); }, upload: function (e) { console.log('Upload started.'); } }); }); </script>
ارسال متادیتای اضافی به همراه فایلهای ارسالی
فرض کنید میخواهید به همراه فایلهای ارسالی به سرور، پارامتر codeId را نیز ارسال کنید. برای این منظور باید خاصیت e.data رویداد upload را به نحو ذیل مقدار دهی کرد:
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { //... }, //... localization: { }, upload: function (e) { console.log('Upload started.'); // Sending metadata to the save action e.data = { codeId: "1234567", param2: 12 //, ... }; } }); }); </script>
[HttpPost] public ActionResult Save(IEnumerable<HttpPostedFileBase> files, string codeId)
فعال سازی ارسال batch
اگر در متد Save سمت سرور یک break point قرار دهید، مشاهده خواهید کرد که به ازای هر فایل موجود در لیست در سمت کاربر، یکبار متد Save فراخوانی میشود و عملا متد Save، لیستی از فایلها را در طی یک فراخوانی دریافت نمیکند. برای فعال سازی این قابلیت تنها کافی است خاصیت batch را به true تنظیم کنیم:
<script type="text/javascript"> $(function () { $("#files").kendoUpload({ name: "files", async: { // .... batch: true }, }); }); </script>
در یک چنین حالتی باید دقت داشت که تنظیم maxRequestLength در web.config برنامه الزامی است؛ زیرا به صورت پیش فرض محدودیت 4 مگابایتی ارسال فایلها توسط ASP.NET اعمال میشود:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <!-- The request length is in kilobytes, execution timeout is in seconds --> <httpRuntime maxRequestLength="10240" executionTimeout="120" /> </system.web> <system.webServer> <security> <requestFiltering> <!-- The content length is in bytes --> <requestLimits maxAllowedContentLength="10485760"/> </requestFiltering> </security> </system.webServer> </configuration>
CREATE TABLE #Transactions ( AccountId INTEGER, TranDate DATE, TranAmt NUMERIC(8, 2) ); INSERT INTO #Transactions SELECT * FROM ( VALUES ( 1, '2011-01-15', 50),( 1, '2011-01-17', 500),( 1, '2011-01-17', 500), ( 1, '2011-01-16', 500),( 1, '2011-01-24', 75),( 1, '2011-01-26', 125), ( 1, '2011-02-28', 500),( 2, '2011-01-01', 500),( 2, '2011-01-15', 50), ( 2, '2011-01-22', 25),( 2, '2011-01-23', 125),( 2, '2011-01-26', 200), ( 2, '2011-01-29', 250),( 3, '2011-01-01', 500),( 3, '2011-01-15', 50 ), ( 3, '2011-01-22', 5000),( 3, '2011-01-25', 550),( 3, '2011-01-27', 95 ), ( 3, '2011-01-30', 2500) ) dt (AccountId, TranDate, TranAmt);
SELECT AccountId, TranDate, TranAmt, Sum(TranAmt) OVER(partition by Accountid ORDER BY TranDate RANGE UNBOUNDED PRECEDING) AS SumAmt FROM #Transactions GO
SELECT AccountId, TranDate, TranAmt, Sum(TranAmt) OVER(partition by Accountid ORDER BY TranAmt RANGE UNBOUNDED PRECEDING) AS SumAmt FROM #Transactions GO
چرا برنامه نویسی موبایل؟
با افزایش روزافزون SmartPhone ها و تبلتها، بازار تکنولوژی به این سمت سوق پیدا کردهاست. از این رو شرکتهای ارائه دهنده نرم افزاری، از این موقعیت استفاده کرده و هر کدام پلتفرم متفاوتی را برای برنامه نویسی بر روی این اسمارت فونها ارائه دادهاند. یکی از بزرگترین دغدغههای امروزه شرکتهای برنامه نویسی و توسعه نرم افزار موبایل، انتخاب درست پلتفرم برای توسعه نرم افزار میباشد. در این مقاله قصد دارم یکی از این پلت فرمها را بررسی کرده و معرفی کنم.
شرکت xamarin کار خود را در سال 2011 با ارایه نسخه Cross Platform پلتفرم .Net به نام Mono آغاز کرد. بعد از ارایه این نسخه از .Net، زامارین به کمک Mono توانست پیاده سازی بر روی Android و IOS را به نامهای MonoForAndroid و MonoTouch ارایه دهد. بعد از این نسخهها برنامه نویسان توانستند بر روی سیستم عاملهای اندروید و آی او اس به صورت Native کد خود را به زبان C# نوشته و آنها را اجرا کنند.
چرا باید از Xamarin استفاده کنم؟
در ادامه مقاله قصد دارم شما را با برخی از ویژگیهای زامارین آشنا کرده و مزایای استفاده از آن را بیان کنم.
Xamarin امکانی را فراهم کردهاست که برنامه نویسان به دو روش متفاوت قادر خواهند بود برنامههای خود را بنویسند:
Xamarin Native :1
زامارین به شما این امکان را میدهد که بتوانید به صورت مستقیم برای هر پلتفرم به صورت جداگانه برنامه نویسی کنید. در اندروید اینکار با Xamarin.Droid و در IOS اینکار با Xamarin.Touch امکانپذیر است. مزیتهای استفاده از این روش عبارتند از:
· بهره گیری از یک زبان برنامه نویسی
همانطور که میدانید یادگیری یک زبان برنامه نویسی هزینهی زیادی را برای یک سازمان و یا یک شخص به همراه دارد. در زامارین این امکان فراهم شدهاست که با استفاده از تنها یک زبان برنامه نویسی مانند C# ، برنامه نویسان بتوانند برای پلتفرمهای مختلف برنامه بنویسند. در نظر داشته باشید که UI در هر پلتفرم به صورت جداگانه پیاده سازی میشود. به طور مثال در اندروید به وسیلهی Android Xml میتوانید ظاهر برنامه خود را پیاده سازی کنید و منطقهای خود را با زبان C# برای تمامی پلت فرمها به صورت یکسان بنویسید.
· تجربه کاربری Native
زامارین به شما این امکان را خواهد داد که با استفاده از کنترلهای Native هر پلتفرم به تجربه کاربری همان پلت فرم دسترسی پیدا کنید و اپلیکیشنی با ظاهر و UX همان پلتفرم بسازید.
· استفاده 100% از امکانات هر پلتفرم
زامارین به دلیل Native بودن این امکان را به برنامه نویسان ارائه میدهد که با استفاده از یک زبان و با بکارگیری Cycle Life مخصوص هر پلتفرم، به 100% امکانات و API های هر پلتفرم دسترسی پیدا کنند.
· Performance
به دلیل اینکه برنامههای زامارین به صورت Native اجرا میشوند Performance بالایی دارند.
· دسترسی به API های موجود در .Net
شما قادر خواهید بود با دانش موجود مانند Entity Framework Code و.. به فریم ورک .Net دسترسی پیدا کرده و از API های درون آن استفاده کنید. زامارین از یکی از پیاده سازیهای .Net Standard استفاده میکند.
· استفاده مجدد از کد
در زامارین قادر خواهید بود که از کدهای خود، استفاده مجدد کرده و این امر سبب مدیریت بهتر بر روی کد، کد نویسی کمتر، هزینه نگهداری کد کمتر، توسعه راحتتر اپلیکیشن و ... میشود.
· تست خودکار
در زامارین شما میتوانید برای کدهای خود تست خودکار نوشته و آنها را به صورت خودکار تست کنید.
· Bind کردن Library های Objective-C و Java
زامارین طوری طراحی شدهاست که دست شما را در هیچگونه شرایطی نخواهد بست. شما میتوانید به صورت مستقیم کدهایی را که به زبان های Java و Objective-C نوشته شدهاند، به پروژه اضافه کرده و هیچگونه نگرانی از بابت کدهای از قبل نوشته شده که به زبانهای Objective-C و Java هستند، نداشته باشید.
· Designer
در زمارین این امکان وجود دارد که در هر پلتفرم از طریق Designer مخصوص به آن پلتفرم، UI خود را طراحی و پیاده سازی کنید.
· Async
در برنامه نویسی غیر همزمان ( Asynchronous Programming ) این امکان وجود دارد که برنامه شما بدون توقف، یک قسمت از کد را اجرا کرده و منتظر اجرای قسمتهای دیگر کد نشود؛ یا به اصطلاح برنامه از حالت Response خارج نشود. در زبانهای Java ، Objective-C و Swift اینکار باید با CallBack و به صورت Manual مدیریت شود؛ اما #C این امکان را فراهم آورده است که به راحتی اینکار را انجام داده و برنامه خود را همیشه در حالت پاسخ دهی نگه دارید.
public async Task<List<FeedItem>> GetFeedItems(DateTime date) { var feed = "http://planet.xamarin.com/feed/"; var response = await httpClient.GetStringAsync(feed); var items = await ParseFeedAsync(response); return items.Where(item => item.Published.Date == date).ToList(); }
· Parallel Programming
در برنامه نویسی موازی( Parallel Programming ) برخلاف برنامه نویسی MultiThread که بر روی یک هسته CPU اجرا میشود، بر روی چندین هسته CPU به صورت موازی اجرا میشود. زامارین از این نوع برنامه نویسی پشتیبانی میکند.
Xamarin.Forms: 2
پس از معرفی Xamarin Forms API شما میتوانید علاوه بر مزیتهایی که در بالا اشاره شد، کدهای Logic خود را با زبان C# و کدهای UI خود را با زبان XAML پیاده سازی کرده و با یک بار نوشتن کد، در پلتفرمهای مختلف خروجی خود را مشاهده کنید. مزیت استفاده از Xamarin Forms عبارتند از:
· استفاده از کد واحد برای پیاده سازی UI و Logic
یکی از بهترین مزیتهایی را که میتوان به آن اشاره نمود این است که شما کافیست یک بار کد خود را بنویسید و Xamarin Forms کد شما را در پلت فرمهای متفاوت پیاده سازی خواهد کرد.
<?xml version="1.0" encoding="UTF-8"?> <TabbedPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="MyApp.MainPage"> <TabbedPage.Children> <ContentPage Title="Profile" Icon="Profile.png"> <StackLayout Spacing="20" Padding="20" VerticalOptions="Center"> <Entry Placeholder="Username" Text="{Binding Username}"/> <Entry Placeholder="Password" Text="{Binding Password}" IsPassword="true"/> <Button Text="Login" TextColor="White" BackgroundColor="#77D065" Command="{Binding LoginCommand}"/> </StackLayout> </ContentPage> <ContentPage Title="Settings" Icon="Settings.png"> <!-- Settings --> </ContentPage> </TabbedPage.Children> </TabbedPage>
برای پیاده سازی UI در Xamarin Forms باید از XAML استفاده کنید. همچنین مانند روش قبلی میتوانید از زبان C# برای پیاده سازی منطق، استفاده نمایید.
با استفاده از Xamarin Forms شما تجربه نوشتن کد Cross Platform را در کنار Native بودن آن خواهید داشت.
· استفاده از یک کنترل مخصوص یک پلتفرم در بین کد ( Embedding )
در Xamarin Forms این امکان وجود دارد که اگر شما خواستید یک کنترل مخصوص IOS را در بین کدهای خود استفاده کنید، بتوانید به راحتی اینکار را انجام دهید.( (Embedding
اگر به تصویر بالا دقت کنید متوجه خواهید شد که در یکسری از کنترلها، تصاویر متفاوت هستند. در نسخه اندروید یک Action Button در قسمت پایین صفحه مشاهده میکنید که در نسخهی IOS آن موجود نیست. یعنی به صورت مستقیم کنترل Action Button که مختص به پلت فرم اندروید میباشد، درون Xamarin Forms استفاده شده است.
· دسترسی به هر پلتفرم به طور مستقیم
شما قادر خواهید بود به طور مستقیم به هر پلت فرم دسترسی پیدا کرده و به طور مثال در هر پلتفرم، UI مخصوص به خود را با Property های مخصوص به خود طراحی کنید.
· UITest و Test Cloud
در Xamarin Forms میتوانید برای UI خود تست نوشته و آنها را به وسیله Xamarin Test Cloud بر روی صدها Device متفاوت تست کنید. (این امکان فقط برای Android و IOS وجود دارد.)
· Life Cycle مشابه در تمامی پلتفرم ها
همانطور که میدانید پلتفرمهای مختلف، Life Cycle های متفاوتی برای مدیریت اپلیکیشن دارند. یکی از مزیتهای استفاده از Xamarin Forms این است که شما میتوانید برای تمامی پلتفرمها بهوسیلهی یک Life Cycle یکسان کد بنویسید.
· Previewer
یکی از بهترین قابلیتهایی که در Xamarin Forms اضافه شدهاست این است که شما قادر خواهید بود به صورت Real Time خروجی فایل XAML خود را به وسیله Previewer مشاهده نمایید.
· Performance Profiler
به وسیله Xamarin Profiler شما میتوانید میزان مصرف حافظه، Performance و ... را در اندروید و IOS اندازه گیری نمایید.
نکات قابل توجه:
Ø استفاده همزمان از Xamarin Forms و Xamarin Native
شما میتوانید کدهای خود را با حداکثر Reusability نوشته و در صورت لزوم با کدهای Xamarin Native ترکیب کنید.
Ø Documentation خیلی خوب
زمارین مستندات جامع و کاملی را در سایت خود گردآوری کرده که میتوانید به راحتی از آن برای فهم تمامی قسمتهای Xamarin استفاده کنید.
در این قسمت قصد داریم یک فرم Ajaxایی را در ASP.NET MVC به همراه تمام مسایل اعتبارسنجی، پردازش اطلاعات و غیره را به کمک Twitter Bootstrap و jQuery Ajax پیاده سازی کنیم.
تهیه افزونه jquery.bootstrap-modal-ajax-form.js
از این جهت که مباحث مرتبط با نمایش و پردازش فرمهای مودال Ajaxایی به کمک Twitter Bootstrap اندکی نکته دار و طولانی هستند، بهتر است این موارد را به شکل یک افزونه، کپسوله کنیم. کدهای کامل افزونه jquery.bootstrap-modal-ajax-form.js را در ادامه ملاحظه میکنید:
// <![CDATA[ (function ($) { $.bootstrapModalAjaxForm = function (options) { var defaults = { renderModalPartialViewUrl: null, renderModalPartialViewData: null, postUrl: '/', loginUrl: '/login', beforePostHandler: null, completeHandler: null, errorHandler: null }; var options = $.extend(defaults, options); var validateForm = function (form) { //فعال سازی دستی اعتبار سنجی جیکوئری var val = form.validate(); val.form(); return val.valid(); }; var enableBootstrapStyleValidation = function () { $.validator.setDefaults({ highlight: function (element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).addClass(errorClass).removeClass(validClass); } else { $(element).addClass(errorClass).removeClass(validClass); $(element).closest('.control-group').removeClass('success').addClass('error'); } $(element).trigger('highlited'); }, unhighlight: function (element, errorClass, validClass) { if (element.type === 'radio') { this.findByName(element.name).removeClass(errorClass).addClass(validClass); } else { $(element).removeClass(errorClass).addClass(validClass); $(element).closest('.control-group').removeClass('error').addClass('success'); } $(element).trigger('unhighlited'); } }); } var enablePostbackValidation = function () { $('form').each(function () { $(this).find('div.control-group').each(function () { if ($(this).find('span.field-validation-error').length > 0) { $(this).addClass('error'); } }); }); } var processAjaxForm = function (dialog) { $('form', dialog).submit(function (e) { e.preventDefault(); if (!validateForm($(this))) { //اگر فرم اعتبار سنجی نشده، اطلاعات آن ارسال نشود return false; } //در اینجا میتوان مثلا دکمهای را غیرفعال کرد if (options.beforePostHandler) options.beforePostHandler(); //اطلاعات نباید کش شوند $.ajaxSetup({ cache: false }); $.ajax({ url: options.postUrl, type: "POST", data: $(this).serialize(), success: function (result) { if (result.success) { $('#dialogDiv').modal('hide'); if (options.completeHandler) options.completeHandler(); } else { $('#dialogContent').html(result); if (options.errorHandler) options.errorHandler(); } } }); return false; }); }; var mainContainer = "<div id='dialogDiv' class='modal hide fade in'><div id='dialogContent'></div></div>"; enableBootstrapStyleValidation(); //اعمال نکات خاص بوت استرپ جهت اعتبارسنجی یکپارچه با آن $.ajaxSetup({ cache: false }); $.ajax({ type: "POST", url: options.renderModalPartialViewUrl, data: options.renderModalPartialViewData, contentType: "application/json; charset=utf-8", dataType: "json", complete: function (xhr, status) { var data = xhr.responseText; var data = xhr.responseText; if (xhr.status == 403) { window.location = options.loginUrl; //در حالت لاگین نبودن شخص اجرا میشود } else if (status === 'error' || !data) { if (options.errorHandler) options.errorHandler(); } else { var dialogContainer = "#dialogDiv"; $(dialogContainer).remove(); $(mainContainer).appendTo('body'); $('#dialogContent').html(data); // دریافت پویای اطلاعات مودال دیالوگ $.validator.unobtrusive.parse("#dialogContent"); // فعال سازی اعتبارسنجی فرمی که با ایجکس بارگذاری شده enablePostbackValidation(); // و سپس نمایش آن به صورت مودال $('#dialogDiv').modal({ backdrop: 'static', //با کلیک کاربر روی صفحه، صفحه مودال بسته نمیشود keyboard: true }, 'show'); // تحت نظر قرار دادن این فرم اضافه شده processAjaxForm('#dialogContent'); } } }); }; })(jQuery); // ]]>
- توابع enableBootstrapStyleValidation و enablePostbackValidation در مطلب «اعمال کلاسهای ویژه اعتبارسنجی Twitter bootstrap به فرمهای ASP.NET MVC» بررسی شدند.
- این افزونه با توجه به مقدار renderModalPartialViewUrl، یک partial view را از برنامه ASP.NET MVC درخواست میکند.
- سپس این partial view را به صورت خودکار به صفحه اضافه کرده و آنرا به صورت modal نمایش میدهد.
- پس از افزودن فرم Ajaxایی دریافتی، مسایل اعتبارسنجی را به آن اعمال کرده و سپس دکمه submit آنرا تحت کنترل قرار میدهد.
- در زمان submit، ابتدا بررسی میکند که آیا فرم معتبر است و اعتبارسنجی آن بدون مشکل است؟ اگر اینچنین است، اطلاعات فرم را به آدرس postUrl به صورت Ajaxایی ارسال میکند.
کدهای مدل برنامه
using System.ComponentModel; using System.ComponentModel.DataAnnotations; namespace Mvc4TwitterBootStrapTest.Models { public class User { public int Id { set; get; } [DisplayName("نام")] [Required(ErrorMessage="لطفا نام را تکمیل کنید")] public string Name { set; get; } [DisplayName("نام خانوادگی")] [Required(ErrorMessage = "لطفا نام خانوادگی را تکمیل کنید")] public string LastName { set; get; } } }
کدهای کنترلر برنامه
using System.Web.Mvc; using Mvc4TwitterBootStrapTest.Models; namespace Mvc4TwitterBootStrapTest.Controllers { public class ModalFormAjaxController : Controller { [HttpGet] public ActionResult Index() { return View(); //نمایش صفحه اولیه } [HttpPost] //برای این حالت امنتر است //[AjaxOnly] public ActionResult RenderModalPartialView() { //رندر پارشال ویوو صفحه مودال به همراه اطلاعات مورد نیاز آن return PartialView(viewName: "_ModalPartialView", model: new User { Name = "", LastName = "" }); } [HttpPost] //[AjaxOnly] public ActionResult Index(User user) //ذخیره سازی اطلاعات { if (this.ModelState.IsValid) { //todo: SaveChanges; return Json(new { success = true }); } this.ModelState.AddModelError("", "خطایی رخ داده است"); return PartialView("_ModalPartialView", user); } } }
الف) متد Index حالت HttpGet که صفحه ابتدایی را نمایش خواهد داد.
ب) متد RenderModalPartialView یک partial view اضافه شده به برنامه به نام _ModalPartialView.cshtml را بازگشت میدهد. این partial view در حقیقت همان فرمی است که قرار است به صورت مودال نمایش داده شود و پردازش آن نیز Ajaxایی باشد.
ج) متد Index حالت HttpPost که نهایتا اطلاعات فرم مودال را دریافت خواهد کرد. اگر پردازش موفقیت آمیز بود، نیاز است همانند کدهای فوق return Json صورت گیرد. در غیراینصورت مجددا همان partial view را بازگشت دهید.
کدهای Index.cshtml
@{ ViewBag.Title = "Index"; var renderModalPartialViewUrl = Url.Action("RenderModalPartialView", "ModalFormAjax"); var postDataUrl = Url.Action("Index", "ModalFormAjax"); } <h2> Index</h2> <a href="#" class="btn btn-primary" id="btnCreate">ثبت اطلاعات</a> @section JavaScript { <script type="text/javascript"> $(function () { $('#btnCreate').click(function (e) { e.preventDefault(); //میخواهیم لینک به صورت معمول عمل نکند $.bootstrapModalAjaxForm({ postUrl: '@postDataUrl', renderModalPartialViewUrl: '@renderModalPartialViewUrl', renderModalPartialViewData: {}, loginUrl: '/login', beforePostHandler: function () { }, completeHandler: function () { // Refresh: برای حالتیکه نیاز به به روز رسانی کامل صفحه زیرین باشد // location.reload(); }, errorHandler: function () { } }); }); }); </script> }
- در اینجا یک لینک ساده در صفحه قرار گرفته و به کمک کلاس btn مجموعه bootstrap به شکل یک دکمه مزین شده است.
- در ادامه نحوه استفاده از افزونهای را که در ابتدای بحث طراحی کردیم، ملاحظه میکنید. کار با آن بسیار ساده است و تنها باید مسیرهای ارسال اطلاعات نهایی به سرور یا postDataUrl و مسیر دریافت partial view رندر شده یا renderModalPartialViewUrl به آن معرفی شود. سایر مسایل آن خودکار است.
کدهای _ModalPartialView.cshtml یا همان فرم مودال برنامه
@model Mvc4TwitterBootStrapTest.Models.User <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-hidden="true"> ×</button> <h5> افزودن کاربر جدید</h5> </div> @using (Html.BeginForm("Index", " ModalFormAjax", FormMethod.Post, new { @class = "modal-form" })) { <div class="modal-body"> @Html.ValidationSummary(true, null, new { @class = "alert alert-error alert-block" }) <fieldset class="form-horizontal"> <legend>مشخصات کاربر</legend> <div class="control-group"> @Html.LabelFor(model => model.Name, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.Name) @Html.ValidationMessageFor(model => model.Name, null, new { @class = "help-inline" }) </div> </div> <div class="control-group"> @Html.LabelFor(model => model.LastName, new { @class = "control-label" }) <div class="controls"> @Html.EditorFor(model => model.LastName) @Html.ValidationMessageFor(model => model.LastName, null, new { @class = "help-inline" }) </div> </div> </fieldset> </div> <div class="modal-footer"> <button class="btn btn-primary" type="submit"> ارسال</button> <button class="btn" data-dismiss="modal" aria-hidden="true"> انصراف</button> </div> }
حاصل نهایی این مبحث را در دو شکل ذیل ملاحظه میکنید. صفحه index نمایش دهنده یک دکمه و در ادامه باز شدن یک فرم مودال، پس از کلیک بر روی دکمه ثبت اطلاعات.
ارتباطات بلادرنگ و SignalR
+ دورهها در سایت قسمتی دارند جهت پرسش و پاسخ اختصاصی که میشود مشکلات و سؤالات مرتبط به دوره را در آنجا ارسال کرد با توضیح بیشتر.