EF Code First #12
بررسی تصویر امنیتی (Captcha) سایت - قسمت دوم
ممنون از پاسختون.
اما IIS من ۷ است و موردی رو هم که فرمودید پیش از این چک کردم ولی تغییری حاصل نشده بود.
آشنایی با NHibernate - قسمت سوم
EF Code First #10
- در EF 6 اصلا نیازی به پروفایلر خاصی ندارید : نحوهی لاگ کردن توکار با EF 6
- برنامههای دیگری هم برای لاگ کردن وجود دارند (سورس باز و رایگان). مثلا mini profiler
FirstName
firstName
strFirstName lblFirstName
<Company>.<Technology|Produt|Project>[.<Feature>][.<SubNamespace>]
Microsoft.Reporting.WebForms Kara.Support.Manager.Enums Kara.CSS.HQ.WebUI.Configuration
PackageManager , PacakgeConfigGenerator Circle , Utility , Package
CreateConfig , classdata CManager , ClsPackage , Config_Creator , Config1389
CenterCollection , PackageCollection
public delegate void Logger (string log); public delegate void LoggingCallback (object sender, string reason);
AddEventArgs , EditEventArgs , DeleteEventArgs
Adding , Add , Added
public delegate void <EventName>EventHandler (object sender, <EventName>EventArgs e);
public event EventHandler <AddEventArgs> Adding;
DisplayNameAttribute , MessageTypeAttribute
IComponent (اسم) IConnectionProvider (موصوف) ICloneable (صفت)
public enum FileMode { Append, Read, … }
[Flag] public enum KeyModifiers { Alt = 1, Control = 2, Shift = 4 }
public enum OperationState { DoneState, FaultState, RollbackState }
AddDays , Save , DeleteRow , BindData , Close , Open
Radius , ReportType , DataSource , Mode , CurrentCenterId
public CenterCollection Centers { get; set; }
if (list.Contains(item)) if (regularExpression.Matches(text)) if (stream.CanSeek) if (context.Created) if (form.Enabled)
if (list.IsContains(item)) if (regularExpression.Match(text)) if (stream.Seekable) if (context.IsCreated) if (form.IsEnabled)
public Color Color { get; set; }
firstName , e , id , packageId , centerName , name
public static MyType operator +(MyType left, MyType right) public static bool operator ==(MyType left, MyType right)
public static MyType operator ++(MyType value)
public static MyType operator /(MyType dividend, MyType divisor)
public static MyType operator -(MyType d1, MyType d2) // incorrect!
Area , DataBinder , PublicCacheName
_centersList _firstName _currentCenter
parameterType , packageOperationTypeId
lblName (Label) txtHeader (TextBox) btnSave (Button)
ArgumentNullException , InvalidOperaionException
System.Data
<Company>.<Component>.dll <Company>.<Project|Product|Technology>.<Component>.dll
Microsoft.CSharp.dll , Kara.CSS.Manager.dll
public int IComparer<T> {…} public delegate bool Predicate<T> (T item)
public int ISessionChannel<TSession> {…} public delegate TOutput Converter<TInput, TOutput> (TInput from) public class Nullable<T> {…} public class List<T> {…}
ArgumentExceptionIllegalCharacters ArgumentExceptionInvalidName ArgumentExceptionFileNotFound
Pascal Casing |
camel Casing |
Wrong |
Callback |
callback |
CallBack |
BitFlag |
bitFlag |
Bitflag / bitflag |
Canceled |
canceled |
Cancelled |
DoNot |
doNot |
Donot / Don’t |
|
|
|
Endpoint |
endpoint |
EndPoint / endPoint |
FileName |
fileName |
Filename / filename |
Gridline |
gridline |
GridLine / gridLine |
Hashtable |
hashtable |
HashTable / hashTable |
Id |
id |
ID |
Indexes |
indexes |
Indices |
LogOff |
logOff |
Logoff / LogOut ! |
LogOn |
logOn |
Logon / LogIn ! |
SignOut |
signOut |
Signout / SignOff |
SignIn |
signIn |
Signin / SignOn |
Metadata |
metadata |
MetaData / metaData |
Multipanel |
multipanel |
MultiPanel / multiPanel |
Multiview |
multiview |
MultiView / multiView |
Namespace |
namespace |
NameSpace / nameSpace |
Ok |
ok |
OK |
Pi |
pi |
PI |
Placeholder |
placeholder |
PlaceHolder / placeHolder |
UserName |
username |
Username / username |
WhiteSpace |
whiteSpace |
Whitespace / whitespace |
Writable |
writable |
Writeable / writeable |
public class Color { … public static Color FromArgb(…) { … } }
در ادامه یک سری از خط مشیهای متداول در defensive programming را با هم مرور خواهیم کرد:
1- بررسی نال بودن اشیاء
سعی در استفاده از اشیاء نال، به یک NullReferenceException منتهی خواهد شد. اگر به هر دلیلی امکان نال بودن یک شیء وجود داشت، پیش از استفاده از آن، حتما این وضعیت را بررسی نمائید.
بهترین ابزاری هم که برای این منظور میتوان استفاده کرد، نگارش جدید افزونهی ReSharper است که زیر شیءایی را که احتمال نال بودن آن میرود یک خط آبی رنگ میکشد.
2- بررسی آرگومانهای دریافتی
برای نمونه اگر متد شما تاریخی را بر اساس DateTime دریافت میکند، حتما حدود آنرا بررسی نمائید. برای مثال دریافت تاریخ 31 اسفند از کاربر، به یک ArgumentOutOfRangeException منتهی خواهد شد. بنابراین آرگومانهای دریافت شده باید انتظارات مربوطه را برآورده کنند و پیش از استفاده حتما بررسی گردند تا بتوان مشکلات را به کاربر به صورت واضحی گوشزد کرد. (خطای ArgumentOutOfRangeException برای کاربر نهایی بیمعنی است)
3- وضعیت اشیاء را بررسی کنید
برای مثال بستن یک کانکشن به دیتابیس در صورت بسته بودن آن، به یک InvalidOperationException منتهی میشود. بنابراین بهتر است ابتدا وضعیت این شیء بررسی شده و سپس عملیات خاصی بر روی آن صورت گیرد.
4- هنگام کار با آرایهها دقت کنید
اگر اندیس فراخوانی شده کمتر از صفر یا بیشتر از اندازهی آرایه باشد به یک IndexOutOfRangeException بر خواهید خورد. بنابراین همواره بهتر است که این بررسی پیش از بروز واقعه انجام شود.
5- مراقب الگوریتمهای بازگشتی باشید
هر چند متدهای بازگشتی در بعضی از موارد کار راه انداز هستند اما اگر بدون دقت از آنها استفاده شود ممکن است سبب ایجاد یک حلقهی بی نهایت شده و نهایتا برنامه با یک StackOverFlowException خاتمه مییابد (این مورد در دات نت فریم ورک تنها حالتی است که با try و catch قابل مهار نیست).
6- هنگام تبدیل اشیایی از نوع object مراقب باشید
اگر قصد تبدیل یک شیء را به نوعی داشته باشید که با مقدار ذخیره شده در آن مطابقت ندارد، یک InvalidCastException حاصل خواهد شد. بنابراین در اینگونه موارد بهتر است از اپراتورهای as و یا is استفاده کنید. هنگام استفاده از as اگر عملیات تبدیل با موفقیت صورت نگیرد، حاصل عملیات تنها یک شیء نال خواهد بود و استثنایی رخ نخواهد داد.
7- بجای متد Parse از TryParse استفاده کنید
برای مثال در دات نت جهت تبدیل یک رشته به مقداری عددی میتوان از int.Parse و یا int.TryParse استفاده کرد. در حالت اول اگر عملیات تبدیل میسر نباشد حتما یک FormatException رخ خواهد داد اما در حالت دوم در صورت موفقیت آمیز بودن عملیات تبدیل، خروجی true خواهد بود و حاصل اصلی را با یک پارامتر از نوع out در اختیار شما قرار میدهد.
و به صورت خلاصه
- ورودیهای کاربر را محدود کرده (مثلا اگر قرار است عددی را وارد کند، از یک تکست باکس عددی (masked edit controls) استفاده کنید) و یا آنها را دقیقا بررسی نمائید تا احتمال بروز خطاهای بعدی را کاهش دهید.
- زمانیکه میتوان از بروز یک exception جلوگیری کرد، بهتر است مدیریت آنرا به قسمت catch بلاک try/catch واگذار نکرد.
- و هنگامیکه با برنامه نویسی نمیتوانید تمامی خطاهای ممکن را پیش بینی کرده و آنها را مدیریت کنید، برای مدیریت استثناءها برنامه داشته باشید.
public async Task Sample() { var customers = await GetCustomersFromSomeWhere(); foreach (var customer in customers) { await DoSomethingWithCustomer(customer); } }
public async Task Sample() { var customers = await GetCustomersFromSomeWhere(); await Task.WhenAll(customers.Select(c => DoSomethingWithCustomer(c))); }
public async Task Sample() { var customers = await GetCustomersFromSomeWhere(); await customers.Select(c => Observable.FromAsync(() => DoSomethingWithCustomer(c))).Merge(maxConcurrent: 25); }
public async Task Sample() { var customers = await GetCustomersFromSomeWhere(); ActionBlock<Customer> action = new ActionBlock<Customer>(c => DoSomethingWithCustomer(c), new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 25 }); foreach (var customer in customers) { action.Post(customer); } action.Complete(); await action.Completion; }
public class IdentityUser<TKey> where TKey : IEquatable<TKey> { [ProtectedPersonalData] public virtual string UserName { get; set; } [ProtectedPersonalData] public virtual string Email { get; set; }
روش فعالسازی ذخیره سازی رمزنگاری شدهی اطلاعات شخصی کاربران
اگر برنامهی پیشین خود را به نگارشهای جدیدتر ASP.NET Core Identity ارتقاء داده باشید، احتمالا متوجه وجود یک چنین قابلیتی نشدهاید؛ چون به صورت پیشفرض غیرفعال است. برای فعالسازی آن، میتوان به صورت زیر عمل کرد:
services.AddIdentity<IdentityUser, IdentityRole>(options => { options.Stores.ProtectPersonalData = true; // ... })
ویژگی ProtectedPersonalData چگونه به صورت خودکار پردازش میشود؟
پیشنیاز درک نحوهی پردازش ویژگی ProtectedPersonalData، مطلب «رمزنگاری خودکار فیلدها توسط Entity Framework Core» است. در اینجا نیز دقیقا یک «تبدیلگر مقدار» برای رمزنگاری و رمزگشایی خودکار فیلدهای مزین به ProtectedPersonalData تدارک دیده شدهاست:
private class PersonalDataConverter : ValueConverter<string, string> { public PersonalDataConverter(IPersonalDataProtector protector) : base(s => protector.Protect(s), s => protector.Unprotect(s), default) { } }
سپس در IdentityUserContext تعریف شده و متد OnModelCreating آن، ابتدا بررسی میکند که آیا پیشتر ProtectPersonalData را به true تنظیم کردهاید یا خیر؟ اگر بله، تمام خواصی را که با ویژگی ProtectedPersonalDataAttribute مزین شدهاند، یافته و سپس توسط متد HasConversion به آنها تبدیلگر مقداری از نوع PersonalDataConverter را اضافه میکند:
protected override void OnModelCreating(ModelBuilder builder) { var encryptPersonalData = storeOptions?.ProtectPersonalData ?? false; builder.Entity<TUser>(b => { if (encryptPersonalData) { converter = new PersonalDataConverter(this.GetService<IPersonalDataProtector>()); var personalDataProps = typeof(TUser).GetProperties().Where( prop => Attribute.IsDefined(prop, typeof(ProtectedPersonalDataAttribute))); foreach (var p in personalDataProps) { if (p.PropertyType != typeof(string)) { throw new InvalidOperationException(Resources.CanOnlyProtectStrings); } b.Property(typeof(string), p.Name).HasConversion(converter); } } // ...
اگر در کدهای فوق، به جائیکه new PersonalDataConverter نوشته شده دقت کنید؛ یک سرویس از نوع IPersonalDataProtector را دریافت میکند که توسط آن دو متد Protect و Unprotect به کلاس خصوصی PersonalDataConverter تزریق میشوند:
public interface IPersonalDataProtector { string Protect(string data); string Unprotect(string data); }
تاثیر فعالسازی ProtectPersonalData بر روی سایر سرویسهای ASP.NET Core Identity
اگر options.Stores.ProtectPersonalData را به true تنظیم کنید، سرویس UserManager اینبار انتظار خواهد داشت که IUserStore ای که به آن تزریق میشود، از نوع جدید IProtectedUserStore باشد؛ در غیراینصورت یک استثناء را صادر میکند:
if (Options.Stores.ProtectPersonalData) { if (!(Store is IProtectedUserStore<TUser>)) { throw new InvalidOperationException(Resources.StoreNotIProtectedUserStore); } if (services.GetService<ILookupProtector>() == null) { throw new InvalidOperationException(Resources.NoPersonalDataProtector); } }
public class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> : ...
همچنین تمام متدهای سرویس UserManager که با خواص مزین شدهی به [ProtectedPersonalData] کار میکنند، جهت استفادهی از متد ProtectPersonalData به روز رسانی شدهاند:
public virtual async Task UpdateNormalizedUserNameAsync(TUser user) { var normalizedName = NormalizeName(await GetUserNameAsync(user)); normalizedName = ProtectPersonalData(normalizedName); await Store.SetNormalizedUserNameAsync(user, normalizedName, CancellationToken); }
چگونه میتوان بجای DefaultPersonalDataProtector پیشفرض، از یک نمونهی سفارشی استفاده کرد؟
برای انجام اینکار نیاز است ILookupProtector خودتان را نوشته و به سیستم معرفی کنید. یک نمونه از پیاده سازی سفارشی آنرا در پروژهی AspNetCoreIdentityEncryption میتوانید مشاهده نمائید.