This is an initial release of a partial implementation of the .NET platform on top of the Java Virtual Machine, and compatible with Android runtime. The Bluebonnet bytecode compiler translates .NET CIL into Java bytecode in Java classes, and additional run-time support is provided by the Baselib library.
This release is primarily focused on bug fixes, but it contains a few new features as well.
Here’s what’s new in this release for ASP.NET Core:
- Partial class support for Razor components
- Pass parameters to top-level components
- Support for shared queues in HttpSysServer
- Breaking changes for SameSite cookies
Akita is a state management pattern, built on top of RxJS, which takes the idea of multiple data stores from Flux and the immutable updates from Redux, along with the concept of streaming data, to create the Observable Data Stores model.
The .NET team has built a linker to reduce the size of .NET Core applications. It is built on top of the excellent and battle-tested mono linker. The Xamarin tools also use this linker so it makes sense to try it out and perhaps use it everywhere!
UI-Router ابزاری برای مسیریابی در AngularJS است که این امکان را برایتان فراهم میکند تا بخشهای برنامه رابط کاربریتان را به شکل یک ماشین حالت ساماندهی کنید. برخلاف سرویس route$ که بر اساس مسیریابی URLها ساماندهی شده و کار میکند، UI-Router بر اساس حالتها کار میکند، که این حالتها میتوانند در صورت لزوم مسیریابی هم داشته باشند.
UI-Router یکی از افزونههای مجموعه Angular-ui، و پاراگراف بالا معرفی آن در صفحه خانگیش است (تقریبا!). این افزونه جزئیات مفصلی دارد و در این مطلب تنها به معرفی آن خواهم پرداخت (بر اساس مطالب صفحه خانگیش). پیش از ادامه پیشنهاد میکنم اگر مطالب زیر را نخواندهاید ابتدا آنها را مرور کنید:
برای استفاده از UI-Router باید:
- فایل جاوا اسکریپت آن را دانلود کنید (released یا minified).
- در صفحه اصلی برنامهتان پس از include کردن فایل اصلی AngularJS فایل angular-ui-router.js (یا angular-ui-router.min.js) را include کنید.
- 'ui.router' را به لیست وابستگیهای ماژول اصلی اضافه کنید.
<!doctype html> <html ng-app="myApp"> <head> <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.1.5/angular.min.js"></script> <script src="js/angular-ui-router.min.js"></script> <script> var myApp = angular.module('myApp', ['ui.router']); // For Component users, it should look like this: // var myApp = angular.module('myApp', [require('angular-ui-router')]); </script> ... </head> <body> ... </body> </html>
حالتها و viewهای تو در تو
قابلیت اصلی UI-Router امکان تعریف حالتها و vieweهای تو در تو است. در مطلب مسیریابی در AngularJs #بخش اول دایرکتیو ng-view معرفی شده است. هنگام استفاده از سرویس route$ با این دایرکتیو میتوان محل مورد نظر برای بارگذاری محتویات مربوط به مسیرها را مشخص کرد. دایرکتیو ui-view در UI-Router همین نقش را دارد. فرض کنید این کد فایل index.html باشد:<!-- index.html --> <body> <div ui-view></div> <!-- We'll also add some navigation: --> <a ui-sref="state1">State 1</a> <a ui-sref="state2">State 2</a> </body>
در ادامه برای هر کدام از حالتها یک template اضافه میکنیم:
فایل state1.html:
<!-- partials/state1.html --> <h1>State 1</h1> <hr/> <a ui-sref="state1.list">Show List</a> <div ui-view></div>
<!-- partials/state2.html --> <h1>State 2</h1> <hr /> <a ui-sref="state2.list">Show List</a> <div ui-view></div>
دو نکته قابل توجه در این templateها وجود دارد. اول اینکه همانطور که میبینید templateها خود شامل تگی با دایرکتیو ui-view هستند. و دوم مقدار دایرکتیو ui-sref است که به صورت state1.list و state2.list آمده است. این جدا سازی با نقطه نشان دهنده سلسله مراتب حالتهاست. یعنی حالتهای state1 و state2 هرکدام حالت فرزندی به نام list دارند. در ادامه وقتی حالتها و مسیریابی را در ()app.config تعریف کنیم این مسائل از هالهای از ابهام که در آن هستند خارج میشوند! فعلا بیاید با راهنمای UI-Router پیش برویم و فایلهای template حالتهای فرزند را تعریف کنیم. templateهایی که قرار است در ui-view پدرانشان بارگذاری شوند:
<!-- partials/state1.list.html --> <h3>List of State 1 Items</h3> <ul> <li ng-repeat="item in items">{{ item }}</li> </ul>
<!-- partials/state2.list.html --> <h3>List of State 2 Things</h3> <ul> <li ng-repeat="thing in things">{{ thing }}</li> </ul>
myApp.config(['$stateProvider', '$urlRouterProvider', function($stateProvider, $urlRouterProvider) { // // For any unmatched url, redirect to /state1 $urlRouterProvider.otherwise("/state1"); // // Now set up the states $stateProvider .state('state1', { url: "/state1", templateUrl: "partials/state1.html" }) .state('state1.list', { url: "/list", templateUrl: "partials/state1.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } }) .state('state2', { url: "/state2", templateUrl: "partials/state2.html" }) .state('state2.list', { url: "/list", templateUrl: "partials/state2.list.html", controller: function($scope) { $scope.things = ["A", "Set", "Of", "Things"]; } }) }]);
خصوصیت url مشخص کننده مسیر حالت است. این خصوصیت همان مقداریست که به عنوان پارامتر اول به ()routeProvider.when$ پاس میشد. در این پارامتر میشود متغیرهای url را هم به همان ترتیب تعریف کرد. مثلا اگر حالت state1 در آدرسش یک پارامتر id داشته باشد میشود آن را به این ترتیب تعریف کرد:
.state('state1', { url: "/state1/:id", templateUrl: "partials/state1.html" })
$stateParams.id
.state('list', { parent: "state1", url: "/list", templateUrl: "partials/state1.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } }) .state('list', { parent: "state2", url: "/list", templateUrl: "partials/state2.list.html", controller: function($scope) { $scope.items = ["A", "List", "Of", "Items"]; } })
- وابستگیهای فراهم شده در حالت پدر به وسیله "resolve"
- دادههای سفارشی مشخص شده در خصوصیت data حالت پدر
.state('state1', { url: "/state1", templateUrl: "partials/state1.html", data:{ foodata: 'addorder' } })
$state.current.data.foodata
Viewهای نامگذاری شده و چندگانه
<!-- index.html --> <body> <div ui-view="viewA"></div> <div ui-view="viewB"></div> <!-- Also a way to navigate --> <a ui-sref="route1">Route 1</a> <a ui-sref="route2">Route 2</a> </body>
myApp.config(function ($stateProvider) { $stateProvider .state('index', { url: "", views: { "viewA": { template: "index.viewA" }, "viewB": { template: "index.viewB" } } }) .state('route1', { url: "/route1", views: { "viewA": { template: "route1.viewA" }, "viewB": { template: "route1.viewB" } } }) .state('route2', { url: "/route2", views: { "viewA": { template: "route2.viewA" }, "viewB": { template: "route2.viewB" } } }) });
چند نکته
.state('list', { parent: "state1", url: "/list", templateUrl: "partials/state1.list.html", controller: "state1ListController as listCtrl1" } }) .state('list', { parent: "state2", url: "/list", templateUrl: "partials/state2.list.html", controller: "state2ListController as listCtrl2" } })
حالتهای انتزاعی
حساسیت به حروف بزرگ و کوچک
- در فایل "angular-ui-router.js" عبارت "new RegExp(compiled)" را پیدا کرده و آن را به "RegExp(compiled, 'i')" تبدیل کنید. و یا در "angular-ui-router.min.js" (هرکدام از فایلها که استفاده میکنید) عبارت new RegExp(o) را پیدا کرده و آن را به new RegExp(o, "i") تبدیل کنید. همین؛ صدایش را هم در نیاورید!
<embed height="400" width="500" flashvars="config=http://www.aparat.com//video/video/config/videohash/BA9Md/watchtype/embed" allowfullscreen="true" quality="high" name="aparattv_BA9Md" id="aparattv_BA9Md" src="http://host10.aparat.com/public/player/aparattv" type="application/x-shockwave-flash">
using System.Web.Mvc; namespace MvcApplication1 { public static class AparatPlayerHelper { public static MvcHtmlString AparatPlayer(this HtmlHelper helper, string mediafile, int height, int width) { var player = @"<embed height=""{0}"" width=""{1}"" flashvars=""config=http://www.aparat.com//video/video/config/videohash/{2}/watchtype/embed"" allowfullscreen=""true"" quality=""high"" name=""aparattv_{2}"" id=""aparattv_{2}"""" src=""http://host10.aparat.com/public/player/aparattv"" type=""application/x-shockwave-flash"">"; player = string.Format(player, height, width, mediafile); return new MvcHtmlString(player); } } }
@Html.AparatPlayer("BA9Md", 400, 500)
using System; using System.Drawing; using System.Web.Mvc; namespace MvcApplication1 { public static class YouTubePlayerHelper { public static MvcHtmlString YouTubePlayer(this HtmlHelper helper, string playerId, string mediaFile, YouTubePlayerOption youtubePlayerOption) { const string baseURL = "http://www.youtube.com/v/"; // YouTube Embedded Code var player = @"<div id=""YouTubePlayer_{7}""width:{1}px; height:{2}px;""> <object width=""{1}"" height=""{2}""> <param name=""movie"" value=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}""></param> <param name=""allowFullScreen"" value=""true""></param> <embed src=""{6}{0}&fs=1&border={3}&color1={4}&color2={5}"" type = ""application/x-shockwave-flash"" width=""{1}"" height=""{2}"" allowfullscreen=""true""></embed> </object> </div>"; // Replace All The Value player = String.Format(player, mediaFile, youtubePlayerOption.Width, youtubePlayerOption.Height, (youtubePlayerOption.Border ? "1" : "0"), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.PrimaryColor), ConvertColorToHexa.ConvertColorToHexaString(youtubePlayerOption.SecondaryColor), baseURL, playerId); //Retrun Embedded Code return new MvcHtmlString(player); } } public class YouTubePlayerOption { int _width = 425; int _height = 355; Color _color1 = Color.Black; Color _color2 = Color.Aqua; public YouTubePlayerOption() { Border = false; } public int Width { get { return _width; } set { _width = value; } } public int Height { get { return _height; } set { _height = value; } } public Color PrimaryColor { get { return _color1; } set { _color1 = value; } } public Color SecondaryColor { get { return _color2; } set { _color2 = value; } } public bool Border { get; set; } } public class ConvertColorToHexa { private static readonly char[] HexDigits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static string ConvertColorToHexaString(Color color) { var bytes = new byte[3]; bytes[0] = color.R; bytes[1] = color.G; bytes[2] = color.B; var chars = new char[bytes.Length * 2]; for (int i = 0; i < bytes.Length; i++) { int b = bytes[i]; chars[i * 2] = HexDigits[b >> 4]; chars[i * 2 + 1] = HexDigits[b & 0xF]; } return new string(chars); } } }
@Html.YouTubePlayer("Casablanca", "iLdqKUkkM6w", new YouTubePlayerOption() { Border = true })
string name = "Vahid", country = "Iran"; string jsonString = $$""" { "Name": {{name}}, "Country": {{country}} } """; Console.WriteLine(jsonString);
"{\r\n \"Name\": Vahid,\r\n \"Country\": Iran\r\n}"
و یا امکان درج سادهتر عبارات XML، بدون نیاز به escape قسمتی از آن:
string html = """ <body style="normal"> <div class="book-content"> This is information about the "C# 11" book. </body> <footer> This is information about the author of the "C# 11" book. </footer> </element> """;
سؤال: اگر در محتوای Raw String Literal تعریف شده، نیاز به سه عدد " متوالی وجود داشت، چه باید کرد؟
اگر به توضیحات فوق دقت کنید، عنوان شد که شروع و پایان Raw String Literals، با «حداقل» سه عدد " همراه است و به این صورت پیاده سازی میشود:
- اگر رشتهی شما نیاز به سه "" متوالی داشت، باید raw string literal را با حداقل چهار " شروع و خاتمه دهید.
- اگر رشتهی شما نیاز به چهار "" متوالی داشت، باید raw string literal را با حداقل پنج " شروع و خاتمه دهید.
و ... به همین ترتیب برای مابقی حالات.
var text1 = """" Hello World! """ """"; var text2 = """"" Hello World! """" """"";
کاهش فواصل سمت چپ رشتهها، با استفاده از Raw string literals
به مثال زیر که یک قطعه چند سطری SQL را به دو روش قدیم و جدید تعریف میکند، دقت کنید (فواصل سمت چپ در این مثال مهم هستند):
var sql1 = @" SELECT Name FROM Customers WHERE id = @id "; Console.WriteLine(sql1); var sql2 = """ SELECT Name FROM Customers WHERE id = @id """; Console.WriteLine(sql2);
پاسخ: خیر! خروجی نمایشی این دو به صورت زیر است:
SELECT Name FROM Customers WHERE id = @id SELECT Name FROM Customers WHERE id = @id
خروجی واقعی رشتهی sql1 به صورت زیر است:
"\r\n SELECT Name\r\n FROM Customers\r\n WHERE id = @id\r\n "
"SELECT Name\r\nFROM Customers\r\nWHERE id = @id"
استفاده از string interpolation در raw string literals
همیشه عبارات ما از رشتههای ثابت تشکیل نمیشوند. در این بین همواره نیاز به interpolation با مقادیر ثابت و یا متغیرها وجود خواهد داشت. انجام چنین کاری با raw string literals هم میسر است:
var name = "Vahid"; var text = $""" Hello {name1}! Welcome to the Team! """;
سؤال: اگر در این مثال نیاز بود تا از {} جهت مقاصد نمایشی استفاده شود، چه باید کرد؟ یعنی نیاز به درج {} صرفا متنی وجود داشت.
پاسخ: در اینجا تنها کاری را که باید انجام داد، استفاده از یک $ اضافهتر در ابتدای interpolated string است (مانند مثال ابتدای بحث):
var name1 = "Vahid"; var text = $$""" Hello {{{name1}}}! Welcome to the Team! """;
"Hello {Vahid}!\r\n\r\nWelcome to the Team!"
سؤال: اگر در این مثال نیاز بود تا از {{{}}} جهت مقاصد نمایشی استفاده شود، چه باید کرد؟
پاسخ: باید تعداد $های ابتدای رشته را افزایش داد. برای مثال اگر نیاز به درج سه { متوالی است، باید از 4 عدد $ در ابتدای رشته استفاده کرد:
var name4 = "Vahid"; var text4 = $$$$""" Hello {{{{{{{name4}}}}}}}! Welcome to the Team! """;
"Hello {{{Vahid}}}!\r\nWelcome to the Team!"
string name = "Vahid"; var text1 = $"{name}"; var text2 = $"""{name}"""; var text3 = $$"""{{name}}"""; var text4 = $$$"""{{{name}}}"""; var text5 = $$$$"""{{{{name}}}}""";
اما در مثال زیر، تعداد $ها با تعداد {}ها یکی نیست؛ برای مثال اگر از دو $ ابتدایی استفاده شود، ذکر یک جفت تکی {}، تنها به معنای وجود کاراکتری آنها است و همینطور اگر از سه $ ابتدایی استفاده شود، ذکر یک جفت دو تایی {{}}، تنها به معنای وجود کاراکتری آنها است و همینطور الی آخر. اما اگر معادل تعداد $ها، از جفتهای {} استفاده شود، تمام آنها با هم فقط یک interpolation expression delimiter را تشکیل میدهند.
string name = "Vahid"; var text6 = $$"""{name}"""; // = "{name}" var text7 = $$"""{{{name}}}"""; // = "{Vahid}" var text8 = $$$"""{{name}}"""; // = "{{name}}" var text9 = $$$"""{{{{{name}}}}}"""; // = "{{Vahid}}" var text10 = $$$$"""{{{name}}}"""; // = "{{{name}}}" var text11 = $$$$"""{{{{{{{name}}}}}}}"""; // = "{{{Vahid}}}"
public static string funConvertToStandard(string inputString) { //تبدیل اعداد فارسی به انگلیسی جهت ذخیره سازی یکنواخت در بانک inputString = inputString.Replace("٠", "0"); inputString = inputString.Replace("١", "1"); inputString = inputString.Replace("٢", "2"); inputString = inputString.Replace("٣", "3"); inputString = inputString.Replace("۴", "4"); inputString = inputString.Replace("۵", "5"); inputString = inputString.Replace("۶", "6"); inputString = inputString.Replace("٧", "7"); inputString = inputString.Replace("٨", "8"); inputString = inputString.Replace("٩", "9"); //تبدیل ی و ک عربی بهی و ک فارسی inputString = inputString.Replace((char)1609, (char)1740); inputString = inputString.Replace((char)1610, (char)1740); inputString = inputString.Replace((char)1603, (char)1705); //یکنواخت سازی نیم فاصله //inputString = inputString.Replace("", "");//تبدیل نیم فاصله 8207 به نیم فاصله 8204 return inputString.Trim(); }
آشنایی با Leaflet
<script src="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.js"></script> <link rel="stylesheet" href="http://cdn.leafletjs.com/leaflet-0.7.3/leaflet.css" />
#map { height: 600px; }
var map = L.map('map').setView([29.6760859,52.4950737], 13);
var osmUrl='http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'; var osmAttrib='Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors'; var osm = new L.TileLayer(osmUrl, { maxZoom: 18, attribution: osmAttrib}).addTo(map);
Marker، دایره و چندضلعی
در کنار نمایش Tileها میتوان اشکال گرافیکی نیز به نقشه اضافه کرد؛ مثل مارکر(نقطه)، مستطیل، دایره و یا یک Popup. اضافه کردن یک Marker به سادگی، با کد زیر صورت میپذیرد:
var marker = L.marker([29.623116,52.497856]).addTo(map);
محل مورد نظر به شیء مارکر پاس داده شده و مقدار بازگشتی به map اضافه شده است.
نمایش چند ضلعی و دایره هم کار ساده ای است. برای دایره باید ابتدا مختصات مرکز دایره و شعاع به متر را به L.circle پاس داد:
var circle = L.circle([29.6308217,52.5048021], 500, { color: 'red', fillColor: '#f03', fillOpacity: 0.5 }).addTo(map);
در کد بالا علاوه بر محل و اندازه دایره، رنگ محیط، رنگ داخل و شفافیت (opacity) نیز مشخص شدهاند.
برای چند ضلعیها میتوان به این صورت عمل کرد:
var polygon = L.polygon([ [29.628453, 52.488838], [29.637368, 52.493987], [29.637168, 52.503987] ]).addTo(map);
کار کردن با Popup ها
از Popup میتوان برای نمایش اطلاعات اضافهای بر روی یک محل خاص یا یک عنوان به مانند Marker استفاده کرد. برای مثال میتوان اطلاعاتی دربارهی محل یک Marker یا دایره نمایش داد. در هنگام ایجاد marker، دایره و چندضلعی مقادیر بازگشتی در متغیرهای جدایی ذخیره شدند. اکنون میتوان به آن اشیاء یک popup اضافه کرد:
marker.bindPopup("باغ عفیف آباد").openPopup(); circle.bindPopup("I am a circle."); polygon.bindPopup("I am a polygon.");
به علت اینکه openPopup برای Marker صدا زده شده، به صورت پیشفرض popup را نمایش میدهد. اما برای بقیه، نمایش با کلیک خواهد بود. البته الزاما نیازی نیست که popup روی یک شیء نمایش داده شود، میتوان popupهای مستقلی نیز ایجاد کرد:
var popup = L.popup() .setLatLng([51.5, -0.09]) .setContent("I am a standalone popup.") .openOn(map);