یکی از سؤالاتی که ممکن است در مصاحبهها با آن روبرو شوید، عنوان این مطلب است. در این مقاله قصد داریم تفاوت بین این دو را بررسی کنیم.
در علم کامپیوتر، یک call stack، یک ساختار دادهای پشته میباشد که اطلاعات جزئی را راجع به زیرروالهای فعال یک برنامه، ذخیره میکند. این نوع پشته با اسامی مختلفی از جمله Execution Stack (ES)، Program Stack (PS)، Control Stack، Runtime Stack یا Machine Stack شناخته میشود و یا اینکه به صورت کلی به آن The Stack یا همان پشته هم میگویند. با استفاده از صفحه Call Stack میتوانیم توابع و پروسیجرهایی را که فراخوانی شدهاند، ببینیم. Call Stack به ما میگوید که کدام متدها و توابع، با چه ترتیبی اجرا شدهاند. Call Stack یک راه بسیار خوب، برای فهم درست نحوهی اجرای یک برنامه است. با رهگیری یا Track کردن Call Stack میتوانیم بفهمیم که مکانیزم کار داخلی برنامه چگونه است و برای بهتر رفع کردن مشکلات، از آن استفاده کنیم. در سی شارپ، Stack Trace یک پشتهی اجرایی یا Execution Stack است که تمامی متدهای درحال اجرا را رهگیری (Track) میکند. Stack Trace راهی است که با استفاده از آن میتوانیم Call Stack را بررسی کنیم، تا شماره خط متدی را که Exception درآن رخ داده است، ببینیم. از این به بعد برای سادگی مطلب، Stack Trace را به صورت ST بیان میکنیم. برای دسترسی به ST از فضای نام System.Diagnostics مانند زیر استفاده میکنیم.
System.Diagnostics.StackTrace myTrack = new System.Diagnostics.StackTrace();
و یا برای مشاهدهی آن در کنسول از کد زیر استفاده میکنیم:
static void Main(string[] args) { Console.WriteLine("Stack Trace: {0}", Environment.StackTrace); }
نتیجه:
Stack Trace:at System.Environment.get_StackTrace() at DiffThrowAndThrowException.Program.Main(String[] args) in Program.cs:line 9
استفاده از ST در Try Catch :
static void Main(string[] args) { try { throw new Exception(); } catch (Exception ex) { Console.WriteLine("Stack Trace: {0}", Environment.StackTrace); } }
نتیجه:
Stack Trace:at System.Environment.get_StackTrace() at DiffThrowAndThrowException.Program.Main(String[] args) in Program.cs:line 11
حالا که مفهوم Stack Trace و نحوه کار و نمایش آن را بررسی کردیم، به راحتی میتوان تفاوت بین Throw و Throw Exception را درک کرد. به طور کلی میتوان اینطور گفت، در حالتیکه در داخل بلاک Catch، از Throw استفاده کنیم، این کار باعث میشود استثنائی که در اینجا رخ داده، به ابتدای ST افزوده شده و در واقع سلسله مراتب اجرای برنامه تا جایی که Throw نوشته شده، در ST نگهداری شود. اما در صورتیکه به جای Throw از Throw Exception استفاده کنیم، اتفاقی که رخ میدهد این است که ST تا اینجای کار که throw exception را استفاده میکنیم، نگهداری میشود و اطلاعات متدهایی که بعد از throw exception اجرا شدهاند، از آن حذف میشود. در نهایت در این حالت ST شامل اطلاعات متدهای اجرا شده در فرآیند جاری، از ابتدا تا رسیدن به throw exception میباشد.
در زیر، نمونه کدی را برای استفاده از Throw، میبینید:
class Program { static void Main(string[] args) { FirstExceptionMethod firstException = new FirstExceptionMethod(); try { firstException.Method1(); } catch (Exception ex) { Console.WriteLine(ex.StackTrace); } } } class FirstExceptionMethod { public void Method1() { try { SecondExceptionMethod secondException = new SecondExceptionMethod(); secondException.Method2(); } catch (Exception ex) { throw; } } } class SecondExceptionMethod { public void Method2() { try { ThrowExMethod(); } catch (Exception ex) { throw; } } public void ThrowExMethod() { throw new Exception(); } }
نتیجه:
at DiffThrowAndThrowException.SecondExceptionMethod.ThrowExMethod() in Program.cs:line 51 at DiffThrowAndThrowException.SecondExceptionMethod.Method2() in Program.cs:line 41 at DiffThrowAndThrowException.FirstExceptionMethod.Method1() in Program.cs:line 27 at DiffThrowAndThrowException.Program.Main(String[] args) in Program.cs:line 12
همانطور که میبینید اطلاعات متدهایی که در این فرآیند اجرا شدهاند، در داخل Stack Trace رهگیری (track) شدهاند.
این دفعه برای نشان دادن تفاوت محتویات ST، کدهای Method1 را به شکل زیر تغییر میدهیم که در بخش catch آن، از throw exception استفاده کردهایم:
public void Method1() { try { SecondExceptionMethod secondException = new SecondExceptionMethod(); secondException.Method2(); } catch (Exception ex) { throw new Exception("Some Text ..."); } }
نتیجه:
at DiffThrowAndThrowException.FirstExceptionMethod.Method1() in Program.cs:line 31 at DiffThrowAndThrowException.Program.Main(String[] args) in Program.cs:line 12
در اینجا اطلاعات متدهای برنامه از شروع فرآیند تا جائیکه از throw exception استفاده کرده، در ST نوشته میشود.
با دیدن خروجیهای بالا میتوان دریافت که استفاده از throw exception بجای throw باعث میشود تا اطلاعات کمتری از فرآیند اجرا شده در ST ذخیره شود و در واقع رهگیری متدهای فرآیند از ابتدا تا جائیکه throw exception استفاده میشود، پیش میرود و بعد از آن اطلاعاتی را ثبت نمیکند.
طراحی یک معماری خوب و مناسب یکی از عوامل مهم تولید یک برنامه
کاربردی موفق میباشد. بنابراین انتخاب یک ساختار مناسب به منظور تولید برنامه
کاربردی بسیار مهم و تا حدودی نیز سخت است. در اینجا یاد خواهیم گرفت که چگونه یک
طراحی مناسب را انتخاب نماییم. همچنین روشهای مختلف تولید برنامههای کاربردی را
که مطمئنا شما هم از برخی از این روشها استفاده نمودید را بررسی مینماییم و مزایا
و معایب آن را نیز به چالش میکشیم.
ضد الگو (Antipattern) – رابط کاربری هوشمند (Smart UI)
با استفاده از Visual Studio یا به اختصار VS، میتوانید برنامههای کاربردی را به راحتی تولید نمایید. طراحی رابط کاربری به آسانی عمل کشیدن و رها کردن (Drag & Drop) کنترلها بر روی رابط کاربری قابل انجام است. همچنین در پشت رابط کاربری (Code Behind) تمامی عملیات مربوط به مدیریت رویدادها، دسترسی به داده ها، منطق تجاری و سایر نیازهای برنامه کاربردی، کد نویسی خواهند شد. مشکل این نوع کدنویسی بدین شرح است که تمامی نیازهای برنامه در پشت رابط کاربری قرار میگیرند و موجب تولید کدهای تکراری، غیر قابل تست، پیچیدگی کدنویسی و کاهش قابلیت استفاده مجدد از کد میگردد.
به این روش کد نویسی Smart UI میگویند که موجب تسهیل تولید برنامههای کاربردی میگردد. اما یکی از مشکلات عمدهی این روش، کاهش قابلیت نگهداری و پشتیبانی و عمر کوتاه برنامههای کاربردی میباشد که در برنامههای بزرگ به خوبی این مشکلات را حس خواهید کرد.
از آنجایی که تمامی برنامه نویسان مبتدی و تازه کار، از جمله من و شما در روزهای اول برنامه نویسی، به همین روش کدنویسی میکردیم، لزومی به ارائه مثال در رابطه با این نوع کدنویسی نمیبینم.
تفکیک و جدا سازی اجزای برنامه کاربردی (Separating Your Concern)
راه حل رفع مشکل Smart UI، لایه بندی یا تفکیک اجزای برنامه از یکدیگر میباشد. لایه بندی برنامه میتواند به شکلهای مختلفی صورت بگیرد. این کار میتواند توسط تفکیک کدها از طریق فضای نام (Namespace)، پوشه بندی فایلهای حاوی کد و یا جداسازی کدها در پروژههای متفاوت انجام شود. در شکل زیر نمونه ای از معماری لایه بندی را برای یک برنامه کاربردی بزرگ میبینید.
به منظور پیاده سازی یک برنامه کاربردی لایه بندی شده و تفکیک اجزای برنامه از یکدیگر، مثالی را پیاده سازی خواهیم کرد. ممکن است در این مثال با مسائل جدید و شیوههای پیاده سازی جدیدی مواجه شوید که این نوع پیاده سازی برای شما قابل درک نباشد. اگر کمی صبر پیشه نمایید و این مجموعهی آموزشی را پیگیری کنید، تمامی مسائل نامانوس با جزئیات بیان خواهند شد و درک آن برای شما ساده خواهد گشت. قبل از شروع این موضوع را هم به عرض برسانم که علت اصلی این نوع پیاده سازی، انعطاف پذیری بالای برنامه کاربردی، پشتیبانی و نگهداری آسان، قابلیت تست پذیری با استفاده از ابزارهای تست، پیاده سازی پروژه بصورت تیمی و تقسیم بخشهای مختلف برنامه بین اعضای تیم و سایر مزایای فوق العاده آن میباشد.
1- Visual Studio را باز کنید و یک Solution خالی با نام SoCPatterns.Layered ایجاد نمایید.
· جهت ایجاد Solution خالی، پس از انتخاب New Project، از سمت چپ گزینه Other Project Types و سپس Visual Studio Solutions را انتخاب نمایید. از سمت راست گزینه Blank Solution را انتخاب کنید.
2- بر روی Solution کلیک راست نموده و از گزینه Add > New Project یک پروژه Class Library با نام SoCPatterns.Layered.Repository ایجاد کنید.
3- با استفاده از روش فوق سه پروژه Class Library دیگر با نامهای زیر را به Solution اضافه کنید:
- SoCPatterns.Layered.Model
- SoCPatterns.Layered.Service
- SoCPatterns.Layered.Presentation
4- با توجه به نیاز خود یک پروژه دیگر را باید به Solution اضافه نمایید. نوع و نام پروژه در زیر لیست شده است که شما باید با توجه به نیاز خود یکی از پروژههای موجود در لیست را به Solution اضافه کنید.
- Windows Forms Application (SoCPatterns.Layered.WinUI)
- WPF Application (SoCPatterns.Layered.WpfUI)
- ASP.NET Empty Web
Application (SoCPatterns.Layered.WebUI)
- ASP.NET MVC 4 Web
Application (SoCPatterns.Layered.MvcUI)
5- بر روی پروژه SoCPatterns.Layered.Repository کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژهی SoCPatterns.Layered.Model ارجاع دهید.
6- بر روی پروژه SoCPatterns.Layered.Service کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model و SoCPatterns.Layered.Repository ارجاع دهید.
7- بر روی پروژه SoCPatterns.Layered.Presentation کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model و SoCPatterns.Layered.Service ارجاع دهید.
8- بر روی پروژهی UI خود به عنوان مثال SoCPatterns.Layered.WebUI کلیک راست نمایید و با انتخاب گزینه Add Reference به پروژههای SoCPatterns.Layered.Model، SoCPatterns.Layered.Repository، SoCPatterns.Layered.Service و SoCPatterns.Layered.Presentation ارجاع دهید.
9- بر روی پروژهی UI خود به عنوان مثال SoCPatterns.Layered.WebUI کلیک راست نمایید و با انتخاب گزینه Set as StartUp Project پروژهی اجرایی را مشخص کنید.
10- بر روی Solution کلیک راست نمایید و با انتخاب گزینه Add > New Solution Folder پوشههای زیر را اضافه نموده و پروژههای مرتبط را با عمل Drag & Drop در داخل پوشهی مورد نظر قرار دهید.
- 1. UI
- § SoCPatterns.Layered.WebUI
- 2. Presentation Layer
- § SoCPatterns.Layered.Presentation
- 3. Service Layer
- § SoCPatterns.Layered.Service
- 4. Domain Layer
- § SoCPatterns.Layered.Model
- 5. Data Layer
- § SoCPatterns.Layered.Repository
- توجه
داشته باشید که پوشه بندی برای مرتب سازی لایهها و دسترسی راحتتر به آنها میباشد.
پیاده سازی ساختار لایه بندی برنامه به صورت کامل انجام شد. حال به پیاده سازی کدهای مربوط به هر یک از لایهها و بخشها میپردازیم و از لایه Domain شروع خواهیم کرد.
یک سرویس کوچک ویندوز ان اتی نوشتهام که کارش این است که در پایان هر هفته، تمام دیتابیسهای اس کیوال سرور موجود را یافته و اسکریپت تمام اشیاء آنها را به صورت خودکار تولید میکند (از جداول گرفته تا تریگرها، رویههای ذخیره شده و غیره)، سپس کل مجموعه را فشرده کرده و سپس ایمیل میزند. اینکار برای نگهداری تغییرات انجام شده در طول یک هفته لازم است.
برنامه با استفاده از امکانات SMO تهیه شده است و اگر علاقمند بودید که اینکار را انجام دهید، میتوانید به مقالههای زیر رجوع کنید:
Making a database clone using SMO
Using the SqlServer.Management.Smo
SQL Server: SMO Scripting Basics
با آمدن اس کیوال سرور 2008، اشیاء SMO هم به روز شدهاند و اگر با این اشیاء برنامه نویسی کرده باشید، برنامه بر روی سروری با اس کیوال سرور 2005 اجرا نخواهد شد و پیغام خطای زیر را دریافت خواهید کرد:
خوشبختانه مایکروسافت این کتابخانهها را به صورت مجزا هم برای دریافت قرار داده است و میتوان آنها را نصب نمود تا برنامه بدون اشکال اجرا شود. به صفحه زیر و قسمت Microsoft SQL Server 2008 Management Objects مراجعه نمائید:
اینجا کلیک نمائید
البته همانطور که در صفحه ذکر شده نیز عنوان گردیده است، به MSXML 6.0 هم نیاز میباشد که لینک دریافت آن در ابتدای صفحه فوق موجود است.
5 دلیل برای استفاده از یک ابزار ORM
- امیدی به ادامهی آن باشد (نگن امروز به به! فردا ... خوب دیگه ... تموم شد! صرف نمیکنه، دیگه توسعه نمیدیم! خیلی از سیاستهای مایکروسافت همینطوری است. مثلا همون کاری که با LINQ to SQL کرد)
- چند هزار نفری پیرو و دنبال مباحث آن باشند (حداقل 2 تا فوروم رفع اشکال بتونید پیدا کنید)
- دو تا کتاب در موردش باشه
- 4 تا وبلاگ در موردش مطلب بنویسند.
و مسایلی از این دست.
به همین جهت یا روی EF یا NH سرمایه گذاری کنید.
به شخصه NH رو ترجیح میدم چون سورس باز است، به همین جهت مرگ برای آن معنی ندارد (این گروه نخواست ادامه بده ... گروههای دیگر هستند)، رایگان است، مجوزش اجازه استفاده در کارهای تجاری سورس بسته را میدهد. چندتا کتاب در موردش هست و ...
به EF شک دارم. نمیدونم مایکروسافت مثلا 4 سال دیگه آیا این را هم بازنشسته اعلام میکند یا نه.
در SampleProject1 مدل Product را داریم:
public partial class Product : Entity { public int Id { get; set; } public string Name { get; set; } public Nullable<byte> ProductTypeId { get; set; } }
public partial class ProductType : Entity { public byte Id { get; set; } public string Name { get; set; } }
List<Assembly> allAssemblies = new List<Assembly>(); string path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); foreach (string dll in Directory.GetFiles(path, "*.Common.dll")) allAssemblies.Add(Assembly.LoadFile(dll)); var type = typeof(Entity); List<Type> types = allAssemblies .SelectMany(s => s.GetTypes()) .Where(p => type.IsAssignableFrom(p)).ToList(); List<string> entities = new List<string>(); foreach (var item in types) { entities.Add(item.Name); } types.Add(typeof(Entity));
public class ContextGenerator { public void Generate(List<string> entities, params Type[] types) { StringBuilder code = new StringBuilder(); code.AppendLine(@" using System.Data.Entity; using System.Data.Entity.Core.EntityClient; using SampleProject1.Common.Models; using SampleProject1.Common.Models.Mapping; using SampleProject2.Common.Models; using SampleProject2.Common.Models.Mapping; namespace DbContextGenerator { public partial class TestContext : DbContext { static TestContext() { Database.SetInitializer<TestContext>(null); } public TestContext() : base(""Data Source=.;Initial Catalog=Test;Integrated Security=True;MultipleActiveResultSets=True"") { } "); var pluralizeHelper = new PluralizeHelper(); foreach (var entity in entities) { code.AppendLine($@"public DbSet<{entity}> {pluralizeHelper.Pluralize(entity)} {{ get; set; }}"); } code.AppendLine(@"protected override void OnModelCreating(DbModelBuilder modelBuilder)"); code.AppendLine(@"{"); foreach (var entity in entities) { code.AppendLine($@"modelBuilder.Configurations.Add(new {entity}Map());"); } code.AppendLine(@"}"); code.AppendLine(@"}"); code.AppendLine(@"}"); CSharpCodeProvider provider = new CSharpCodeProvider(); CompilerParameters parameters = new CompilerParameters(); parameters.ReferencedAssemblies.Add("System.Drawing.dll"); parameters.ReferencedAssemblies.Add("System.Data.dll"); parameters.ReferencedAssemblies.Add("System.Data.Entity.dll"); parameters.ReferencedAssemblies.Add("System.ComponentModel.dll"); foreach (var type in types) { parameters.ReferencedAssemblies.Add(type.Assembly.Location); } parameters.ReferencedAssemblies.Add(typeof(DbSet).Assembly.Location); parameters.ReferencedAssemblies.Add(typeof(DbContext).Assembly.Location); parameters.ReferencedAssemblies.Add(typeof(IQueryable).Assembly.Location); parameters.ReferencedAssemblies.Add(typeof(IQueryable<>).Assembly.Location); parameters.ReferencedAssemblies.Add(typeof(System.ComponentModel.IListSource).Assembly.Location); parameters.GenerateExecutable = false; parameters.GenerateInMemory = false; parameters.OutputAssembly = "ProjectContext.dll"; CompilerResults results = provider.CompileAssemblyFromSource(parameters, code.ToString()); if (results.Errors.HasErrors) { StringBuilder sb = new StringBuilder(); foreach (CompilerError error in results.Errors) { sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText)); } throw new InvalidOperationException(sb.ToString()); } } }
new ContextGenerator().Generate(entities, types.ToArray()); // generate dbContext
حال برای استفاده از Context تولید شده، به صورت زیر شیءایی را ساخته:
static DbContext _dbContext=null; public static DbContext GetDbContextInstance() { if (_dbContext == null) { string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); var dllversionAssm = Assembly.LoadFile(path + "\\ProjectContext.dll"); Type type = dllversionAssm.GetType("DbContextGenerator.TestContext"); _dbContext = (DbContext)Activator.CreateInstance(type); } return _dbContext; }
و سپس برای ساخت DbSet از هر Entity به کد زیر نیاز خواهیم داشت:
public static System.Data.Entity.DbSet<T> Get<T>() where T : class { var set = GetDbContextInstance().Set<T>(); return set; }
هم اکنون میتوان رکوردهای Entityها را واکشی کرده و یا آنها را با یکدیگر Join بزنیم:
var products = Get<Product>().ToList(); var productTypes = Get<ProductType>().ToList(); var query = from p in Get<Product>() join pt in Get<ProductType>() on p.ProductTypeId equals pt.Id select new { Id = p.Id, Name = p.Name, ProductType = pt.Name }; var JoinResult = query.ToList();
و نتیجه واکشی ها
5 پیشنهاد جهت کنترل بهتر تیم خلاق
شروع هرگونه سرمایه گذاری جدید هیجان انگیز است. شما از چنگال زندگی شرکتهای آزاد است و در نهایت قادر به کنترل برنامه، نرخ، پایه مشتری و گردش کار خود هستید. هرچه بیشتر پیشرفت میکنید مسئولیتها نیز در ابعاد بیشتری پیشرفت میکنند که شما وقت انجام آن را ندارید؛ به همین جهت شروع به استخدام چندنفر در قالب یک تیم خواهید نمود که ممکن است به ناسازگاریهایی در روند مدیریت گروه مواجه شوید...
تا حدی که برای من و خیلی ها عادت شده بود که شب ها قبل از خواب ابتدا اشتراک های شما رو بررسی کنیم.
جدا از خلاصه اشتراک ها بدون تملق این وبلاگ "مهمترین" دلیل اندک پیشرفت من و امثال من که در ابتدای راه هستیم بوده .
امیدوارم همچنان به تلاشتون جهت پیشرفت بار فنی و فکر برنامه نویسان ایرانی ادامه بدید. و فضایی که ذکر کردید بیشتر از الآن متقابل شود.
ممنون.
static void Main(string[] args) { var configuration = new Raven.Database.Config.RavenConfiguration() { AccessControlAllowMethods = "All", AnonymousUserAccessMode = Raven.Database.Server.AnonymousUserAccessMode.All, DataDirectory = @"C:\Sam\labs\HttpServerData", Port = 8071, }; var database = new Raven.Database.DocumentDatabase(configuration); var server = new Raven.Database.Server.HttpServer(configuration, database); database.SpinBackgroundWorkers(); server.StartListening(); Console.WriteLine("RavenDB http server is running ..."); Console.ReadLine(); }
CloudStorageAccount storageAccount = CloudStorageAccount.FromConfigurationSetting(connectionString); // here is when later on you may add code for inititalizing CloudDrive chache CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient(); blobClient.GetContainerReference("drives").CreateIfNotExist(); CloudDrive cloudDrive = storageAccount.CreateCloudDrive( blobClient .GetContainerReference("drives") .GetPageBlobReference("ravendb4.vhd") .Uri.ToString() ); try { // create a 1GB Virtual Hard Drive cloudDrive.Create(1024); } catch (CloudDriveException /*ex*/ ) { // the most likely exception here is ERROR_BLOB_ALREADY_EXISTS // exception is also thrown if the drive already exists }
string driveLetter = cloudDrive.Mount(25, DriveMountOptions.Force);
LocalResource localCache = RoleEnvironment.GetLocalResource("RavenCache"); CloudDrive.InitializeCache(localCache.RootPath, localCache.MaximumSizeInMegabytes);
حال که پورت هم تنظیم شده است میتوانیم RavenDB را در Worker Role راه بیاندازیم:
var config = new RavenConfiguration { DataDirectory = driveLetter, AnonymousUserAccessMode = AnonymousUserAccessMode.All, HttpCompression = true, DefaultStorageTypeName = "munin", Port = RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Raven"].IPEndpoint.Port, PluginsDirectory = "plugins" }; try { documentDatabase = new DocumentDatabase(config); documentDatabase.SpinBackgroundWorkers(); httpServer = new HttpServer(config, documentDatabase); try { httpServer.StartListening(); } catch (Exception ex) { Trace.WriteLine("StartRaven Error: " + ex.ToString(), "Error"); if (httpServer != null) { httpServer.Dispose(); httpServer = null; } } } catch (Exception ex) { Trace.WriteLine("StartRaven Error: " + ex.ToString(), "Error"); if (documentDatabase != null) { documentDatabase.Dispose(); documentDatabase = null; } }
همون طور که آقای محسن خان گفت، احتمالا هاست شما medium trust هست. اما رو کامپیوتر خودتون full trust برنامه نویسی میکنید.
چون هویت کاربر هنوز مشخص نشده پیغامی مبنی بر این لاگ میشه که اسمبلی mscorlib وجود نداره. در واقع وجود داره ولی نه برای کاربر anonymous ! همچنین این به دلیل medium trust بودن هم میتونه باشه. برای حل این مشکل کارهای زیر رو انجام بدین:
1) به فایل web.config برین و کد زیر رو اضافه کنید:
<trust level="Full" originUrl=".*" />
2) باید تغییری رو در متدهای الحاقی Encrypt و Decrypt بدین، که از این متدها برای رمزنگاری و رمزگشایی محتوای کوکی تصویر امنیتی استفاده میشه. قبل از هر کدوم از این متدها flag زیر رو اضافه کنید:
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Assert, Unrestricted = true)]
همچنین، یک خط داخل بدنه هر کدوم از متدهای الحاقی Encrypt و Decrypt هست، منظورم این خط کد هست:
var cspp = new CspParameters { KeyContainerName = key };
var cspp = new CspParameters { KeyContainerName = key, Flags = CspProviderFlags.UseMachineKeyStore };