مسیرراه‌ها
ASP.NET MVC
              نظرات مطالب
              MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel
              آقای نصیری به عنوان کسب تجربه سوالی داشتم :
              زمانی که در آموزش های iTextSharp خودتون به این مسئله که مشغول تهیه ی گذارش ساز هستید اشاره کردید من هم تصمیم گرفتم کمی با iTextSharp برای چاپ گذارش ها کار کنم.(با توجه به مشکلاتی که با ابزار های آماده داشتم) که انصافا خیلی راضی هستم و از شما متشکرم.
              حالا می خوام بدونم آیا به نظر شما درست هست نتیجه ی زحمت رو به صورت سورس باز در اینترنت قرار داد ؟  و گروهی از اون منفعت مالی ببرن و فقط استفاده کننده باشند.

              مثلا همین پروژه های کد باز شما چند نفر به غیر از خود شما روی توسعه آن وقت گذاشتن ؟
              در شرکت ما (و احتمالا خیلی شرکت ها) بسیار پیش آمده که مدیر پروژه یا برنامه نویس نتیجه ی زحمت صاحب یک وبلاگ رو به اسم خودش تمام می کنه (نمونش jQueyr User control loader شما یا خیلی نمونه های دیگه)
              خیلی ممنون از شما.
              نظرات نظرسنجی‌ها
              آیا با وجود سی‌ام‌اس فروشگاهی قدرتمندی مثل nopCommerce یا SmartStore آیا منطقی است که ما دوباره خودمان از صفر کد بزنیم؟
              با این که کار من نوشتن از صفر است و اگر قرار باشد چیزی از صفر نوشته نشود من هم در آن پروژه نخواهم بود، اما به طور کلی با نوشتن از صفر میانه خوبی ندارم. ترجیح می‌دهم گزینه نوشتن از صفر را به عنوان آخرین گزینه بررسی کنم. نوشتن از صفر بیشتر مناسب پروژه هایی است که مشابه شان وجود نداشته باشد. در کاربردی مثل فروشگاه اینترنتی که خیلی عام به نظر می‌رسد ترجیحم این است که از یک سورس موجود استفاده کنم.
              استفاده مجدد از پروژه‌های موجود که تعداد زیادی نصب از آن زیر بار است ارزان‌تر و سریع‌تر از «نوشتن از صفر» به نظر می‌رسد. خیلی از اوقات نوشتن از صفر به معنای اتلاف منابع است.
              مطالب
              راهنمای تغییر بخش احراز هویت و اعتبارسنجی کاربران سیستم مدیریت محتوای IRIS به ASP.NET Identity – بخش سوم
              تغییر الگوریتم پیش فرض هش کردن کلمه‌های عبور ASP.NET Identity

              کلمه‌های عبور کاربران فعلی سیستم با الگوریتمی متفاوت از الگوریتم مورد استفاده Identity هش شده‌اند. برای اینکه کاربرانی که قبلا ثبت نام کرده بودند بتوانند با کلمه‌های عبور خود وارد سایت شوند، باید الگوریتم هش کردن Identity را با الگوریتم فعلی مورد استفاده Iris جایگزین کرد.

              برای تغییر روش هش کردن کلمات عبور در Identity باید اینترفیس IPasswordHasher را پیاده سازی کنید:
                  public class IrisPasswordHasher : IPasswordHasher
                  {
                      public string HashPassword(string password)
                      {
                          return Utilities.Security.Encryption.EncryptingPassword(password);
                      }
              
                      public PasswordVerificationResult VerifyHashedPassword(string hashedPassword, string providedPassword)
                      {
                          return Utilities.Security.Encryption.VerifyPassword(providedPassword, hashedPassword) ?
                                                                              PasswordVerificationResult.Success :
                                                                              PasswordVerificationResult.Failed;
                      }
                  }

                سپس باید وارد کلاس ApplicationUserManager شده و در سازنده‌ی آن اینترفیس IPasswordHasher را به عنوان وابستگی تعریف کنید:
              public ApplicationUserManager(IUserStore<ApplicationUser, int> store,
                          IUnitOfWork uow,
                          IIdentity identity,
                          IApplicationRoleManager roleManager,
                          IDataProtectionProvider dataProtectionProvider,
                          IIdentityMessageService smsService,
                          IIdentityMessageService emailService, IPasswordHasher passwordHasher)
                          : base(store)
                      {
                          _store = store;
                          _uow = uow;
                          _identity = identity;
                          _users = _uow.Set<ApplicationUser>();
                          _roleManager = roleManager;
                          _dataProtectionProvider = dataProtectionProvider;
                          this.SmsService = smsService;
                          this.EmailService = emailService;
                          PasswordHasher = passwordHasher;
                          createApplicationUserManager();
                      }

              برای اینکه کلاس IrisPasswordHasher را به عنوان نمونه درخواستی IPasswordHasher معرفی کنیم، باید در تنظیمات StructureMap کد زیر را نیز اضافه کنید:
              x.For<IPasswordHasher>().Use<IrisPasswordHasher>();

              پیاده سازی اکشن متد ثبت نام کاربر با استفاده از Identity

              در کنترلر UserController، اکشن متد Register را به شکل زیر بازنویسی کنید:
                      [HttpPost]
                      [ValidateAntiForgeryToken]
                      [CaptchaVerify("تصویر امنیتی وارد شده معتبر نیست")]
                      public virtual async Task<ActionResult> Register(RegisterModel model)
                      {
                          if (ModelState.IsValid)
                          {
                              var user = new ApplicationUser
                              {
                                  CreatedDate = DateAndTime.GetDateTime(),
                                  Email = model.Email,
                                  IP = Request.ServerVariables["REMOTE_ADDR"],
                                  IsBaned = false,
                                  UserName = model.UserName,
                                  UserMetaData = new UserMetaData(),
                                  LastLoginDate = DateAndTime.GetDateTime()
                              };
              
                              var result = await _userManager.CreateAsync(user, model.Password);
              
                              if (result.Succeeded)
                              {
                                  var addToRoleResult = await _userManager.AddToRoleAsync(user.Id, "user");
                                  if (addToRoleResult.Succeeded)
                                  {
                                      var code = await _userManager.GenerateEmailConfirmationTokenAsync(user.Id);
                                      var callbackUrl = Url.Action("ConfirmEmail", "User",
                                          new { userId = user.Id, code }, protocol: Request.Url.Scheme);
              
                                      _emailService.SendAccountConfirmationEmail(user.Email, callbackUrl);
              
                                      return Json(new { result = "success" });
                                  }
              
                                  addErrors(addToRoleResult);
                              }
              
                              addErrors(result);
                          }
              
                          return PartialView(MVC.User.Views._Register, model);
                      }
              نکته: در اینجا برای ارسال لینک فعال سازی حساب کاربری، از کلاس EmailService خود سیستم IRIS استفاده شده است؛ نه EmailService مربوط به ASP.NET Identity. همچنین در ادامه نیز از EmailService مربوط به خود سیستم Iris استفاده شده است.

              برای این کار متد زیر را به کلاس EmailService  اضافه کنید: 
                      public SendingMailResult SendAccountConfirmationEmail(string email, string link)
                      {
                          var model = new ConfirmEmailModel()
                          {
                              ActivationLink = link
                          };
              
                          var htmlText = _viewConvertor.RenderRazorViewToString(MVC.EmailTemplates.Views._ConfirmEmail, model);
              
                          var result = Send(new MailDocument
                          {
                              Body = htmlText,
                              Subject = "تایید حساب کاربری",
                              ToEmail = email
                          });
              
                          return result;
                      }
              همچنین قالب ایمیل تایید حساب کاربری را در مسیر Views/EmailTemplates/_ConfirmEmail.cshtml با محتویات زیر ایجاد کنید:
              @model Iris.Model.EmailModel.ConfirmEmailModel
              
              <div style="direction: rtl; -ms-word-wrap: break-word; word-wrap: break-word;">
                  <p>با سلام</p>
                  <p>برای فعال سازی حساب کاربری خود لطفا بر روی لینک زیر کلیک کنید:</p>
                  <p>@Model.ActivationLink</p>
                  <div style=" color: #808080;">
                      <p>با تشکر</p>
                      <p>@Model.SiteTitle</p>
                      <p>@Model.SiteDescription</p>
                      <p><span style="direction: ltr !important; unicode-bidi: embed;">@Html.ConvertToPersianDateTime(DateTime.Now, "s,H")</span></p>
                  </div>
              </div>

              اصلاح پیام موفقیت آمیز بودن ثبت نام  کاربر جدید


              سیستم IRIS از ارسال ایمیل تایید حساب کاربری استفاده نمی‌کند و به محض اینکه عملیات ثبت نام تکمیل می‌شد، صفحه رفرش می‌شود. اما در سیستم Identity یک ایمیل حاوی لینک فعال سازی حساب کاربری به او ارسال می‌شود.
              برای اصلاح پیغام پس از ثبت نام، باید به فایل myscript.js درون پوشه‌ی Scripts مراجعه کرده و رویداد onSuccess شیء RegisterUser را به شکل زیراصلاح کنید: 
              RegisterUser.Form.onSuccess = function (data) {
                  if (data.result == "success") {
                      var message = '<div id="alert"><button type="button" data-dismiss="alert">×</button>ایمیلی حاوی لینک فعال سازی، به ایمیل شما ارسال شد؛ لطفا به ایمیل خود مراجعه کرده و بر روی لینک فعال سازی کلیک کنید.</div>';
                      $('#registerResult').html(message);
                  }
                  else {
                      $('#logOnModal').html(data);
                  }
              };
              برای تایید ایمیل کاربری که ثبت نام کرده است نیز اکشن متد زیر را به کلاس UserController اضافه کنید:
                      [AllowAnonymous]
                      public virtual async Task<ActionResult> ConfirmEmail(int? userId, string code)
                      {
                          if (userId == null || code == null)
                          {
                              return View("Error");
                          }
                          var result = await _userManager.ConfirmEmailAsync(userId.Value, code);
                          return View(result.Succeeded ? "ConfirmEmail" : "Error");
                      }
              این اکشن متد نیز احتیاج به View دارد؛ پس view متناظر آن را با محتویات زیر اضافه کنید:
              @{
                  ViewBag.Title = "حساب کاربری شما تایید شد";
              }
              <h2>@ViewBag.Title.</h2>
              <div>
                  <p>
                      با تشکر از شما، حساب کاربری شما تایید شد.
                  </p>
                  <p>
                      @Ajax.ActionLink("ورود / ثبت نام", MVC.User.ActionNames.LogOn, MVC.User.Name, new { area = "", returnUrl = Html.ReturnUrl(Context, Url) }, new AjaxOptions { HttpMethod = "GET", InsertionMode = InsertionMode.Replace, UpdateTargetId = "logOnModal", LoadingElementDuration = 300, LoadingElementId = "loadingMessage", OnSuccess = "LogOnForm.onSuccess" }, new { role = "button", data_toggle = "modal", data_i_logon_link = "true", rel = "nofollow" })
                  </p>
              </div>

              اصلاح اکشن متد ورود به سایت 

                      [HttpPost]
                      [ValidateAntiForgeryToken]
                      public async virtual Task<ActionResult> LogOn(LogOnModel model, string returnUrl)
                      {
                          if (!ModelState.IsValid)
                          {
                              if (Request.IsAjaxRequest())
                                  return PartialView(MVC.User.Views._LogOn, model);
                              return View(model);
                          }
              
              
                          const string emailRegPattern =
                              @"^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
              
                          string ip = Request.ServerVariables["REMOTE_ADDR"];
              
                          SignInStatus result = SignInStatus.Failure;
              
                          if (Regex.IsMatch(model.Identity, emailRegPattern))
                          {
              
                              var user = await _userManager.FindByEmailAsync(model.Identity);
              
                              if (user != null)
                              {
                                  result = await _signInManager.PasswordSignInAsync
                                 (user.UserName,
                                 model.Password, model.RememberMe, shouldLockout: true);
                              }
                          }
                          else
                          {
                              result = await _signInManager.PasswordSignInAsync(model.Identity, model.Password, model.RememberMe, shouldLockout: true);
                          }
              
              
                          switch (result)
                          {
                              case SignInStatus.Success:
                                  if (Request.IsAjaxRequest())
                                      return JavaScript(IsValidReturnUrl(returnUrl)
                                          ? string.Format("window.location ='{0}';", returnUrl)
                                          : "window.location.reload();");
                                  return redirectToLocal(returnUrl);
              
                              case SignInStatus.LockedOut:
                                  ModelState.AddModelError("",
                                      string.Format("حساب شما قفل شد، لطفا بعد از {0} دقیقه دوباره امتحان کنید.",
                                          _userManager.DefaultAccountLockoutTimeSpan.Minutes));
                                  break;
                              case SignInStatus.Failure:
                                  ModelState.AddModelError("", "نام کاربری یا کلمه عبور اشتباه است.");
                                  break;
                              default:
                                  ModelState.AddModelError("", "در ورود شما خطایی رخ داده است.");
                                  break;
                          }
              
              
                          if (Request.IsAjaxRequest())
                              return PartialView(MVC.User.Views._LogOn, model);
                          return View(model);
                      }


              اصلاح اکشن متد خروج کاربر از سایت

                      [HttpPost]
                      [ValidateAntiForgeryToken]
                      [Authorize]
                      public virtual ActionResult LogOut()
                      {
                          _authenticationManager.SignOut();
              
                          if (Request.IsAjaxRequest())
                              return Json(new { result = "true" });
              
                          return RedirectToAction(MVC.User.ActionNames.LogOn, MVC.User.Name);
                      }

              پیاده سازی ریست کردن کلمه‌ی عبور با استفاده از ASP.NET Identity

              مکانیزم سیستم IRIS برای ریست کردن کلمه‌ی عبور به هنگام فراموشی آن، ساخت GUID و ذخیره‌ی آن در دیتابیس است. سیستم Identity  با استفاده از یک توکن رمز نگاری شده و بدون استفاده از دیتابیس، این کار را انجام می‌دهد و با استفاده از قابلیت‌های تو کار سیستم Identity، تمهیدات امنیتی بهتری را نسبت به سیستم کنونی در نظر گرفته است.

              برای این کار کدهای کنترلر ForgottenPasswordController را به شکل زیر ویرایش کنید:
              using System.Threading.Tasks;
              using System.Web.Mvc;
              using CaptchaMvc.Attributes;
              using Iris.Model;
              using Iris.Servicelayer.Interfaces;
              using Iris.Web.Email;
              using Microsoft.AspNet.Identity;
              
              namespace Iris.Web.Controllers
              {
                  public partial class ForgottenPasswordController : Controller
                  {
                      private readonly IEmailService _emailService;
                      private readonly IApplicationUserManager _userManager;
              
                      public ForgottenPasswordController(IEmailService emailService, IApplicationUserManager applicationUserManager)
                      {
                          _emailService = emailService;
                          _userManager = applicationUserManager;
                      }
              
                      [HttpGet]
                      public virtual ActionResult Index()
                      {
                          return PartialView(MVC.ForgottenPassword.Views._Index);
                      }
              
                      [HttpPost]
                      [ValidateAntiForgeryToken]
                      [CaptchaVerify("تصویر امنیتی وارد شده معتبر نیست")]
                      public async virtual Task<ActionResult> Index(ForgottenPasswordModel model)
                      {
                          if (!ModelState.IsValid)
                          {
                              return PartialView(MVC.ForgottenPassword.Views._Index, model);
                          }
              
                          var user = await _userManager.FindByEmailAsync(model.Email);
                          if (user == null || !(await _userManager.IsEmailConfirmedAsync(user.Id)))
                          {
                              // Don't reveal that the user does not exist or is not confirmed
                              return Json(new
                              {
                                  result = "false",
                                  message = "این ایمیل در سیستم ثبت نشده است"
                              });
                          }
              
                          var code = await _userManager.GeneratePasswordResetTokenAsync(user.Id);
              
                          _emailService.SendResetPasswordConfirmationEmail(user.UserName, user.Email, code);
              
                          return Json(new
                          {
                              result = "true",
                              message = "ایمیلی برای تایید بازنشانی کلمه عبور برای شما ارسال شد.اعتبارایمیل ارسالی 3 ساعت است."
                          });
                      }
              
                      [AllowAnonymous]
                      public virtual ActionResult ResetPassword(string code)
                      {
                          return code == null ? View("Error") : View();
                      }
              
              
                      [AllowAnonymous]
                      public virtual ActionResult ResetPasswordConfirmation()
                      {
                          return View();
                      }
              
                      //
                      // POST: /Account/ResetPassword
                      [HttpPost]
                      [AllowAnonymous]
                      [ValidateAntiForgeryToken]
                      public virtual async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
                      {
                          if (!ModelState.IsValid)
                          {
                              return View(model);
                          }
                          var user = await _userManager.FindByEmailAsync(model.Email);
                          if (user == null)
                          {
                              // Don't reveal that the user does not exist
                              return RedirectToAction("Error");
                          }
                          var result = await _userManager.ResetPasswordAsync(user.Id, model.Code, model.Password);
                          if (result.Succeeded)
                          {
                              return RedirectToAction("ResetPasswordConfirmation", "ForgottenPassword");
                          }
                          addErrors(result);
                          return View();
                      }
              
                      private void addErrors(IdentityResult result)
                      {
                          foreach (var error in result.Errors)
                          {
                              ModelState.AddModelError("", error);
                          }
                      }
              
                  }
              }

              همچنین برای اکشن متدهای اضافه شده، View‌های زیر را نیز باید اضافه کنید:

              - View  با نام  ResetPasswordConfirmation.cshtml را اضافه کنید.
              @{
                  ViewBag.Title = "کلمه عبور شما تغییر کرد";
              }
              
              <hgroup>
                  <h1>@ViewBag.Title.</h1>
              </hgroup>
              <div>
                  <p>
                      کلمه عبور شما با موفقیت تغییر کرد
                  </p>
                  <p>
                      @Ajax.ActionLink("ورود / ثبت نام", MVC.User.ActionNames.LogOn, MVC.User.Name, new { area = "", returnUrl = Html.ReturnUrl(Context, Url) }, new AjaxOptions { HttpMethod = "GET", InsertionMode = InsertionMode.Replace, UpdateTargetId = "logOnModal", LoadingElementDuration = 300, LoadingElementId = "loadingMessage", OnSuccess = "LogOnForm.onSuccess" }, new { role = "button", data_toggle = "modal", data_i_logon_link = "true", rel = "nofollow" })
                  </p>
              </div>

              - View با نام ResetPassword.cshtml
              @model Iris.Model.ResetPasswordViewModel
              @{
                  ViewBag.Title = "ریست کردن کلمه عبور";
              }
              <h2>@ViewBag.Title.</h2>
              @using (Html.BeginForm("ResetPassword", "ForgottenPassword", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
              {
                  @Html.AntiForgeryToken()
                  <h4>ریست کردن کلمه عبور</h4>
                  <hr />
                  @Html.ValidationSummary("", new { @class = "text-danger" })
                  @Html.HiddenFor(model => model.Code)
                  <div>
                      @Html.LabelFor(m => m.Email, "ایمیل", new { @class = "control-label" })
                      <div>
                          @Html.TextBoxFor(m => m.Email)
                      </div>
                  </div>
                  <div>
                      @Html.LabelFor(m => m.Password, "کلمه عبور", new { @class = "control-label" })
                      <div>
                          @Html.PasswordFor(m => m.Password)
                      </div>
                  </div>
                  <div>
                      @Html.LabelFor(m => m.ConfirmPassword, "تکرار کلمه عبور", new { @class = "control-label" })
                      <div>
                          @Html.PasswordFor(m => m.ConfirmPassword)
                      </div>
                  </div>
                  <div>
                      <div>
                          <input type="submit" value="تغییر کلمه عبور" />
                      </div>
                  </div>
              }

              همچنین این View و Controller متناظر آن، احتیاج به ViewModel زیر دارند که آن را به پروژه‌ی Iris.Models اضافه کنید.
              using System.ComponentModel.DataAnnotations;
              namespace Iris.Model
              {
                  public class ResetPasswordViewModel
                  {
                      [Required]
                      [EmailAddress]
                      [Display(Name = "ایمیل")]
                      public string Email { get; set; }
              
                      [Required]
                      [StringLength(100, ErrorMessage = "کلمه عبور باید حداقل 6 حرف باشد", MinimumLength = 6)]
                      [DataType(DataType.Password)]
                      [Display(Name = "کلمه عبور")]
                      public string Password { get; set; }
              
                      [DataType(DataType.Password)]
                      [Display(Name = "تکرار کلمه عبور")]
                      [Compare("Password", ErrorMessage = "کلمه عبور و تکرارش یکسان نیستند")]
                      public string ConfirmPassword { get; set; }
              
                      public string Code { get; set; }
                  }
              }

              حذف سیستم قدیمی احراز هویت

              برای حذف کامل سیستم احراز هویت IRIS، وارد فایل Global.asax.cs شده و سپس از متد Application_AuthenticateRequest کدهای زیر را حذف کنید:

              var principalService = ObjectFactory.GetInstance<IPrincipalService>();
              var formsAuthenticationService = ObjectFactory.GetInstance<IFormsAuthenticationService>();
              context.User = principalService.GetCurrent()

              فارسی کردن خطاهای ASP.NET Identity

              سیستم Identity، پیام‌های خطا‌ها را از فایل Resource موجود در هسته‌ی خود، که به طور پیش فرض، زبان آن انگلیسی است، می‌خواند. برای مثال وقتی ایمیلی تکراری باشد، پیامی به زبان انگلیسی دریافت خواهید کرد و متاسفانه برای تغییر آن، راه سر راست و واضحی وجود ندارد. برای تغییر این پیام‌ها می‌توان از سورس باز بودن Identity استفاده کنید و قسمتی را که پیام‌ها را تولید می‌کند، خودتان با پیام‌های فارسی باز نویسی کنید.

              راه اول این است که از این پروژه استفاده کرد و کلاس‌های زیر را به پروژه اضافه کنید:

                  public class CustomUserValidator<TUser, TKey> : IIdentityValidator<ApplicationUser>
                      where TUser : class, IUser<int>
                      where TKey : IEquatable<int>
                  {
              
                      public bool AllowOnlyAlphanumericUserNames { get; set; }
                      public bool RequireUniqueEmail { get; set; }
              
                      private ApplicationUserManager Manager { get; set; }
                      public CustomUserValidator(ApplicationUserManager manager)
                      {
                          if (manager == null)
                              throw new ArgumentNullException("manager");
                          AllowOnlyAlphanumericUserNames = true;
                          Manager = manager;
                      }
                      public virtual async Task<IdentityResult> ValidateAsync(ApplicationUser item)
                      {
                          if (item == null)
                              throw new ArgumentNullException("item");
                          var errors = new List<string>();
                          await ValidateUserName(item, errors);
                          if (RequireUniqueEmail)
                              await ValidateEmailAsync(item, errors);
                          return errors.Count <= 0 ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());
                      }
              
                      private async Task ValidateUserName(ApplicationUser user, ICollection<string> errors)
                      {
                          if (string.IsNullOrWhiteSpace(user.UserName))
                              errors.Add("نام کاربری نباید خالی باشد");
                          else if (AllowOnlyAlphanumericUserNames && !Regex.IsMatch(user.UserName, "^[A-Za-z0-9@_\\.]+$"))
                          {
                              errors.Add("برای نام کاربری فقط از کاراکتر‌های مجاز استفاده کنید ");
                          }
                          else
                          {
                              var owner = await Manager.FindByNameAsync(user.UserName);
                              if (owner != null && !EqualityComparer<int>.Default.Equals(owner.Id, user.Id))
                                  errors.Add("این نام کاربری قبلا ثبت شده است");
                          }
                      }
              
                      private async Task ValidateEmailAsync(ApplicationUser user, ICollection<string> errors)
                      {
                          var email = await Manager.GetEmailStore().GetEmailAsync(user).WithCurrentCulture();
                          if (string.IsNullOrWhiteSpace(email))
                          {
                              errors.Add("وارد کردن ایمیل ضروریست");
                          }
                          else
                          {
                              try
                              {
                                  var m = new MailAddress(email);
              
                              }
                              catch (FormatException)
                              {
                                  errors.Add("ایمیل را به شکل صحیح وارد کنید");
                                  return;
                              }
                              var owner = await Manager.FindByEmailAsync(email);
                              if (owner != null && !EqualityComparer<int>.Default.Equals(owner.Id, user.Id))
                                  errors.Add("این ایمیل قبلا ثبت شده است");
                          }
                      }
                  }

                  public class CustomPasswordValidator : IIdentityValidator<string>
                  {
                      #region Properties
                      public int RequiredLength { get; set; }
                      public bool RequireNonLetterOrDigit { get; set; }
                      public bool RequireLowercase { get; set; }
                      public bool RequireUppercase { get; set; }
                      public bool RequireDigit { get; set; }
                      #endregion
              
                      #region IIdentityValidator
                      public virtual Task<IdentityResult> ValidateAsync(string item)
                      {
                          if (item == null)
                              throw new ArgumentNullException("item");
                          var list = new List<string>();
              
                          if (string.IsNullOrWhiteSpace(item) || item.Length < RequiredLength)
                              list.Add(string.Format("کلمه عبور نباید کمتر از 6 کاراکتر باشد"));
              
                          if (RequireNonLetterOrDigit && item.All(IsLetterOrDigit))
                              list.Add("برای امنیت بیشتر از حداقل از یک کارکتر غیر عددی و غیر حرف  برای کلمه عبور استفاده کنید");
              
                          if (RequireDigit && item.All(c => !IsDigit(c)))
                              list.Add("برای امنیت بیشتر از اعداد هم در کلمه عبور استفاده کنید");
                          if (RequireLowercase && item.All(c => !IsLower(c)))
                              list.Add("از حروف کوچک نیز برای کلمه عبور استفاده کنید");
                          if (RequireUppercase && item.All(c => !IsUpper(c)))
                              list.Add("از حروف بزرک نیز برای کلمه عبور استفاده کنید");
                          return Task.FromResult(list.Count == 0 ? IdentityResult.Success : IdentityResult.Failed(string.Join(" ", list)));
                      }
              
                      #endregion
              
                      #region PrivateMethods
                      public virtual bool IsDigit(char c)
                      {
                          if (c >= 48)
                              return c <= 57;
                          return false;
                      }
              
                      public virtual bool IsLower(char c)
                      {
                          if (c >= 97)
                              return c <= 122;
                          return false;
                      }
              
              
                      public virtual bool IsUpper(char c)
                      {
                          if (c >= 65)
                              return c <= 90;
                          return false;
                      }
              
                      public virtual bool IsLetterOrDigit(char c)
                      {
                          if (!IsUpper(c) && !IsLower(c))
                              return IsDigit(c);
                          return true;
                      }
                      #endregion
              
                  }

              سپس باید کلاس‌های فوق را به Identity معرفی کنید تا از این کلاس‌های سفارشی شده به جای کلاس‌های پیش فرض خودش استفاده کند. برای این کار وارد کلاس ApplicationUserManager شده و درون متد createApplicationUserManager کدهای زیر را اضافه کنید: 
                          UserValidator = new CustomUserValidator< ApplicationUser, int>(this)
                          {
                              AllowOnlyAlphanumericUserNames = false,
                              RequireUniqueEmail = true
                          };
              
                          PasswordValidator = new CustomPasswordValidator
                          {
                              RequiredLength = 6,
                              RequireNonLetterOrDigit = false,
                              RequireDigit = false,
                              RequireLowercase = false,
                              RequireUppercase = false
                          };
              روش دیگر مراجعه به سورس ASP.NET Identity است. با مراجعه به مخزن کد آن، فایل Resources.resx آن را که حاوی متن‌های خطا به زبان انگلیسی است، درون پروژه‌ی خود کپی کنید. همچین کلاس‌های UserValidator و PasswordValidator را نیز درون پروژه کپی کنید تا این کلاس‌ها از فایل Resource موجود در پروژه‌ی خودتان استفاده کنند. در نهایت همانند روش قبلی درون متد createApplicationUserManager کلاس ApplicationUserManager، کلاس‌های UserValidator و PasswordValidator را به Identity معرفی کنید.


              ایجاد SecurityStamp برای کاربران فعلی سایت

              سیستم Identity برای لحاظ کردن یک سری موارد امنیتی، به ازای هر کاربر، فیلدی را به نام SecurityStamp درون دیتابیس ذخیره می‌کند و برای این که این سیستم عملکرد صحیحی داشته باشد، باید این مقدار را برای کاربران فعلی سایت ایجاد کرد تا کاربران فعلی بتوانند از امکانات Identity نظیر فراموشی کلمه عبور، ورود به سیستم و ... استفاده کنند.
              برای این کار Identity، متدی به نام UpdateSecurityStamp را در اختیار قرار می‌دهد تا با استفاده از آن بتوان مقدار فیلد SecurityStamp را به روز رسانی کرد.
              معمولا برای انجام این کارها می‌توانید یک کنترلر تعریف کنید و درون اکشن متد آن کلیه‌ی کاربران را واکشی کرده و سپس متد UpdateSecurityStamp را بر روی آن‌ها فراخوانی کنید.
                      public virtual async Task<ActionResult> UpdateAllUsersSecurityStamp()
                      {
                          foreach (var user in await _userManager.GetAllUsersAsync())
                          {
                              await _userManager.UpdateSecurityStampAsync(user.Id);
                          }
                          return Content("ok");
                      }
              البته این روش برای تعداد زیاد کاربران کمی زمان بر است.


              انتقال نقش‌های کاربران به جدول جدید و برقراری رابطه بین آن‌ها

              در سیستم Iris رابطه‌ی بین کاربران و نقش‌ها یک به چند بود. در سیستم Identity این رابطه چند به چند است و من به عنوان یک حرکت خوب و رو به جلو، رابطه‌ی چند به چند را در سیستم جدید انتخاب کردم. اکنون با استفاده از دستورات زیر به راحتی می‌توان نقش‌های فعلی و رابطه‌ی بین آن‌ها را به جداول جدیدشان منتقل کرد:
                      public virtual async Task<ActionResult> CopyRoleToNewTable()
                      {
                          var dbContext = new IrisDbContext();
              
                          foreach (var role in await dbContext.Roles.ToListAsync())
                          {
                              await _roleManager.CreateAsync(new CustomRole(role.Name)
                              {
                                  Description = role.Description
                              });
                          }
              
                          var users = await dbContext.Users.Include(u => u.Role).ToListAsync();
              
                          foreach (var user in users)
                          {
                              await _userManager.AddToRoleAsync(user.Id, user.Role.Name);
                          }
                          return Content("ok");
                      }
              البته اجرای این کد نیز برای تعداد زیادی کاربر، زمانبر است؛ ولی روشی مطمئن و دقیق است.
              پاسخ به بازخورد‌های پروژه‌ها
              راه اندازی پروژه
              آیکن ویژوال استودیوی شما شبیه به VS 2013 است؛ بنابراین امکان استفاده از این پروژه را نخواهید داشت چون از قابلیت‌های C# 6.0 استفاده می‌کند که با VS 2015 سازگار است.
              نظرات مطالب
              چک لیست تهیه یک برنامه ASP.NET MVC
              HTTP Module استاندارد ASP.NET است و بر روی کل سایت تاثیر دارد. روش فعال سازی آن در وب فرم‌ها یا MVC تفاوتی نمی‌کند و یکی است.
              مراجعه کنید به سایت اصلی سازنده آن، مثال به همراه وب کانفیگ تنظیم شده دارد؛ یا پروژه IRIS هم از این ماژول استفاده می‌کند.
              مطالب
              بررسی مفاهیم متغیرهای Value Type و Reference Type در سی شارپ
              نوع داده(Data Type) ، متغیر‌ها(Variables) ، انواع مقداری(Value Type) ، انواع ارجاعی(Reference Type)

              مقدمه :
              نوع داده‌ها، اجزای اصلی سازنده‌ی یک زبان برنامه نویسی و شبیه قواعد هر زبانی هستند.
              مفاهیمی که در این مطلب بررسی خواهد شد :
               • Data Type نوع داده
               • Variables  متغیرها
               • Naming Convention قرارداد‌های نامگذاری
               • Value Type/Reference Type انواع مقداری و ارجاعی
               • Stack/heap memory  حافظه پشته و هرم

              نوع داده

              در دنیای واقعی، برای نگهداری مواد مختلف، ظروف مختلفی با اندازه‌های مختلفی طراحی شده است. در دنیای برنامه نویسی، به تناسب اطلاعاتی که می‌خواهیم در حافظه ذخیره کنیم، باید نوع ظرف ذخیره سازی را انتخاب کنیم. نوع ظرف ذخیره سازی را در دنیای برنامه نویسی، نوع داده‌ها مشخص می‌کنند.
              در دات نت، همه‌ی نوع داده‌ها (Data Type) بصورت مستقیم و یا غیر مستقیم، از کلاس System.Object مشتق شده‌اند.


              متغیرها

              متغیر‌ها برای ذخیره‌ی مقادیر (اطلاعات)، استفاده می‌شوند. به این مثال دقت کنید: ما یک کیف داریم که در آن یک کتاب قرار دارد. در اینجا کیف نقش متغیر و کتاب نقش مقدار (value) را ایفا می‌کند. اندازه‌ی کیف همان نوع داده (Data Type) در دنیای برنامه نویسی می‌باشد.


              چک کردن سایز نوع داده (Data Type)

              ما نیازی به حفظ کردن اندازه‌ی نوع داده‌ها نداریم. در سی شارپ متدی به نام () sizeof مهیا شده است که با چک کردن نوع داده، اندازه‌ی آن را بر حسب بایت نمایش می‌دهد.
              به مثال زیر دقت کنید:
              Console.WriteLine(sizeof(int));
              Console.WriteLine(sizeof(char));
              Console.WriteLine(sizeof(bool));
              Console.WriteLine(sizeof(decimal));
              Console.WriteLine(sizeof(float));
              خروجی کد‌های بالا :
               4
              2
              1
              16
              4

              نکته : متد sizeof فقط برای نمایش اندازه‌ی نوع داده‌های مقداری (value type) می‌تواند مورد استفاده قرار گیرد.


              چک کردن نوع داده

              ما می‌توانیم نوع داده‌ها را برای بدست آوردن کلاسی که به آن تعلق دارند، چک کنیم.
              مثال :
               int a = 23;
              float b = 3.14f;
              Console.WriteLine(a.GetType());
              Console.WriteLine(b.GetType());
              خروجی کد‌های بالا : 
              System.Int32
              System.Single

              چک کردن نوع داده‌ی دو شیء

              فرض کنید 2 شیء را با نام‌های obj1 و obj2 داریم که هر دو از نوع long هستند. برای اینکه این مقایسه را انجام دهیم، از متد Object.RefrenceEqual می‌توان استفاده کرد.
              مثال :
              long obj1 = 356;
              long obj2 = 54;
              float obj3 = 234;
              Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj2.GetType()));
              Console.WriteLine(object.ReferenceEquals(obj1.GetType(), obj3.GetType()));
              خروجی کد‌های بالا : 
              True
              False

              تعریف یک متغیر ومقدار دهی به آن
              سی شارپ یک زبان strongly typed است (البته با در نظر نگرفتن نوع dynamic آن). به این معنا که کلیه‌ی متغیر‌ها، قبل از استفاده باید تعریف و مقدار دهی شوند و بعد از تعریف متغیر، نمی‌توان نوع آن را تغییر داد. رفتار یک متغیر بر اساس نوع انتخابی ما مشخص می‌شود. بطور مثال با انتخاب نوع int تنها می‌توان اعداد صحیح را ذخیره و نگهداری کرد و برای تغییر رفتار متغیر‌ها باید آنها را تبدیل کنیم.

              تعریف یک متغیر
              برای استفاده از یک متغیر ابتداباید آن را تعریف کنیم :
              //<data type> <variable name>;
              Int a;

              مقداردهی اولیه یک متغیر

              مقدار دهی اولیه‌ی یک متغیر با استفاده از عملگر = و نوشتن مقدار مورد نظر برای ذخیره کردن در متغیر، در سمت راست عملگر اتفاق خواهد افتاد.
              //<data type> <variable name>=value;
              Int a=23;
              Int a;//declare تعریف
              a=23;//مقدار دهی اولیه initializing
              Int a=23;//تعریف و مقدار دهی در یک خط
              Int a,b,c=23;//تعریف چند متغیر و مقدار دهی در یک خط


              قرار دا‌دهای نام گذاری متغیر‌ها :

              در دنیای برنامه نویسی دو نوع قرار داد نام گذاری بسیار متداول وجود دارند:
               1-  camelCase : در این قرار داد، حرف اول کلمه‌ی اول، بصورت کوچک و حرف اول از کلمه‌ی دوم، بصورت بزرگ نوشته خواهد شد. برای مثال: firstName,lastName
               2- PascalCase : در این قرار داد حروف ابتدایی دو کلمه‌ی مجاور، بصورت بزرگ نوشته خواهند شد: FirstName,LastName

              چند نکته :
               • نامگذاری متغیر‌ها را می‌توانید با علامت _ و یا @ شروع کنید.
               • کلمات کلیدی (key word) سی شارپ نمی‌توانند به عنوان نام متغیر مورد استفاده قرار بگیرند (مگر آنکه با @ شروع شوند).
               • در بین نام متغیر نباید فضای خالی وجود داشته باشد. کاراکتر‌های سازنده‌ی متغیر می‌توانند اعداد، حروف و زیر خط باشند.
              لیستی از نام گذاری‌های مجاز:
               int abc;
              long _abcd;
              float @abcd;
              bool main_button;
              decimal piValue;
              string firstName;
              string first_name;
              bool button55_on;
              لیستی از نام گذاری‌های غیر مجاز
              long _a.5bc5d;
              float @ab cd;
              decimal pi@Value;
              //استفاده از کلمات کلیدی سی شارپ که کامپایلر آنها را مجاز نمی‌داند
              bool class;
              string namespace;
              string string;
              int static;
              برای مطالعه‌ی کاملتر کلمات کلیدی سی شارپ می‌توانید اینجا را مطالعه کنید.


              در ادامه کمی در مورد نوع داده‌ها بحث خواهیم کرد.
              در سی شارپ دو مدل نوع داده وجود دارد:
               • انواع مقداری Value Type
               • انواع ارجاعی یا اشاره‌ای Reference Type

              انواع مقداری (Value Type) :
               • انواع مقداری مستقیما حاوی داده‌ها هستند. اگر یک متغیر از نوع مقداری را به یک متغیر دیگر تخصیص دهید، مقدار آنها مستقیما کپی می‌شوند؛ برعکس نوع‌های اشاره‌ای که با نخصیص یک متغیر به یک متغیر دیگر، تنها اشاره‌گر به مقدار شیء کپی خواهد شد و نه خود شیء.
               • کلیه نوع‌های مقداری از کلاس ValueType مشتق شده‌اند.
               • در فضای stack  به آنها حافظه تخصیص داده می‌شود.
               • نمی‌توانند مقدار null  بپذیرند. البته با قابلیت nullabletype امکان تخصیص مقدار null به نوع داده‌های مقداری نیز مهیا شده است.
               • همه نوع‌های داده‌های مقداری، یک سازنده پیش فرض دارند که به صورت ضمنی کار مقدار دهی اولیه برای آنها را انجام می‌دهد. برای مطالعه بیشتر درباره مقادیر پیش فرض به اینجا مراجعه کنید.

              انواع مقداری به دو دسته‌ی اصلی تقسیم می‌شود :
               • Structs
               • Enumerations

              طبقه بندی Structs به صورت زیر است :
               • Numeric Type
              * Integral Type : sbyte,short,ushort,int,uint,long,ulong,char
              * Floating-Point Types : float,double
              * Decimal : decimal
               •  Bool دو مقدار true و false
               • User Defined Struct


              نوع داده نال (تهی) پذیر (nullable Type) و چگونگی تعریف آن

              در ابتدای معرفی نوع داده‌های مقداری گفتیم همیشه باید وضعیت متغیر مشخص و مقدار دهی اولیه‌ی آن یا به صورت ضمنی و یا آشکار انجام شود. هیچ یک از نوع داده‌های مقداری نمی‌توانند بصورت null تعریف شوند. برای تبدیل یک نوع داده مقداری به صورتی که قابلیت ذخیره‌ی مقدار null را داشته باشد، بعد از نوشتن نوع داده، علامت سوال ؟ قرار می‌دهیم.
               < data type >? < variable name >= null; //syntax

              int? a = null; //assigning null
              int? b = 55; //assigning null and a value
              var? c = 55 //it will give error

              نکته :  var نمی‌تواند بصورت nullable تعریف شود.

              برای چک کردن مقدار در انواع تهی پذیر (nullable) دو خصوصیت وجود دارد:
               • HasValue
              اگر مقداری در متغیر وجود داشته باشد ارزش true  بازگردانده می‌شود؛ در غیر اینصورت ارزش false
               • Value
              مقدار واقعی متغیر را باز می‌گرداند.

              مثال :
               int? a = null;
              int? b = 22;
              Console.WriteLine(a.HasValue);
              //------------
              Console.WriteLine(b.HasValue);
              Console.WriteLine(b.Value);
              خروجی کد بالا :
               False
              True
              22

              انواع ارجاعی Reference Type

              انواع ارجاعی مستقیما حاوی اطلاعات نیستند و ارجاعی هستند به آدرسی از حافظه که حاوی اطلاعات واقعی است. به بیانی دیگر، اشاره‌گری به آدرسی از حافظه هستند.
               • انواع ارجاعی بصورت غیر مستقیم حاوی داده‌ها هستند.
               • در بخشی از حافظه که به آن heap می‌گوییم، به آنها فضا اختصاص داده می‌شود.
               • می‌توانند بصورت null (بدون مقدار) باشند.

              انواع ارجاعی نیز به دو دسته‌ی کلی تقسیم می‌شوند :

               • انواع از پیش تعریف شده
                Object,string,dynamic
               • انواع تعریف شده توسط کاربر
                      class,interface,delegate

              نکته : آدرس مکانی از حافظه که داده‌ها در آن قرار دارند، در بخش پشته یا Stack ذخیره می‌شود و داد‌ه‌ها در فضای heap ذخیره می‌شوند.
              مثال :
               test obj; //allocating reference on stack
              obj= new test(55);//allocating object on heap

              نکته : دو متغیر از نوع ارجاعی می‌توانند به یک آدرس از حافظه اشاره کنند. در شکل زیر این موضوع نشان داده شده است.

               
              در شکل زیر طبقه بندی نوع داده‌ها در سی شارپ نشان داده شده است :


              • عملیات کپی در نوع داده مقداری
              وقتی از یک متغیر مقداری را به یک متغیر دیگر تخصیص می‌دهیم، یک کپی جدید از آن در فضای stack  ایجاد می‌شود. بدین معنی که محتوای دو متغیر یکسان هستند، ولی در دو بخش مجزای در حافظه‌ی Stack قرار دارند. به همین خاطر تغییر  محتوای یک متغیر، محتوای متغیر دیگر را تغییر نمی‌دهد.
              مثال :
               int a = 55;//declare a and initialize
              int copya = a;//copya contains the copy of value a
              دیاگرام حافظه کد بالا :

               

              • عملیات کپی، در نوع داده‌ی ارجاعی
              وقتی یک متغیر از نوع ارجاعی را به یک متغیر دیگر تخصیص می‌دهیم، دو اشاره‌گر در فضای Stack ایجاد می‌شود که به یک مقدار واحد در حافظه‌ی heap اشاره می‌کنند. آدرس‌های ذخیره شده‌ی در stack  یکسان هستند.
              مثال : در اینجا فرض بر این است کهtest یک کلاس تعریف شده‌ی توسط کاربر می‌باشد.
              test obj;
              obj=new test(23);
              test objCopy;
              objCopy = obj;

              دیاگرام حافظه‌ی قطعه کد بالا به شکل زیر است :



              تخصیص حافظه در بخش Stack  و Heap به متغیر‌ها

              سیستم عامل و net CLR. حافظه را به دو بخش stack و heap تقسیم بندی می‌کنند.
              زمانی که یک متد را فراخوانی می‌کنیم، در بخش پشته به پارامتر‌های متد فضا تخصیص داده می‌شود و بعد از پایان کار متد، فضای اشغال شده‌ی بوسیله GC یا همان Garbage collection  آزاد می‌شود.
              تخصیص حافظه در Stack  بر اساس قانون LIFO انجام و به ترتیب و پشت سر هم، حافظه تخصیص داده می‌شود. دیاگرام تخصیص حافظه به stack:


              تخصیص حافظه در Heap بصورت تصادفی است؛ بر عکس پشته (stack) که به ترتیب و متوالی انجام می‌شد. انواع ارجاعی در Stack  ذخیره می‌شوند؛ ولی داده‌ی واقعی در heap قرار می‌گیرد.
              حافظه‌های پویا در بخش heap و حافظه‌های استاتیک در بخش stack تخصیص داده می‌شوند.
               
              مطالب
              نحوه‌ی استفاده از کتابخانه‌ی OpenSSL در ویندوز

              سؤالی شده به این مضمون : "یه الگوریتم دارم که بر طبق اون باید اعداد تصادفی خیلی بزرگ تولید کنم، اونها رو جمع و ضرب کنم. اینکه چطوری باید از dll یا lib استفاده کنم رو بلد نیستم. از VS2008 استفاده میکنم..."

              سؤال در مورد زبان CPP است. کتابخانه‌ی استاندارد انجام اینگونه عملیات برای زبان‌های C و CPP ، کتابخانه‌ی OpenSSL است. البته شاید الان 100 کتابخانه دیگر را هم لیست کنید، اما کسانی که با مباحث رمزنگاری اطلاعات مدتی کار کرده باشند، بعید است سر و کارشان به این کتابخانه نیفتاده باشد و یک استاندارد در این زمینه به شمار می‌رود؛ همچنین به دلیل سورس باز بودن در اکثر سکوهای کاری موجود نیز قابل استفاده است. بنابراین فراگیری نحوه‌ی کار کردن با آن یک مزیت به شمار می‌رود. قسمتی از این کتابخانه‌ی معظم مرتبط است به کار با اعداد بزرگ. این مورد را هم جهت استفاده در الگوریتم RSA نیاز دارد.
              برای استفاده از آن در ویندوز ابتدا باید OpenSSL را کامپایل کنید. کار پر دردسری است. به همین جهت یک سایت فقط به این موضوع اختصاص یافته و هربار آخرین نسخه‌ی OpenSSL را برای ویندوز کامپایل می‌کند و در اختیار علاقمندان قرار می‌دهد : +
              در حال حاضر یا باید Win32 OpenSSL v1.0.0a و یا Win64 OpenSSL v1.0.0a را دریافت کنید (برنامه‌ی شما اگر 64 بیتی کامپایل شود، dll های 32 بیتی را نمی‌تواند بارگذاری کند و برعکس).

              روش استفاده از کتابخانه‌ی OpenSSL در ویژوال CPP :

              الف) ابتدا فایل‌های کامپایل شده‌ی فوق را دریافت و نصب کنید. اکنون برای مثال یک پوشه‌ی OpenSSL-Win32 در کامپیوتر شما با محتویات این کتابخانه باید ایجاد شده باشد(اگر نسخه‌ی 32 بیتی را دریافت کرده‌اید).
              سپس به پوشه‌ی OpenSSL-Win32\lib\VC آن مراجعه کنید. در اینجا فایل‌های کتابخانه‌ای جهت استفاده در ویژوال CPP قرار گرفته‌اند. اگر از محتویات پوشه OpenSSL-Win32\lib\VC\static استفاده کنید، نیازی به توزیع فایل‌های DLL این کتابخانه نخواهید داشت و اگر از کتابخانه‌های OpenSSL-Win32\lib\VC استفاده کنید، فایل‌های dll را نیز حتما باید به همراه برنامه‌ی خود توزیع نمائید.
              سه نوع فایل در آن وجود دارند. ختم شده به MD ، MT و MDd که معانی آن‌ها در مورد چند ریسمانی بودن یا خیر است (برگرفته شده از فایل faq.txt دریافتی):

              Single Threaded /ML - MS VC++ often defaults to this for the release version of a new project.
              Debug Single Threaded /MLd - MS VC++ often defaults to this for the debug version of a new project.
              Multithreaded /MT
              Debug Multithreaded /MTd
              Multithreaded DLL /MD - OpenSSL defaults to this.
              Debug Multithreaded DLL /MDd

              ب) جهت سهولت کار، پوشه‌ی OpenSSL قرار گرفته در مسیر OpenSSL-Win32\include را در آدرس زیر کپی نمائید:
              C:\Program Files\Microsoft Visual Studio 10.0\VC\include
              به این صورت حین استفاده از این کتابخانه نیازی به مشخص سازی محل قرارگیری فایل‌های include نخواهد بود.

              ج) اکنون یک پروژه‌ی جدید Visual C++\Win32\Win32 console application را در VS.NET آغاز کنید؛ برای مثال به نام OpenSSLTest .

              د) سپس به منوی پروژه، گزینه‌ی خواص پروژه مراجعه کرده و مطابق تصاویر زیر، این فایل‌های کتابخانه‌ای را معرفی کنید (انتخاب MD یا MT یا MDd بر اساس runtime library انتخاب شده است که در تصاویر مشخص گردیده):









              ه) اکنون یک مثال ساده در مورد ضرب دو عدد بزرگ به صورت زیر می‌تواند باشد:

              #include "stdafx.h"
              #include <openssl/bn.h>
              #include <string.h>


              void RotateBytes(unsigned char *in, int n)
              {
              unsigned char *e=in+n-1;
              do {
              unsigned char temp=*in;
              *in++=*e;
              *e-- =temp;
              } while(in<e);
              }

              int _tmain(int argc, _TCHAR* argv[])
              {
              //دو عدد بزرگ جهت آزمایش
              unsigned char testP[] = {0xD1,0x31,0x85,0x4D,0x00,0xD6,0x31,0x97,0x3A,0xFC,0xD2,0x27,0x02,0xEF,0xC2,0xA7};
              unsigned char testA[] = {0xC7,0x1B,0x25,0x72,0x03,0xCB,0x72,0x03,0xCF,0x23,0x27,0x2D,0x00,0xD6,0x31,0x98};

              //تبدیل آرایه‌های فوق به فرمت اعداد بزرگ
              BIGNUM *a = BN_new();
              //it should be in "big-endian" form
              RotateBytes(testA, 16);
              BN_bin2bn(testA, 16, a);

              BIGNUM *p = BN_new();
              //it should be in "big-endian" form
              RotateBytes(testP, 16);
              BN_bin2bn(testP, 16, p);


              //ضرب این دو عدد در هم
              BIGNUM *result = BN_new();
              BN_CTX *ctx = BN_CTX_new();

              BN_mul(result, a, p, ctx);

              //نمایش نتیجه
              //حاصل از چند بایت تشکیل شده؟
              int num = BN_num_bytes(result);
              if(num>0)
              {
              unsigned char *tmpdata;
              if((tmpdata=(unsigned char *)malloc(num)))
              memset(tmpdata, 0, num);

              //تبدیل عدد با فرمت اعداد بزرگ به آرایه‌ای از بایت‌ها
              BN_bn2bin(result, tmpdata);
              RotateBytes(tmpdata, num);

              for(int i=0; i<num; i++)
              {
              if(i%16==0) printf("\n");
              printf("%02X ",tmpdata[i]);
              }

              if(tmpdata) free(tmpdata);
              }


              //آزاد سازی منابع
              BN_free(a);
              BN_free(p);
              BN_CTX_free(ctx);

              return 0;
              }


              در مورد شرح توابع کتابخانه OpenSSL به اینجا مراجع کنید : +
              علت استفاده از تابع RotateBytes ، تغییر endian ورودی است.

              نظرات مطالب
              ASP.NET MVC #17
              این یک کار سورس باز هست. می‌تونید مطابق قوانین آن، خودتون این کار رو انجام بدید و یک مرحله اون رو جلو ببرید. حاصل نهایی باید فایل ورد قابل ویرایش باشد. pdf درست نکنید. ممنون.
              مطالب
              بستن یک پنجره از طریق ViewModel با استفاده از خصوصیت های پیوست شده هنگام استفاده از الگوی MVVM
               در نظر بگیرید که یک پروژه WPF را با الگوی MVVM پیاده سازی کرده اید و نیاز پیدا می‌کنید تا یک پنجره را از طریق کد ببندید. از آنجایی که به کنترل Window درون ViewModel دسترسی ندارید، نمی‌توانید از متد Close آن برای اینکار استفاده کنید. راه‌های مختلفی برای اینکار وجود دارند، مثلا اگر از MVVM Light Toolkit استفاده می‌کنید با ارسال یک Message و نوشتن یک تکه کد در CodeBehind پنجره می‌توانید اینکار را انجام بدهید.
              اما برای اینکار یک راه حل ساده‌تری بدون نیاز به نوشتن کد در CodeBehind و استفاده از Toolkit خاصی وجود دارد و آن استفاده ازخاصیت‌های پیوست شده یا Attached Properties است. برای اینکار یک خاصیت از نوع Boolean مانند زیر تعریف می‌کنیم و آن را به پنجره ای که می‌خواهیم Colse شود پیوست می‌کنیم.
              namespace TestProject.XamlServices
              {
                  public class CloseBehavior
                  {
                      public static readonly DependencyProperty CloseProperty = 
              DependencyProperty.RegisterAttached("Close", typeof(bool), typeof(CloseBehavior), new UIPropertyMetadata(false, OnClose));
              
                      private static void OnClose(DependencyObject sender, DependencyPropertyChangedEventArgs e)
                      {
                          if (!(e.NewValue is bool) || !((bool) e.NewValue)) return;
                          var win = GetWindow(sender);
                          if (win != null)
                              win.Close();
                      }
              
                      private static Window GetWindow(DependencyObject sender)
                      {
                          Window w = null;
                          if (sender is Window)
                              w = (Window)sender;
                          return w ?? (w = Window.GetWindow(sender));
                      }
              
                      public static bool GetClose(Window target)
                      {
                          return (bool)target.GetValue(CloseProperty);
                      }
              
                      public static void SetClose(DependencyObject target, bool value)
                      {
                          target.SetValue(CloseProperty, value);
                      }
                  }
              } 
              در تکه کد بالا یک خصوصیت از نوع  Boolean  ایجاد کردیم که می‌تواند به هر پنجره ای که قرار است از طریق کد بسته شود، پیوست شود. خصوصیت‌های پیوست شده یک  Callback مربوط به تغییر مقدار دارند که یک  متداستاتیک است و مقدار جدید، از طریق  EventArg و   شیءایی که این خاصیت به آن پیوست شده نیز بعنوان Source  به آن  ارسال می‌شود. هر وقت مقدار خصوصیت، تغییر کند این متد فراخوانی می‌گردد. در کد بالا متد OnClose ایجاد شده است و زمانی که مقدار این خصوصیت برابر true می‌شود پنجره close خواهد شد.
              برای استفاده از این خصوصیت و اتصال آن باید یک خصوصیت از نوع Boolean  نیز در ViewModel مربوط به Window ایجاد کنید:  
               private bool _isClose;
               public bool IsClose
                 {
                    get { return _isClose; }
                    set
                    {
                     _isClose = value;
                    OnClosed();
                    RaisePropertyChanged("IsClose");
                    }
              }
              و آن را به صورت زیر Bind کنید:  
              <Window x:Class="TestProject.TestView"
                      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                      xmlns:xamlServices="clr-namespace:TestProject.XamlServices;assembly=TestProject.XamlServices"
                     xamlServices:CloseBehavior.Close="{Binding IsClose}">
                     ...
              </Window>
              پس از انجام اتصالات فوق، کافیست   هر جایی از ViewModel که نیاز است پنجره بسته شود،مقدار این خصوصیت برابر False بشود.