[Required(ErrorMessage = "(*)"), DisplayName("نام")] [MaxLength(3,ErrorMessage="لطفا بیشتر از 3 کاراکتر وارد ننمایید")] public string Name { set; get; }
معرفی کتابخانهی DNTPersianUtils.Core
Cannot implicitly convert type 'System.DateTime?' to 'System.DateTime'. An explicit conversion exists
[Parameter(CaptureUnmatchedValues = true)] public IReadOnlyDictionary<string, object>? AdditionalAttributes { get; set; }
[Parameter, EditorRequired] public string Title { get; set; }
[Required(ErrorMessageResourceType = typeof(ValidationErrorsResource), ErrorMessageResourceName = ResourceKeys.ValidationErrorsResource.RequiredField)] [MaxLength] [DisplayName("متن")] [AllowHtml] public string FullDescription { get; set; }
<div>متن: </div> <div>@Html.TextAreaFor(p => p.FullDescription)</div> <div>@Html.ValidationMessageFor(p => p.FullDescription)</div> $('#FullDescription').redactor({ autoformat: false, convertDivs: false });
معرفی برخی عملگرها
در مقالات قبلی مقدماتی را جهت ورود به برنامه نویسی شیء گرا در جاوا اسکریپت مطرح کردیم و در اینجا نیز به معرفی برخی عملگرها میپردازیم که در برنامه نویسی شیء گرا نقشی اساسی را ایفا میکنند.
عملگر typeof
از آنجائیکه جاوا اسکریپت دارای نوع دادهای ضعیف یا Loosely Typed میباشد، باید در بکارگیری متغیرها و یا آرگومانهای ورودی توابع، دقت لازم را داشته باشیم تا خطایی در اجرای کد یا محاسبات به وجود نیاید. بنابراین به راهکارهایی نیاز داریم تا بتوانیم نوع دادهای یک متغیر را تشخیص دهیم و قبل از بکارگیری آنها صحت و اعتبار دادههای ورودی را بررسی کنیم. با استفاده از عملگر typeof میتوانیم نوع دادهای یک متغیر را تشخیص دهیم که برای هر نوع دادهای مقادیر زیر را بر میگرداند:
· برای متغیرهایی که شامل مقدار undefined میباشند مقدار "undefined"
· برای متغیرهای منطقی یا Boolean مقدار "boolean"
· برای متغیرهای رشتهای یا String مقدار "string"
· برای متغیرهای عددی و مقادیر NaN و Infinity مقدار "number"
· برای تابع مقدار "function"
· برای اشیا و مقادیر null مقدار "object"
var x; var n = 12; var obj = {}; var fn = function () { }; var a = new Array(); alert(typeof x); // "undefined" alert(typeof n); // "number" alert(typeof obj); // "object" alert(typeof fn); // "function" alert(typeof a); // "object"
عملگر instanceof
عملگر typeof بهترین روش جهت تشخیص نوع دادهای متغیرهایی است که دارای نوع دادهای پایه یا Primitive Type هستند. اما جهت تشخیص نوع دادهای اشیاء و به صورت کلی انواع ارجاعی، این عملگر فقط مقدار "object" را برمیگرداند و اشارهای به ماهیت واقعی آن Object ندارد. برای این منظور میتوانیم از عملگر instanceof استفاده نماییم تا بررسی کنیم یک نوع ارجاعی از جنس چه نوع Object ی میباشد. شکل کلی استفاده از این عملگر به صورت زیر است:
result = variable instanceof constructor
اگر variable ، از جنس نوع ارجاعی تعیین شده در بخش سازنده یا constructor باشد، عملگر instanceof مقدار true را بر میگرداند. به مثال زیر توجه کنید:
var a = new Array(); alert(a instanceof Array); // true alert(a instanceof Object); // true alert(a instanceof Date); // false
عملگر in
همانطور که قبلا اشاره شد، جهت دسترسی به اعضای یک شیء، میتوان با آن شیء همانند یک آرایه رفتار نمود. به عبارتی دیگر میتوان نام یک ویژگی یا تابع را در [] قرار داد تا به مقدار آن دسترسی داشت. بنابراین میتوان همانند یک آرایه و با استفاده از یک حلقهی for-in تمامی اعضای یک شیء را پیمایش نمود. در واقع عملگر in در این حلقه بررسی میکند چه ویژگیها و توابعی در یک شیء وجود دارند و تمامی آنها را بر میگرداند. به مثال زیر توجه کنید:
var person = { name: "Meysam", age: 33, sayInfo: function () { alert(name + ":" + age); } }; for (var i in person) alert(i + " => " + person[i]);
خروجی :
name => Meysam age => 33 sayInfo => function() { alert(name + ":" + age); }
کاربرد دیگر عملگر in بررسی وجود یک ویژگی یا تابع در یک شیء میباشد. اگر ویژگی یا تابع مورد نظر در شیء وجود داشته باشد، مقدار true را بر میگرداند. به مثال زیر توجه کنید:
alert("name" in person); // true alert("sayInfo" in person); // true alert("birth" in person); // false
عملگر delete
از عملگر delete جهت حذف یک ویژگی و یا یک تابع از یک شیء استفاده میشود. به مثال زیر توجه کنید:
var person = { name: "Meysam", age: 33, sayInfo: function () { alert(name + ":" + age); } }; alert("sayInfo" in person); // true delete person.sayInfo; alert("sayInfo" in person); // false
ویژگی constructor
پس از عملگرهای فوق، یکی از پرکاربردترین ویژگیهایی که برای اشیاء وجود دارد، ویژگی constructor میباشد. در واقع این ویژگی نیز یکی از راهکارهای بررسی صحت و اعتبار متغیرها، آرگومانها و اشیا میباشد. ویژگی constructor ، به تابع سازندهی یک شیء اشاره میکند و آن سازنده را به عنوان خروجی بر میگرداند. دقت داشته باشید که خروجی این ویژگی، خود تابع سازنده میباشد و یک مقدار رشتهای نیست. به مثال زیر توجه کنید:
var obj = {}; var a = new Array(); var x = 10; alert(obj.constructor); alert(obj.constructor === Object); alert(typeof obj.constructor); alert(a.constructor); alert(x.constructor);
خروجی :
function Object() { [native code] } true function function Array() { [native code] } function Number() { [native code] }
در اینجا دیگر آمادهی ورود به برنامه نویسی شیء گرا در جاوا اسکریپت میباشیم که در مقالات بعدی به آن خواهیم پرداخت و همچنین با جزئیات بیشتری اشیاء را تشریح مینماییم.
1- تعریف کلاس به صورت زیر
public class ImageSize { public int Height { get; set; } public int Width { get; set; } }
public class ImageResizer { public ImageSize Resize(ImageSize originalSize, ImageSize targetSize) { var aspectRatio = (float)originalSize.Width / (float)originalSize.Height; var width = targetSize.Width; var height = targetSize.Height; if (originalSize.Width > targetSize.Width || originalSize.Height > targetSize.Height) { if (aspectRatio > 1) { height = (int)(targetSize.Height / aspectRatio); } else { width = (int)(targetSize.Width * aspectRatio); } } else { width = originalSize.Width; height = originalSize.Height; } return new ImageSize { Width = Math.Max(width, 1), Height = Math.Max(height, 1) }; } }
3- تعریف کلاس ThumbnailCreator همانند نمونه زیر :
public class ThumbnailCreator { private static readonly IDictionary<string, ImageFormat> ImageFormats = new Dictionary<string, ImageFormat>{ {"image/png", ImageFormat.Png}, {"image/gif", ImageFormat.Gif}, {"image/jpeg", ImageFormat.Jpeg} }; private readonly ImageResizer resizer; public ThumbnailCreator() { this.resizer = new ImageResizer(); } public byte[] Create(Stream source, ImageSize desiredSize, string contentType) { using (var image = Image.FromStream(source)) { var originalSize = new ImageSize { Height = image.Height, Width = image.Width }; var size = resizer.Resize(originalSize, desiredSize); using (var thumbnail = new Bitmap(size.Width, size.Height)) { ScaleImage(image, thumbnail); using (var memoryStream = new MemoryStream()) { thumbnail.Save(memoryStream, ImageFormats[contentType]); return memoryStream.ToArray(); } } } } private void ScaleImage(Image source, Image destination) { using (var graphics = Graphics.FromImage(destination)) { graphics.CompositingMode = CompositingMode.SourceCopy; graphics.CompositingQuality = CompositingQuality.HighQuality; graphics.SmoothingMode = SmoothingMode.AntiAlias; graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; graphics.DrawImage(source, 0, 0, destination.Width, destination.Height); } } }
4- تعریف اکشن Thumbnail همانند زیر :
private FileContentResult CreateThumbnail(string physicalPath) { using (var fileStream = System.IO.File.OpenRead(physicalPath)) { var desiredSize = new ImageSize { Width = ThumbnailWidth, Height = ThumbnailHeight }; string contentType = MimeMapping.GetMimeMapping(physicalPath); return File(thumbnailCreator.Create(fileStream, desiredSize, contentType), contentType); } }
و در پایان اکشن GetThumbnail را همانند زیر تغییر خواهیم داد :
public virtual ActionResult GetThumbnail(string path) { path = GetSafeFileAndDirPath(path); // return File(path, contentType); return CreateThumbnail(path); }
در این قسمت سعی خواهیم کرد تا منبع داده جدول را یک آرایه جاوا اسکریپتی و سپس کالکشنی از آبجکتهای جاوا اسکریپتی (json) در نظر بگیریم و نیز برخی ویژگیهای پیش فرض پلاگین را غیر فعال نمائیم.
فرض کنید میخواهید لیستی از اطلاعات دانشجویان شامل نام (FirstName)، نام خانوادگی (LastName)، و سن (Age) را نمایش دهید. اطلاعات قرار است در جدول زیر قرار بگیرند:
<table id="std-grid"> <thead> <th>نام</th> <th>نام خانوادگی</th> <th>سن</th> </thead> <tbody> </tbody> </table>
مشاهده میکنید که این جدول فقط شامل قسمت header است و در بدنه آن هیچ سطری قرار نگرفته است. در این مثال اطلاعات از یک آرایه جاوا اسکریپتی باید خوانده شوند و تبدیل به html شده و در نهایت درون قسمت <tbody></tbody> آن تزریق شوند. خوشبختانه DataTables برای این کار امکانات آماده ای را در اختیار قرار میدهد. این کار بدین صورت قابل انجام است:
<script> $(document).ready(function() { $('#std-grid').dataTable({ "aaData": [ ["پژمان", "پارسائی", "24"], ["سعید", "الیاسی", "25"], ["محمد رضا", "گلزار", "20"], ["آرش", "ایرانی", "19"], ["مرتضی", "فرمانی", "22"], ["سعید", "حمیدیان", "23"], ["امین", "پارسانیا", "23"], ["محمد امین", "فقیهی", "24"], ["محمد", "خرمی", "25"], ["سینا", "امیریان", "20"], ["آرش", "ایرانی", "19"], ["وحید", "فرزانه", "22"], ["امیر علی", "فرمانی", "23"], ["امین", "حسینی", "23"], }); }); </script>
aaData : یک آرایه دو بعدی (که به آن ماتریس یا آرایه ای از آرایهها هم گفته میشود) است که مقادیر سلول هایی را نشان میدهد که در جدول قرار خواهند گرفت. تعداد ستونها در این آرایه دو بعدی باید با تعداد ستونهای جدول html متناظر یکسان باشند.
در مثال بالا از یک ماتریس به عنوان منبع داده استفاده شد. منبع داده میتواند به فرمت json نیز باشد. البته در این صورت باید ستونهای جدول html را هم به پلاگین معرفی کنید، بدین صورت:
$(document).ready(function() { $('#std-grid').dataTable({ "aaData": [ {"FirstName" : "پژمان", "LastName" : "پارسائی", "Age" : "24"}, { "FirstName": "سعید", "LastName": "الیاسی", "Age": "25" }, { "FirstName": "محمد رضا", "LastName": "گلزار", "Age": "24" }, { "FirstName": "آرش", "LastName": "ایرانی", "Age": "24" }, { "FirstName": "مرتضی", "LastName": "فرمانی", "Age": "24" }, { "FirstName": "سعید", "LastName": "حمیدیان", "Age": "24" }, { "FirstName": "امین", "LastName": "پارسانیا", "Age": "24" }, { "FirstName": "محمد امین", "LastName": "فقیهی", "Age": "24" }, { "FirstName": "محمد", "LastName": "خرمی", "Age": "24" }, { "FirstName": "سینا", "LastName": "امیریان", "Age": "24" }, { "FirstName": "آرش", "LastName": "ایرانی", "Age": "24" }, { "FirstName": "وحید", "LastName": "فرزانه", "Age": "24" }, { "FirstName": "امیر علی", "LastName": "فرمانی", "Age": "24" }, { "FirstName": "امین", "LastName": "حسینی", "Age": "24" }, ], "aoColumns": [ { "mDataProp": "FirstName" }, { "mDataProp": "LastName" }, { "mDataProp": "Age" } ] }); });
aoColumns : در این قسمت باید اسم ستونهای جدول ذکر شوند.
غیرفعال کردن بعضی از ویژگیهای پیش فرض DataTables
همان طور که گفته شد پلاگین DataTables به صورت پیش فرض ویژگیهای مرتب سازی (sorting)، صفحه بندی (paging)، فیلتر کردن دادهها (filtering)، و غیره را به جدول مورد نظرش اعمال میکند. و بدین صورت قابل تغییر است:
$('#std-grid').dataTable({ "bPaginate": false, "bLengthChange": false, "bFilter": false, "bSort": false, "bInfo": true, "bAutoWidth": false });
bLengthChange : در صورتی که قابلیت صفحه بندی فعال باشد ، بیان میکند که کاربر بتواند اندازه صفحه را تغییر دهد یا نه.
bFilter : بیان میکند آیا قابلیت فیلتر کردن دادهها فعال باشد یا نه.
bSort : بیان میکند قابلیت مرتب سازی دادههای جدول فعال باشد یا نه.
bInfo : بیان میکند که قسمت info زیر گرید نشان داده شود یا نه (در این قسمت اطلاعاتی راجع به تعداد کل رکوردهای بایند شده به جدول و نیز رکوردهای درون صفحه جاری نشان داده میشود)
bAutoWidth : در صورتی که این گزینه فعال باشد اندازه عرض هر ستون به صوتر خودکار توسط DataTables مقدار دهی خواهد شد.
مقدارهای قابل قبول برای هر کدام از این خصوصیات : true یا false
کدهای مربوط به این مثال را میتوانید از لینک زیر دریافت کنید:
DataTables-DoteNetTips-Tutorial-02.zip
در فریمورک NET. ابزارهای مختلفی برای کار با دادههای XML در نظر گرفته شدهاست که بعد از نسخه 3.5 آن، انتخاب اول LINQ to XML می باشد. در این مطلب قصد داریم API ای را برای خواندن اطلاعات فایلهای XML با استفاده از LINQ to XML و انقیاد پویا در سیشارپ (Dynamic Binding) تهیه کنیم.
راه حل اول: استفاده از ExpandoObject
public static class ExpandoXml { public static dynamic AsExpando(this XDocument document) { return CreateExpando(document.Root); } private static dynamic CreateExpando(XElement element) { var result = new ExpandoObject() as IDictionary<string, object>; if (element.Elements().Any(e => e.HasElements)) { var list = new List<ExpandoObject>(); result.Add(element.Name.ToString(), list); foreach (var childElement in element.Elements()) { list.Add(CreateExpando(childElement)); } } else { foreach (var leafElement in element.Elements()) { result.Add(leafElement.Name.ToString(), leafElement.Value); } } return result; } }
در تکه کد بالا از طریق متد CreateExpando به صورت بازگشتی ابتدا بررسی میشود که آیا عنصر جاری دارای عناصری میباشد و همچنین آیا آنها دارای فرزند میباشند یا خیر؛ در صورت برقراری شرط، نتیجهی اجرای متد CreateExpando بر روی تک تک عناصر فرزند را درون لیستی از ExpandoObject قرار داده و سپس آن لیست نیز به عنوان Value عنصر جاری در نظر گرفته میشود. در صورت عدم برقراری شرط مذکور، مقادیر مربوط به عناصر فرزند را در قالب یک ExpandoObject به عنوان خروجی بازگشت خواهد داد.
راه حل دوم: استفاده از DynamicObject
public class DynamicXml : DynamicObject, IEnumerable { private readonly dynamic _xml; public DynamicXml(string fileName) { _xml = XDocument.Load(fileName); } public DynamicXml(dynamic xml) { _xml = xml; } public IEnumerator GetEnumerator() { foreach (var item in _xml.Elements()) { yield return new DynamicXml(item); } } public override bool TryGetMember(GetMemberBinder binder, out object result) { var xml = _xml.Element(binder.Name); if (xml != null) { result = new DynamicXml(xml); return true; } var attribute = _xml.Attribute(binder.Name); if (attribute != null) { result = new DynamicXml(attribute); return true; } result = null; return false; } public static implicit operator string(DynamicXml xml) { return xml._xml.Value; } }
کلاس DynamicXml از طریق سازنده اول، نام فایل را دریافت کرده و از طریق LINQ to XML با استفاده از متد Load کلاس XDocument، فایل مورد نظر بارگذاری شده و درون فیلدی به نام xml_ از نوع dynamic نگه داشته میشود. کار بعدی، بازنویسی متد TryGetMember میباشد. در بدنه بازنویسی شده این متد ابتدا بررسی میشود که آیا با نام خصوصت درخواست شده عنصری در داده XML وجود دارد یا خیر؛ در صورت موجود بودن، پارامتر result با یک وهله جدید از DynamicXml مقدار دهی میشود که عنصر یافت شده از طریق سازنده دوم، به عنوان داده xml برای مقدار دهی فیلد xml_ به عنوان آرگومان ارسال میشود. در صورت عدم وجود عنصر مذکور، بدنبال خصوصیتی با آن نام بوده و در صورت یافت شدن، باز به عنوان یک وهله DynamicXml برای مقدار دهی result استفاده میشود.
در ادامه برای نسبت دادن یک وهله از DynamicXml به یک متغیر string و دستیابی به مقدار یک عنصر که از طریق خصوصیت، درخواست میشود نیاز است تا اپراتور ضمنی string را نیز برای کلاس بالا نظر بگیریم. همچنین برای ایجاد امکان پیمایش برروی عناصر فرزند از طریق foreach، لازم است واسط IEnumerable را نیز پیاده سازی کرده باشیم.
طریقه استفاده
class Program { static void Main(string[] args) { var doc1 = XDocument.Load("Employees.xml"); foreach (var element in doc1.Element("Employees").Elements("Employee")) { Console.WriteLine(element.Element("FirstName").Value); } dynamic doc2 = XDocument.Load("Employees.xml").AsExpando(); foreach (var employee in doc2.Employees) { Console.WriteLine(employee.FirstName); } dynamic doc3 = new DynamicXml("Employees.xml"); foreach (var employee in doc3.Employees) { Console.WriteLine(employee.FirstName); Console.WriteLine(employee.Id); } } }
<?xml version="1.0" encoding="utf-8" ?> <Employees> <Employee Id="1"> <FirstName> Employee1 </FirstName> </Employee> <Employee Id="2"> <FirstName> Employee2 </FirstName> </Employee> <Employee Id="3"> <FirstName> Employee3 </FirstName> </Employee> <Employee Id="4"> <FirstName> Employee4 </FirstName> </Employee> </Employees>
Blazor 5x - قسمت 31 - احراز هویت و اعتبارسنجی کاربران Blazor WASM - بخش 1 - انجام تنظیمات اولیه
using System; using System.Collections.Generic; using System.Linq; using System.Security.Claims; using System.Text.Json; namespace BlazorWasm.Client.Utils { public class JwtInfo { public IEnumerable<Claim> Claims { set; get; } public DateTime? ExpirationDateUtc { set; get; } public bool IsExpired { set; get; } public IEnumerable<string> Roles { set; get; } } /// <summary> /// From the Steve Sanderson’s Mission Control project: /// https://github.com/SteveSandersonMS/presentation-2019-06-NDCOslo/blob/master/demos/MissionControl/MissionControl.Client/Util/ServiceExtensions.cs /// </summary> public static class JwtParser { public static JwtInfo ParseClaimsFromJwt(string jwt) { var claims = new List<Claim>(); var payload = jwt.Split('.')[1]; var jsonBytes = getBase64WithoutPadding(payload); foreach (var keyValue in JsonSerializer.Deserialize<Dictionary<string, object>>(jsonBytes)) { if (keyValue.Value is JsonElement element && element.ValueKind == JsonValueKind.Array) { foreach (var itemValue in element.EnumerateArray()) { claims.Add(new Claim(keyValue.Key, itemValue.ToString())); } } else { claims.Add(new Claim(keyValue.Key, keyValue.Value.ToString())); } } var roles = getRoles(claims); var expirationDateUtc = getDateUtc(claims, "exp"); var isExpired = getIsExpired(expirationDateUtc); return new JwtInfo { Claims = claims, Roles = roles, ExpirationDateUtc = expirationDateUtc, IsExpired = isExpired }; } private static IList<string> getRoles(IList<Claim> claims) => claims.Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value).ToList(); private static byte[] getBase64WithoutPadding(string base64) { switch (base64.Length % 4) { case 2: base64 += "=="; break; case 3: base64 += "="; break; } return Convert.FromBase64String(base64); } private static bool getIsExpired(DateTime? expirationDateUtc) => !expirationDateUtc.HasValue || !(expirationDateUtc.Value > DateTime.UtcNow); private static DateTime? getDateUtc(IList<Claim> claims, string type) { var exp = claims.SingleOrDefault(claim => claim.Type == type); if (exp == null) { return null; } var expValue = getTimeValue(exp.Value); if (expValue == null) { return null; } var dateTimeEpoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc); return dateTimeEpoch.AddSeconds(expValue.Value); } private static long? getTimeValue(string claimValue) { if (long.TryParse(claimValue, out long resultLong)) return resultLong; if (float.TryParse(claimValue, out float resultFloat)) return (long)resultFloat; if (double.TryParse(claimValue, out double resultDouble)) return (long)resultDouble; return null; } } }