اشتراک‌ها
کار با LINQ to XML
ساخت، لود، جستجو، دستکاری، تبدیل به انواع دیگر.
کار با LINQ to XML
مطالب
جلوگیری از ورود همزمان کاربران با نام کاربری و رمز عبور یکسان
در اکثر برنامه‌های وب، کاربر قادر است با یک نام کاربری و رمز عبور در چند Session همزمان لاگین کند. ممکن است سیاست برخی مدیران محصول این باشد که جلوی این مورد را بگیرند تا به عنوان مثال کاربران را به جای استفاده‌ی همزمان از یک نام کاربری و رمز عبور، مجبور به خرید مجوز‌های بیشتری کنند. ASP.NET Identity به صورت پیش فرض این مورد را پشتیبانی نمی‌کند؛ اما به کمک استفاده از امکانات درونی آن می‌توان این پشتیبانی را اضافه کرد.
یکی از فیلد‌های جدول AspNetUsers فیلد SecurityStamp می‌باشد. SecurityStamp یک مقدار تصادفی است:


Security Stamp باید با هربار تغییر اطلاعات احراز هویت (مانند رمز عبور) و اختیارات کاربر(Role) تغییر کند. به عنوان مثال کاربری در چند مرورگر لاگین کرده و گزینه‌ی مرا به خاطر داشته باش را انتخاب کرده است. اگر این کاربر رمز عبورش از هر جایی عوض شود، باید لاگین او در همه‌ی Session‌ها غیر معتبر شود. این مورد با تغییر کردن SecurityStamp بعد از تغییر رمز عبور صورت می‌گیرد. ASP.NET مقدار SecurityStamp را در کوکی کاربر نگه می‌دارد و در بازه‌های زمانی، این مقدار را با مقدار درون دیتابیس مقایسه می‌کند و در صورت عدم برابری، کاربر را احراز هویت نمی‌کند. بازه‌ی زمانی این بررسی در متد ConfigureAuth قابل تنظیم است که در ادامه شرح داده خواهد شد.
صورت مساله یافتن راه حلی جهت جلوگیری از ورود همزمان چند کاربر با یک نام کاربری و رمز عبور به سیستم می‌باشد. یکی از راه‌حل هایی که در ابتدا به ذهن می‌آید استفاده از Session و نگهداری کاربران لاگین کرده در حافظه می‌باشد. پیاده سازی این راه حل می‌تواند به کمک یک کلاس Static صورت پذیرد، اما قسمت چالشی این موضوع این است که چه زمانی باید کاربر از لیست حذف گردد؟ اگر اتصال کاربر قطع شود چه عملی باید صورت گیرد؟
راه حل دیگر استفاده از SecurityStamp هست؛ به این صورت که با هربار لاگین کاربر این مقدار تصادفی به‌روز گردد و ASP.NET Identity به گونه‌ای تنظیم شود که با هر درخواست HTTP، صحت SecurityStamp بررسی گردد. مقدار پیش فرض بازه‌ی زمانی بررسی، هر 30 دقیقه یک بار است.
در مثال‌های رسمی ASP.NET Identity لاگین به صورت ذیل پیاده سازی شده است:
   
        [HttpPost]
        [AllowAnonymous]
        [ValidateAntiForgeryToken]
        public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
        {
            if (!ModelState.IsValid)
            {
                return View(model);
            }
            // This doesn't count login failures towards account lockout
            // To enable password failures to trigger account lockout, change to shouldLockout: true
            var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
            switch (result)
            {
                case SignInStatus.Success:
                    return RedirectToLocal(returnUrl);
                case SignInStatus.LockedOut:
                    return View("Lockout");
                case SignInStatus.RequiresVerification:
                    return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
                case SignInStatus.Failure:
                default:
                    ModelState.AddModelError("", "Invalid login attempt.");
                    return View(model);
            }
        }
این کد را باید به گونه‌ای تغییر داد که اگر نام کاربری و رمز عبور معتبر بودند، مقدار SeucrityStamp به‌روز گردد. به همین منظور قبل از فراخوانی PasswordSignInAsync کد ذیل اضافه می‌گردد:
       var loggedinUser = await UserManager.FindAsync(model.Email, model.Password);
            if (loggedinUser != null)
            {
                await UserManager.UpdateSecurityStampAsync(loggedinUser.Id);
            }
همانطور که مشاهده می‌شود، جهت بروز رسانی SecurityStamp از سازوکار درونی ASP.NET Identity، در واقع متد UpdateSecurityStampAsync بهره گرفته شده است.
اکنون باید تنظیمات پیش‌فرض بازه‌ی زمانی بررسی صحت SecurityStamp تغییر داده شود. این تنظیمات در فایل Startup.Auth.cs در پوشه‌ی App_Start قرار دارند:
     app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                LoginPath = new PathString("/Account/Login"),
                Provider = new CookieAuthenticationProvider
                {
                    // Enables the application to validate the security stamp when the user logs in.
                    // This is a security feature which is used when you change a password or add an external login to your account.  
                    OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                        validateInterval: TimeSpan.FromMinutes(30),
                        regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
                }
            });
