The Trusted Platform Module (TPM) is a chip that is either integrated into your PC’s motherboard or added separately into the CPU. Its purpose is to help protect encryption keys, user credentials, and other sensitive data behind a hardware barrier so that malware and attackers can’t access or tamper with that data.
اعتبارسنجی JSON با JSON-Schema
When you’re dealing with complex and structured data, you need to determine whether the data is valid or not. JSON-Schema is the standard of JSON documents that describes the structure and the requirements of your JSON data. In this two-part series, you’ll learn how to use JSON-Schema to validate data.
PdfRpt-2.0.zip
- Fixed conflicts of default footer's font and default document's font. - Added an optional parameter to DocumentPreferences.BackgroundImage method to specify the absolute position of the background's image. - Enabled running in medium trust environment. - Added PageTableAdded event. PageTableAdded Fires after each part of the MainTable has been added to the current page. - Added CustomSummaryPerPagePdfReport sample to show how to use PageTableAdded event.
Any experienced .NET developer knows that even though .NET applications have a garbage collector, memory leaks occur all the time. It’s not that the garbage collector has bugs, it’s just that there are ways we can (easily) cause memory leaks in a managed language.
Memory leaks are sneakily bad creatures. It’s easy to ignore them for a very long time, while they slowly destroy the application. With memory leaks, your memory consumption grows, creating GC pressure and performance problems. Finally, the program will just crash on an out-of-memory exception.
In this article, we will go over the most common reasons for memory leaks in .NET programs. All examples are in C#, but they are relevant to other languages.
زمانی که سیستم عامل های GUI مثل ویندوز به بازار آمدند، یکی از قسمتهای گرافیکی آنها AddressBar نام داشت که مسیر حرکت آنها را در فایل سیستم نشان میداد و در سیستم عاملهای متنی CLI با دستور cd یا pwd انجام میشد. بعدها در وب هم همین حرکت با نام BreadCrumb صورت گرفت که به عنوان مثال مسیر رسیدن به صفحهی یک محصول یا یک مقاله را نشان میداد. در یک پروژهی اندرویدی نیاز بود تا یک ساختار درختی را پیاده سازی کنم، ولی در برنامههای اندروید ایجاد یک درخت، کار هوشمندانه و مطلوبی نیست و روش کار به این صورت است که یک لیست از گروههای والد را نمایش داده و با انتخاب هر آیتم لیست به آیتمهای فرزند تغییر میکند. حالا مسئله این بود که کاربر باید مسیر حرکت خودش را بشناسد. به همین علت مجبور شدم یک BreadCrumb را برای آن طراحی کنم که در زیر تصویر آن را مشاهده میکنید.
از نکات جالب توجه در مورد این ماژول میتوان گفت که قابلیت این را دارد تا تصمیمات خود را بر اساس اندازههای مختلف صفحه نمایش بگیرد. به عنوان مثال اگر آیتمهای بالا بیشتر از سه عدد باشد و در صفحه جا نشود از یک مسیر جعلی استفاده میکند و همهی آیتمها با اندیس شماره 1 تا index-3 را درون یک آیتم با عنوان (...) قرار میدهد که من به آن میگویم مسیر جعلی. به عنوان نمونه مسیر تصویر بالا در صفحه جا شده است و نیازی به این کار دیده نشده است. ولی تصویر زیر از آن جا که مسیر، طول width صفحه نمایش رد کرده است، نیاز است تا چنین کاری انجام شود. موقعیکه کاربر آیتم ... را کلیک کند، مسیر باز شده و به محل index-3 حرکت میکند. یعنی دو مرحله به عقب باز میگردد.
نگاهی به کارکرد ماژول
قبل از توضیح در مورد سورس، اجازه دهید نحوهی استفاده از آن را ببینیم.
این سورس شامل دو کلاس است که سادهترین کلاس آن AndBreadCrumbItem میباشد که مشابه کلاس ListItem در بخش وب دات نت است و دو مقدار، یکی متن و دیگری Id را میگیرد:
سورس:
public class AndBreadCrumbItem { private int Id; private String diplayText; public AndBreadCrumbItem(int Id, String displayText) { this.Id=Id; this.diplayText=displayText; } public String getDiplayText() { return diplayText; } public void setDiplayText(String diplayText) { this.diplayText = diplayText; } public int getId() { return Id; } public void setId(int id) { Id = id; } }
به عنوان مثال میخواهیم یک breadcrumb را با مشخصات زیر بسازیم:
AndBreadCrumbItem itemhome=new AndBreadCrumbItem(0,"Home"); AndBreadCrumbItem itemproducts=new AndBreadCrumbItem(12,"Products"); AndBreadCrumbItem itemdigital=new AndBreadCrumbItem(15,"Digital"); AndBreadCrumbItem itemhdd=new AndBreadCrumbItem(56,"Hard Disk Drive");
AndBreadCrumb breadCrumb=new AndBreadCrumb(this); breadCrumb.AddNewItem(itemhome); breadCrumb.AddNewItem(itemproducts); breadCrumb.AddNewItem(itemdigital); breadCrumb.AddNewItem(itemhdd);
breadCumb.setContext(this);
پس از افزودن آیتم ها، تنظیمات زیر را اعمال نمایید:
LinearLayout layout=(LinearLayout)getActivity().findViewById(R.id.breadcumblayout); layout.setPadding(8, 8, 8, 8); breadCrumb.setLayout(layout); breadCrumb.SetTinyNextNodeImage(R.drawable.arrow); breadCrumb.setTextSize(25); breadCrumb.SetViewStyleId(R.drawable.list_item_style);
حال برای رسم آن متد UpdatePath را صدا میزنیم:
breadCrumb.UpdatePath();
الان اگر برنامه اجرا شود باید breadcrumb از چپ به راست رسم گردد. برای استفادههای فارسی، راست به چپ میتوانید از متد زیر استفاده کنید:
breadCrumb.setRTL(true);
در صورتیکه قصد دارید تنظیمات بیشتری چون رنگ متن، فونت متن و ... را روی هر المان اعمال کنید، از رویداد زیر استفاده کنید:
breadCrumb.setOnTextViewUpdate(new ITextViewUpdate() { @Override public TextView UpdateTextView(Context context, TextView tv) { tv.setTextColor(...); tv.setTypeface(...); return tv; } });
همچنین در صورتیکه میخواهید بدانید کاربر بر روی چه عنصری کلیک کرده است، از رویداد زیر استفاده کنید:
breadCumb.setOnClickListener(new IClickListener() { @Override public void onClick(int position, int Id) { //... } });
آخرین متد موجود که کمترین استفاده را دارد، متد SetNoResize است. در صورتیکه این متد با True مقداردهی گردد، عملیات تنظیم بر اساس صفحهی نمایش لغو میشود. این متد برای زمانی مناسب است که به عنوان مثال شما از یک HorozinalScrollView استفاده کرده باشید. در این حالت layout شما هیچ گاه به پایان نمیرسد و بهتر هست عملیات اضافه را لغو کنید.
نگاهی به سورس
کلاس زیر شامل بخشهای زیر است:
فیلدهای خصوصی
//=-=--=-=-=-=-=-=-=-=-=-=-=- Private Properties -=-=-=-=-=-=-=--=-=-= private List<AndBreadCrumbItem> items=null; private List<TextView> textViews; private int tinyNextNodeImage; private int viewStyleId; private Context context; private boolean RTL; private float textSize=20; private boolean noResize=false; LinearLayout layout; IClickListener clickListener; ITextViewUpdate textViewUpdate; LinearLayout.LayoutParams params ;
اینترفیسها هم با حرف I شروع و برای تعریف رویدادها ایجاد شدهاند. در ادامه از تعدادی متد get و Set برای مقدار دهی بعضی از فیلدهای خصوصی بالا استفاده شده است:
//=-=---=-=-=-=-- Constructor =--=-=-=-=-=--=-=- public AndBreadCrumb(Context context) { this.context=context; params = new LinearLayout.LayoutParams (LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT); } //=-=-=--=--=-=-=-=-=-=-=-=- Public Properties --=-=-=-=-=-=--=-=-=-=-=-=- //each category would be added to create path public void AddNewItem(AndBreadCrumbItem item) { if(items==null) items=new ArrayList<>(); items.add(item); } // if you want a pointer or next node between categories or textviews public void SetTinyNextNodeImage(int resId) {this.tinyNextNodeImage=resId;} public void SetViewStyleId(int resId) {this.viewStyleId=resId;} public void setTextSize(float textSize) {this.textSize = textSize;} public boolean isRTL() { return RTL; } public void setRTL(boolean RTL) { this.RTL = RTL; } public void setLayout(LinearLayout layout) { this.layout = layout; } public void setContext(Context context) { this.context = context; } public boolean isNoResize() { return noResize; } public void setNoResize(boolean noResize) { this.noResize = noResize; }
بعد از آن به متدهای خصوصی میرسیم که متد زیر، متد اصلی ما برای ساخت breadcrumb است:
//primary method for render objects on layout private void DrawPath() { //stop here if essentail elements aren't present if (items == null) return ; if (layout == null) return; if (items.size() == 0) return; //we need to get size of layout,so we use the post method to run this thread when ui is ready layout.post(new Runnable() { @Override public void run() { //textviews created here one by one int position = 0; textViews = new ArrayList<>(); for (AndBreadCrumbItem item : items) { TextView tv = MakeTextView(position, item.getId()); tv.setText(item.getDiplayText()); textViews.add(tv); position++; } //add textviews on layout AddTextViewsOnLayout(); //we dont manage resizing anymore if(isNoResize()) return; //run this code after textviews Added to get widths of them TextView last_tv=textViews.get(textViews.size()-1); last_tv.post(new Runnable() { @Override public void run() { //define width of each textview depend on screen width BatchSizeOperation(); } }); } }); }
TextView tv=new TextView(this); tv.getWidth(); //return 0 layout.add(tv); tv.getWidth(); //return 0
TextView tv=new TextView(this); tv.post(new Runnable() { @Override public void run() { tv.getWidth(); //return x } });
باز میگردیم به متد DrawPath و داخل متد post
در اولین خط این پروسه به ازای هر آیتم، یک TextView توسط متد MakeTextView ساخته میشود که شامل کد زیر است:
private TextView MakeTextView(final int position, final int Id) { //settings for cumbs TextView tv=new TextView(this.context); tv.setEllipsize(TextUtils.TruncateAt.END); tv.setSingleLine(true); tv.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize); tv.setBackgroundResource(viewStyleId); /*call custom event - this event will be fired when user click on one of textviews and returns position of textview and value that user sat as id */ tv.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SetPosition(position); clickListener.onClick(position, Id); } }); //if user wants to update each textviews if(textViewUpdate!=null) tv=textViewUpdate.UpdateTextView(context,tv); if(isRTL()) tv.setRotationY(180); return tv; }
در خطوط اولیه، یک Textview ساخته و متد Ellipsize را با Truncate.END مقداردهی مینماید. این مقدار دهی باعث میشود اگر متن، در Textview جا نشد، ادامهی آن با ... مشخص شود. در خط بعدی Textview را تک خطه معرفی میکنیم. در خط بعدی اندازهی قلم را بر اساس آنچه کاربر مشخص کرده است، تغییر میدهیم و بعد هم استایل را برای آن مقداردهی میکنیم. بعد از آن رویداد کلیک را برای آن مشخص میکنیم تا اگر کاربر بر روی آن کلیک کرد، رویداد اختصاصی خودمان را فراخوانی کنیم.
در خط بعدی اگر rtl با true مقدار دهی شده باشد، textview را حول محور Y چرخش میدهد تا برای زبانهای راست به چپ چون فارسی آماده گردد و در نهایت Textview ساخته شده و به سمت متد DrawPath باز میگرداند.
بعد از ساخته شدن TextViewها، وقت آن است که به Layout اضافه شوند که وظیفهی اینکار بر عهدهی متد AddTextViewOnLayout است:
//this method calling by everywhere to needs add textviews on the layout like master method :drawpath private void AddTextViewsOnLayout() { //prepare layout //remove everything on layout for recreate it layout.removeAllViews(); layout.setOrientation(LinearLayout.HORIZONTAL); layout.setVerticalGravity(Gravity.CENTER_VERTICAL); if(isRTL()) layout.setRotationY(180); //add textviews one by one int position=0; for (TextView tv:textViews) { layout.addView(tv,params); //add next node image between textviews if user defined a next node image if(tinyNextNodeImage>0) if(position<(textViews.size()-1)) { layout.addView(GetNodeImage(), params); position++; } } }
تا به اینجا کار چیدمان به ترتیب انجام شده است ولی از آنجا که اندازهی Layout در هر گوشی و در دو حالت حالت افقی یا عمودی نگه داشتن گوشی متفاوت است، نمیتوان به این چینش اعتماد کرد که به چه نحوی عناصر نمایش داده خواهند شد و این مشکل توسط متد BatchSizeOperation (تغییر اندازه دسته جمعی) حل میگردد. در اینجا هم باز متد post به آخرین textview اضافه شده است. به این علت که موقعیکه همهی textviewها در ui جا خوش کردند، بتوانیم به خاصیتهای ui آنها دستیابی داشته باشیم. حالا بعد از ترسیم باید اندازه آنها را اصلاح کنیم. قدم به قدم متد BatchSizeOperation را بررسی میکنیم:
//set textview width depend on screen width private void BatchSizeOperation() { //get width of next node between cumbs Bitmap tinyBmap = BitmapFactory.decodeResource(context.getResources(), tinyNextNodeImage); int tinysize=tinyBmap.getWidth(); //get sum of nodes tinysize*=(textViews.size()-1); ... }
//get width size of screen(layout is screen here) int screenWidth=GetLayoutWidthSize(); //get sum of arrows and cumbs width int sumtvs=tinysize; for (TextView tv : textViews) { int width=tv.getWidth(); sumtvs += width; }
private int GetLayoutWidthSize() { int width=layout.getWidth(); int padding=layout.getPaddingLeft()+layout.getPaddingRight(); width-=padding; return width; }
private void BatchSizeOperation() { .... //if sum of cumbs is less than screen size the state is good so return same old textviews if(sumtvs<screenWidth) return ; if(textViews.size()>3) { //make fake path MakeFakePath(); //clear layout and add textviews again AddTextViewsOnLayout(); } //get free space without next nodes -> and spilt rest of space to textviews count to get space for each textview int freespace =screenWidth-tinysize; int each_width=freespace/textViews.size(); //some elements have less than each_width,so we should leave size them and calculate more space again int view_count=0; for (TextView tv:textViews) { if (tv.getWidth()<=each_width) freespace=freespace-tv.getWidth(); else view_count++; } if (view_count==0) return; each_width=freespace/view_count; for (TextView tv:textViews) { if (tv.getWidth()>each_width) tv.setWidth(each_width); } }
اگر آیتمها بیشتر از سه عدد باشند، میتوانیم از حالت مسیر جعلی استفاده کنیم که توسط متد MakeFakePath انجام میشود. البته بعد از آن هم باید دوباره viewها را چینش کنیم تا مسیر جدید ترسیم گردد، چون ممکن است بعد از آن باز هم جا نباشد یا آیتمها بیشتر از سه عدد نیستند. در این حالت، حداقل کاری که میتوانیم انجام دهیم این است که فضای موجود را بین آنها تقسیم کنیم تا همهی کاسه، کوزهها سر آیتم آخر نشکند و متنش به ... تغییر یابد و حداقل از هر آیتم، مقداری از متن اصلی نمایش داده شود. پس میانگین فضای موجود را گرفته و بر تعداد المانها تقسیم میکنیم. البته این را هم باید در نظر گرفت که در تقسیم بندی، بعضی آیتمها آن مقدار پهنا را نیاز ندارند و با پهنای کمتر هم میشود کل متنشان را نشان داد. پس یک کار اضافهتر این است که مقدار پهنای اضافی آنها را هم حساب کنیم و فقط آیتمهایی را پهنا دهیم که به مقدار بیشتری از این میانگین احتیاج دارند. در اینجا کار به پایان میرسد و مسیر نمایش داده میشود.
نحوهی کارکرد متد MakeFakePath بدین صورت است که 4 عدد TextView را ایجاد کرده که المانهای با اندیس 0 و 2 و 3 به صورت نرمال و عادی ایجاد شده و همان کارکرد سابق را دارند. ولی المان شماره دو با اندیس 1 با متن ... نمایندهی آیتمهای میانی است و رویدادکلیک آن به شکل زیر تحریف یافته است:
//if elements are so much(mor than 3),we make a fake path to decrease elements private void MakeFakePath() { //we make 4 new elements that index 1 is fake element and has a rest of real path in its heart //when user click on it,path would be opened textViews=new ArrayList<>(4); TextView[] tvs=new TextView[4]; int[] positions= {0,items.size()-3,items.size()-2,items.size()-1}; for (int i=0;i<4;i++) { //request for new textviews tvs[i]=MakeTextView(positions[i],items.get(positions[i]).getId()); if(i!=1) tvs[i].setText(items.get(positions[i]).getDiplayText()); else { tvs[i].setText("..."); //override click event and change it to part of code to open real path by call setposition method and redraw path tvs[i].setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int pos = items.size() - 3; int id = items.get(pos).getId(); SetPosition(items.size() - 3); clickListener.onClick(pos, id); } }); } textViews.add(tvs[i]); } }
کدهای کامل این مثال را در ذیل ملاحظه میکنید:
using System; using System.Data.Entity; using System.Data.Entity.Migrations; using System.Diagnostics; using System.Linq; namespace EFGeneral { public class User { public int Id { get; set; } public string Name { get; set; } } public class MyContext : DbContext { public DbSet<User> Users { get; set; } } public class Configuration : DbMigrationsConfiguration<MyContext> { public Configuration() { AutomaticMigrationsEnabled = true; AutomaticMigrationDataLossAllowed = true; } protected override void Seed(MyContext context) { for (int i = 0; i < 21000; i++) { context.Users.Add(new User { Name = "name " + i }); if (i % 1000 == 0) context.SaveChanges(); } base.Seed(context); } } public class PerformanceHelper { public static string RunActionMeasurePerformance(Action action) { GC.Collect(); long initMemUsage = Process.GetCurrentProcess().WorkingSet64; var stopwatch = new Stopwatch(); stopwatch.Start(); action(); stopwatch.Stop(); var currentMemUsage = Process.GetCurrentProcess().WorkingSet64; var memUsage = currentMemUsage - initMemUsage; if (memUsage < 0) memUsage = 0; return string.Format("Elapsed time: {0}, Memory Usage: {1:N2} KB", stopwatch.Elapsed, memUsage / 1024); } } public static class Test { public static void RunTests() { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyContext, Configuration>()); StartDb(); for (int i = 0; i < 3; i++) { Console.WriteLine("\nRun {0}", i + 1); var memUsage = PerformanceHelper.RunActionMeasurePerformance(() => LoadWithTracking()); Console.WriteLine("LoadWithTracking:\n{0}", memUsage); memUsage = PerformanceHelper.RunActionMeasurePerformance(() => LoadWithoutTracking()); Console.WriteLine("LoadWithoutTracking:\n{0}", memUsage); } } private static void StartDb() { using (var ctx = new MyContext()) { var user = ctx.Users.Find(1); if (user != null) { // keep the object in memory } } } private static void LoadWithTracking() { using (var ctx = new MyContext()) { var list = ctx.Users.ToList(); if (list.Any()) { // keep the list in memory } } } private static void LoadWithoutTracking() { using (var ctx = new MyContext()) { var list = ctx.Users.AsNoTracking().ToList(); if (list.Any()) { // keep the list in memory } } } } }
توضیحات:
مدل برنامه یک کلاس ساده کاربر است به همراه id و نام او.
سپس این کلاس توسط Context برنامه در معرض دید EF Code first قرار میگیرد.
در کلاس Configuration تعدادی رکورد را در ابتدای کار برنامه در بانک اطلاعاتی ثبت خواهیم کرد. قصد داریم میزان مصرف حافظه بارگذاری این اطلاعات را بررسی کنیم.
کلاس PerformanceHelper معرفی شده، دو کار اندازه گیری میزان مصرف حافظه برنامه در طی اجرای یک فرمان خاص و همچنین مدت زمان سپری شدن آنرا اندازهگیری میکند.
در کلاس Test فوق چندین متد به شرح زیر وجود دارند:
متد StartDb سبب میشود تا تنظیمات ابتدایی برنامه به بانک اطلاعاتی اعمال شوند. تا زمانیکه کوئری خاصی به بانک اطلاعاتی ارسال نگردد، EF Code first بانک اطلاعاتی را آغاز نخواهد کرد.
در متد LoadWithTracking اطلاعات تمام رکوردها به صورت متداولی بارگذاری شده است.
در متد LoadWithoutTracking نحوه استفاده از متد الحاقی AsNoTracking را مشاهده میکنید. در این متد سطح اول کش به این ترتیب خاموش میشود.
و متد RunTests، این متدها را در سه بار متوالی اجرا کرده و نتیجه عملیات را نمایش خواهد داد.
برای نمونه این نتیجه در اینجا حاصل شده است:
همانطور که ملاحظه کنید، بین این دو حالت، تفاوت بسیار قابل ملاحظه است؛ چه از لحاظ مصرف حافظه و چه از لحاظ سرعت.
نتیجه گیری:
اگر قصد ندارید بر روی اطلاعات دریافتی از بانک اطلاعاتی تغییرات خاصی را انجام دهید و فقط قرار است از آنها به صورت فقط خواندنی گزارشگیری شود، بهتر است سطح اول کش را به کمک متد الحاقی AsNoTracking خاموش کنید.
لیستی از C# Source Generators
C# Source Generators
A list of C# Source Generators (not necessarily awesome), because I haven't found a good list yet.
C# Source Generators is a Roslyn compiler feature introduced in C#9/.NET 5. It lets C# developers inspect user code and generate new C# source files that can be added to a compilation.
<ErrorBoundary> <ChildContent> @Body </ChildContent> <ErrorContent> <p>Whoa, sorry about that! While we fix this problem, buy some shirts!</p> </ErrorContent> </ErrorBoundary>
<ErrorContent Context="exception"> @exception </ErrorContent>
<ErrorBoundary @ref="errorBoundary"> @Body </ErrorBoundary> @code { ErrorBoundary errorBoundary; protected override void OnParametersSet() { // On each page navigation, reset any error state errorBoundary?.Recover(); } }
public int[] WithSpread() { int[] data = new int[10_000]; int[] results = [..data]; return results; }
public int[] WithSpread() { int[] numArray1 = new int[10000]; int index1 = 0; int[] numArray2 = new int[numArray1.Length]; int[] numArray3 = numArray1; for (int index2 = 0; index2 < numArray3.Length; ++index2) { int num = numArray3[index2]; numArray2[index1] = num; ++index1; } return numArray2; }
using BenchmarkDotNet.Attributes; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace SpreadBenchmark { [MemoryDiagnoser] public class Tests { private readonly int[] _myData = new int[10_000]; [Benchmark(Baseline = true)] public int[] WithToArray() { int[] results = _myData.ToArray(); return results; } [Benchmark] public int[] WithCopyTo() { int[] results = new int[_myData.Length]; _myData.CopyTo(results, 0); return results; } [Benchmark] public int[] WithSpread() { int[] results = [.._myData]; return results; } } }
using BenchmarkDotNet.Running; using SpreadBenchmark; BenchmarkRunner.Run<Tests>();
<Project Sdk="Microsoft.NET.Sdk"> <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net8.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup> <ItemGroup> <PackageReference Include="BenchmarkDotNet" Version="0.13.10" /> </ItemGroup> </Project>