در کد بالا OnValidateIdentity باید مقدار ذیل را بگیرد:
OnValidateIdentity =
                        SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                            TimeSpan.FromMinutes(0), // <-- Note the timer is set for zero
                            (manager, user) => user.GenerateUserIdentityAsync(manager))
اکنون Framework موظف است در هر درخواست HTTP، صحت SeucirtyStamp را بررسی کند. بنابراین اگر کاربری در سیستم لاگین باشد و کاربر دیگری با همان نام کاربری و رمز عبور لاگین کند، کاربر اول از سیستم لاگ اوت می‌شود؛ چرا که مقدار SecurityStamp او دیگر معتبر نیست. باید در نظر گرفته شود این عمل در سیستم‌های با تعداد کاربر زیاد باعث افزایش درخواست‌های دیتابیس می‌شود. 
اکنون جهت تست، اگر با مرورگر اول در سیستم لاگین صورت گیرد، سپس با همان اطلاعات در مرورگری دیگر، لاگین صورت گیرد، کاربر اول پس از درخواست بعدی، از سیستم لاگ اوت می‌شود. در مثال انتهای مطلب، صفحه‌ی About به صورت غیر عمومی درآمده که می‌توان بررسی راه حل جاری را در آن صفحه صورت داد. 
اگر بخواهیم لاگ اوت شدن کاربر را آنی کنیم، می‌توان در فواصل زمانی مشخصی، یک درخواست Ajax از سمت کلاینت به سرور ارسال کرد و تصدیق هویت کاربر را بررسی کرد:
        window.setInterval(function() {
            $.ajax({
                url:,
                type: "Post",
                dataType: "json",
                success: function(data) {
                    if (!data) {
                        alert("Someone has logged in using your username and password!");
                        location.reload();
                    }
                }
            });
        }, 60000);
در کد بالا به کمک window.setInterval، هر یک دقیقه یک بار لاگین بودن کاربر بررسی می‌گردد و در صورت لاگین نبودن، پیغام لازم به کاربر نمایش داده می‌شود. در نظر داشته باشید، این کد تنها باید در صفحات غیر عمومی قرار داده شود.
کد اکشن بررسی لاگین بودن به سادگی ذیل است:
        [AllowAnonymous]
        public virtual ActionResult Authenticated()
        {
            return Json(User.Identity.IsAuthenticated);
        }

نکته‌ی مهم این است که خصیصه‌ی AllowAnonymous بالای اکشن قرار گرفته باشد تا در صورتیکه Controller به صورت عمومی در دسترس نیست، اکشن همیشه و حتی وقتی کاربر لاگ اوت شده در دسترس باشد. در مثال انتهای مطلب صفحه‌ی About تنها در اختیار کاربران احراز هویت شده قرار گرفته است، بنابراین اگر دو کاربر با اطلاعات یکسانی به سیستم لاگین کنند، کاربر اول پیغام خطای ذیل را گرفته و به صفحه‌ی لاگین می‌رود. این کد در صفحه‌ی About در مثال انتهای مطلب قرار گرفته است:

اشتراک‌ها
Open-XML-SDK؛ کتابخانه‌ای برای کار با اسناد آفیس

The Open XML SDK provides tools for working with Office Word, Excel, and PowerPoint documents. It supports scenarios such as:

  • High-performance generation of word-processing documents, spreadsheets, and presentations.
  • Document modification, such as adding, updating, and removing content and metadata.
  • Search and replace content using regular expressions.
  • Splitting up (shredding) a file into multiple files, and combining multiple files into a single file.
  • Updating cached data and embedded spreadsheets for charts in Word/PowerPoint. 
Open-XML-SDK؛ کتابخانه‌ای برای کار با اسناد آفیس
مطالب
خواندن اطلاعات از فایل اکسل با استفاده از LinqToExcel
در این مقاله مروری سریع و کاربردی خواهیم داشت بر توانایی‌های مقدماتی LinqToExcel
در ابتدا می‌بایست LinqToExcel را از طریق NuGet به پروژه افزود.
PM> Install-Package LinqToExcel
و یا از طریق solution Explorer گزینه Manage NuGet Packages 

اکنون فایل اکسل ذیل را در نظر بگیرید.

روش خواندن اطلاعات از فایل اکسل فوق تحت فرامین Linq و با مشخص کردن نام sheet مورد نظر  توسط شئ ExcelQueryFactory  بصورت زیر است.

 string pathToExcelFile = @"C:\Users\MASOUD\Desktop\ExcelFile.xlsx";
var excel = new ExcelQueryFactory(pathToExcelFile);
            string sheetName = "Sheet1";
            var persons = from a in excel.Worksheet(sheetName) select a;
            foreach (var a in persons)
            {
                MessageBox.Show(a["Name"]+" "+a["Family"]);
            }


در صورتیکه بخواهیم انتقال اطلاعات فایل اکسل به جداول بانک اطلاعاتی مانند Sql Server بطور مثال با روش EF Entity Framework را انجام دهیم کلاس زیر با نام person را فرض نمایید.

 public class Person
        {
            public string Name { get; set; }
            public string Family { get; set; }
        }
باید بدانید که بصورت پیشفرض سطر اول از فایل اکسل به عنوان نام ستون انتخاب می‌شود و می‌بایست جهت نگاشت با نام property‌های کلاس ما دقیقاً همنام باشد.

 string pathToExcelFile = @"C:\Users\MASOUD\Desktop\ExcelFile.xlsx";
            var excel = new ExcelQueryFactory(pathToExcelFile);
            string sheetName = "Sheet1";
            var persons = from a in excel.Worksheet<Person>(sheetName) select a;
            foreach (var a in persons)
            {
                MessageBox.Show(a.Name+" "+a.Family);
            }
  اگر فایل اکسل ما ستون‌های بیشتری داشته باشد تنها ستونهای همنام با propertyهای کلاس ما به کلاس نگاشت پیدا می‌کند و سایر ستونها نادیده گرفته می‌شود.
در صورتیکه نام ستونهای فایل اکسل(سطر اول) با نام property‌های کلاس یکسان نباشد جهت نگاشت آنها در کلاس می‌توان از متد AddMapping استفاده نمود.
 

 string pathToExcelFile = @"C:\Users\MASOUD\Desktop\ExcelFile.xlsx";
            var excel = new ExcelQueryFactory(pathToExcelFile);
            string sheetName = "Sheet1";
            excel.AddMapping("Name","نام");
            excel.AddMapping("Family", "نام خانوادگی");
            var persons = from a in excel.Worksheet<Person>(sheetName) select a;
            foreach (var a in persons)
            {
                MessageBox.Show(a.Name+" "+a.Family);
            }

در کدهای بالا در صورتی که sheetName قید نشود بصورت پیشفرض Sheet1 از فایل اکسل  انتخاب می‌شود.

var persons = from a in excel.Worksheet<Person>() select a;
همچنین می‌توان از اندیس جهت مشخص نمودن Sheet مورد نظر استفاده نمود که اندیس‌ها از صفر شروع می‌شوند.

var persons = from a in excel.Worksheet<Person>(0) select a;
توسط متد GetWorksheetNames می توان نام sheet‌ها را بدست آورد.

public IEnumerable<string> getWorkSheets()
{
string pathToExcelFile = @"C:\Users\MASOUD\Desktop\ExcelFile.xlsx";
    
    var excel = new ExcelQueryFactory(pathToExcelFile);

    return excel.GetWorksheetNames();
}
و توسط متد GetColumnNames   می توان نام ستونها را بدست آورد.  

var SheetColumnNames = excel.GetColumnNames(sheetName);
همانطور که می‌بینید با روش توضیح داده شده در این مقاله به راحتی از فرامین Linq مانند where می‌توان در انتخاب اطلاعات از فایل اکسل استفاده نمود و سپس نتیجه را به جداول مورد نظر انتقال داد.
اشتراک‌ها
انتشار Microsoft Office 2024
Availability of Office 2024
Office 2024 comes in two editions. Office Home 2024 is $149.99 USD and includes Word, Excel, PowerPoint, and OneNote for one PC or Mac. Office Home & Business 2024 is $249.99 USD and comes with everything in Office Home 2024 plus Outlook and the rights to use the apps for commercial purposes. You can buy both editions from retailers worldwide and via Microsoft.com starting October 1, 2024.
انتشار Microsoft Office 2024
نظرات مطالب
اهمیت Controller های ساده در ASP.NET MVC
آیا در معماری چندلایه (N-Tier arch) مرزبندی شفافی وجود دارد که از نظر شی‌گرایی روش یا روش‌های مرجح وجود داشته باشند؟
مثلا علت اینکه شما کنترل‌ها در MVC رو لایه نمایش به‌حساب میارین متوجه نشدم و مگر در واقع BL ما در کنترلرها اتفاق نمیوفته؟ یا مثلا ViewModel ما اگر با View در دولایه متفاوت هستندـ(که هستند) جزو همان لایه نمایش به‌حساب میان؟ 
اگر برایتان مقدور است در مورد مرزهای شفاف تفکیک منطقی و فیزیکی (Layer & Tier) در MVC توضیح بدین،‌ممنون میشم.