اشتراکها
کتابخانه photoswipe
JavaScript image gallery for mobile and desktop, modular, framework independent Demo
اشتراکها
وب سایت AngularJS 2.0
اشتراکها
ایده Universal App به زودی در ویندوز
اشتراکها
ETO؛ فریم ورک GUI چندسکویی
با تشکر،
فقط مسئله ای که هست، اینه که از Cache مربوط به ASP.NET استفاده میکنه و برای یه نرم افزار Desktop مناسب نیست. آیا پیاده سازی ای با MemoryCache نداره؟
همانطور که پیشتر در این مقاله بحث شده است، بوسیله AOP میتوان قابلیتهایی که قسمت عمدهای از برنامه را تحت پوشش قرار میدهند، کپسوله کرد. یکی از قابلیتهایی که در بخشهای مختلف یک سیستم نرمافزاری مورد نیاز است، Authorization یا اعتبارسنجیست. در ادامه به بررسی یک پیادهسازی به این روش میپردازیم.
کتابخانه SNAP
کتابخانه SNAP به گفته سازنده آن، با یکپارچهسازی AOP با IoC Containerهای محبوب، برنامهنویسی به این سبک را ساده میکند. این کتابخانه هم اکنون علاوه بر structureMap از IoC Providerهای Autofac, Ninject, LinFu و Castle Windsor نیز پشتیبانی میکند.
دریافت SNAP.StructureMap
برای دریافت آن نیاز است دستور پاورشل ذیل را در کنسول نیوگت ویژوال استودیو اجرا کنید:
PM> Install-Package snap.structuremap
StructureMap (≥ 2.6.4.1) CommonServiceLocator.StructureMapAdapter (≥ 1.1.0.3) SNAP (≥ 1.8) fasterflect (≥ 2.1.2) Castle.Core (≥ 3.1.0) CommonServiceLocator (≥ 1.0)
تنظیمات SNAP
از آنجا که تنظیمات SNAP همانند تنظیمات StructureMap تنها باید یک بار اجرا شود، بهترین جا برای آن در یک برنامه وب، Application_Start فایل Global.asax است.
namespace Framework.UI.Asp { public class Global : HttpApplication { void Application_Start(object sender, EventArgs e) { initSnap(); initStructureMap(); } private static void initSnap() { SnapConfiguration.For<StructureMapAspectContainer>(c => { // Tell Snap to intercept types under the "Framework.ServiceLayer..." namespace. c.IncludeNamespace("Framework.ServiceLayer.*"); // Register a custom interceptor (a.k.a. an aspect). c.Bind<Framework.ServiceLayer.Aspects.AuthorizationInterceptor>() .To<Framework.ServiceLayer.Aspects.AuthorizationAttribute>(); }); } void Application_EndRequest(object sender, EventArgs e) { ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects(); } private static void initStructureMap() { var thread = StructureMap.Pipeline.Lifecycles.GetLifecycle(InstanceScope.HttpSession); ObjectFactory.Configure(x => { x.For<IUserManager>().Use<EFUserManager>(); x.For<IAuthorizationManager>().LifecycleIs(thread) .Use<EFAuthorizationManager>().Named("_AuthorizationManager"); x.For<Framework.DataLayer.IUnitOfWork>() .Use<Framework.DataLayer.Context>(); x.SetAllProperties(y => { y.OfType<IUserManager>(); y.OfType<Framework.DataLayer.IUnitOfWork>(); y.OfType<Framework.Common.Web.IPageHelpers>(); }); }); } } }
در ادامه به بررسی کلاس AuthorizationInterceptor میپردازیم.
namespace Framework.ServiceLayer.Aspects { public class AuthorizationInterceptor : MethodInterceptor { public override void InterceptMethod(IInvocation invocation, MethodBase method, Attribute attribute) { var AuthManager = StructureMap.ObjectFactory .GetInstance<Framework.ServiceLayer.UserManager.IAuthorizationManager>(); var FullName = GetMethodFullName(method); if (!AuthManager.IsActionAuthorized(FullName)) throw new Common.Exceptions.UnauthorizedAccessException(""); invocation.Proceed(); // the underlying method call } private static string GetMethodFullName(MethodBase method) { var TypeName = (((System.Reflection.MemberInfo)(method)).DeclaringType).FullName; return TypeName + "." + method.Name; } } public class AuthorizationAttribute : MethodInterceptAttribute { }
کلاس مذکور از کلاس MethodInterceptor کتابخانه snap ارث بری کرده و متد InterceptMethod را تحریف میکند. این متد، کار اجرای متد اصلی ای که با این Aspect تزئین شده را بر عهده دارد. بنابراین میتوان پیش از اجرای متد اصلی، اعتبارسنجی را انجام داد.
کلاس MethodInterceptor
کلاس MethodInterceptor شامل چندین متد دیگر نیز هست که میتوان برای سایر مقاصد از جمله مدیریت خطا و Event logging از آنها استفاده کرد.
namespace Snap { public abstract class MethodInterceptor : IAttributeInterceptor, IInterceptor, IHideBaseTypes { protected MethodInterceptor(); public int Order { get; set; } public Type TargetAttribute { get; set; } public virtual void AfterInvocation(); public virtual void BeforeInvocation(); public void Intercept(IInvocation invocation); public abstract void InterceptMethod(IInvocation invocation, MethodBase method, Attribute attribute); public bool ShouldIntercept(IInvocation invocation); } }
یک نکته
نکته مهمی که در اینجا پیش میآید این است که برای اعتبارسنجی، کد کاربری شخصی که لاگین کرده، باید به طریقی در اختیار متد ()IsActionAuthorized قرار بگیرد. برای این کار میتوان در یک HttpMudole به عنوان مثال همان ماژولی که برای تسهیل در کار تزریق خودکار وابستگیها در سطح فرمها استفاده میشود، با استفاده از امکانات structureMap به وهلهی ایجاد شده از AuthorizationManager (که با کمک structureMap با طول عمر InstanceScope.HttpSession ساخته شده است) دسترسی پیدا کرده و خاصیت مربوطه را مقداردهی کرد.
private void Application_PreRequestHandlerExecute(object source, EventArgs e) { var page = HttpContext.Current.Handler as BasePage; // The Page handler if (page == null) return; WireUpThePage(page); WireUpAllUserControls(page); var UsrCod = HttpContext.Current.Session["UsrCod"]; if (UsrCod != null) { var _AuthorizationManager = ObjectFactory .GetNamedInstance<Framework.ServiceLayer.UserManager.IAuthorizationManager>("_AuthorizationManager"); ((Framework.ServiceLayer.UserManager.EFAuthorizationManager)_AuthorizationManager) .AuditUserId = UsrCod.ToString(); } }
روش استفاده
نحوه استفاده از Aspect تعریف شده در کد زیر قابل مشاهده است:
namespace Framework.ServiceLayer.UserManager { public class EFUserManager : IUserManager { IUnitOfWork _uow; IDbSet<User> _users; public EFUserManager(IUnitOfWork uow) { _uow = uow; _users = _uow.Set<User>(); } [Framework.ServiceLayer.Aspects.Authorization] public List<User> GetAll() { return _users.ToList<User>(); } } }
در مطلب «کار با یک مخزن کد GitHub از طریق VSCode»، نحوهی Clone یک مخزن کد از پیش موجود در GitHub را بررسی کردیم. گردش کاری دیگری را که میتوان درنظر گرفت، داشتن یک مخزن کد محلی و سپس ارسال آن به یک مخزن کد جدید در GitHub است.
ایجاد یک مخزن کد محلی جدید توسط VSCode
فرض کنید پوشهای را با ساختار ذیل داریم:
وجود فایل gitignore. را در حین کار با Git و ارسال پروژه به مخازن کد فراموش نکنید. این فایل سبب خواهد شد تا بسیاری از پوشههایی که نباید ارسال شوند (مانند پوشههای bin یا packages و امثال آن)، به صورت خودکار ندید گرفته شوند.
در ادامه برای افزودن این پوشه به یک مخزن کد محلی تنها کافی است به برگهی Git آن مراجعه کرده و بر روی دکمهی Initialize repository کلیک کنیم:
البته این دستور در منوی ctrl+shift+p هم با جستجوی git ظاهر میشود:
پس از آغازن مخزن کد محلی، توضیحاتی را نوشته و سپس بر روی دکمهی commit کلیک میکنیم تا این تغییرات با آن هماهنگ شوند:
ارسال مخزن کد محلی به GitHub از طریق VSCode
در ادامه میخواهیم این مخزن کد محلی را به یک مخزن کد جدید در GitHub ارسال کنیم. به همین منظور یک مخزن کد جدید را در GitHub آغاز کرده و گزینهی «Initialize this repository with a README » را انتخاب نمیکنیم:
در صفحهی بعدی که ظاهر میشود، دو دستور آن مهم هستند:
در VSCode، با فشردن دکمههای Ctrl+back-tick، کنسول خط فرمان را گشوده و دو دستور فوق را به ترتیب اجرا کنید. این دستورات سبب خواهند شد تا مخزن کد محلی، به مخزن کد GitHub متصل شده و همچنین تغییرات آن به سمت سرور ارسال و با آن هماهنگ شوند.
اکنون اگر به مخزن کد GitHub مراجعه کنیم، میتوان این هماهنگی و ارسال فایلها را مشاهده کرد:
یک گردش کاری دیگر: هم مخزن کد محلی و هم مخزن کد GitHub دارای فایل هستند
فرض کنید مخزن کد GitHub شما هم اکنون دارای تعدادی فایل است و مانند مثال فوق، از ابتدا و بدون افزودن فایلی به آن ایجاد نشدهاست. همچنین مخزن کد محلی نیز دارای تعدادی فایل است (Initialize repository شدهاست) و نمیخواهیم از روش Clone مطلب «کار با یک مخزن کد GitHub از طریق VSCode» استفاده کنیم.
در اینجا نیز با فشردن دکمههای Ctrl+back-tick، کنسول خط فرمان را گشوده و همان سطر اول git remote add origin را اجرا میکنیم:
اما باید دقت داشت که اینبار دستور دوم رال که push است، نمیتوانیم اجرا کنیم (چون سرور ریموت دارای فایل است). در اینجا برای هماهنگی با سرور ابتدا باید دستور pull را صادر کنیم:
به این ترتیب فایلهای سرور دریافت شده و به پروژهی جاری اضافه میشوند.
همچنین برای هماهنگی تغییرات محلی بعدی با سرور (عملیات push) باید ابتدا branch را تنظیم کرد:
ایجاد یک مخزن کد محلی جدید توسط VSCode
فرض کنید پوشهای را با ساختار ذیل داریم:
وجود فایل gitignore. را در حین کار با Git و ارسال پروژه به مخازن کد فراموش نکنید. این فایل سبب خواهد شد تا بسیاری از پوشههایی که نباید ارسال شوند (مانند پوشههای bin یا packages و امثال آن)، به صورت خودکار ندید گرفته شوند.
در ادامه برای افزودن این پوشه به یک مخزن کد محلی تنها کافی است به برگهی Git آن مراجعه کرده و بر روی دکمهی Initialize repository کلیک کنیم:
البته این دستور در منوی ctrl+shift+p هم با جستجوی git ظاهر میشود:
پس از آغازن مخزن کد محلی، توضیحاتی را نوشته و سپس بر روی دکمهی commit کلیک میکنیم تا این تغییرات با آن هماهنگ شوند:
ارسال مخزن کد محلی به GitHub از طریق VSCode
در ادامه میخواهیم این مخزن کد محلی را به یک مخزن کد جدید در GitHub ارسال کنیم. به همین منظور یک مخزن کد جدید را در GitHub آغاز کرده و گزینهی «Initialize this repository with a README » را انتخاب نمیکنیم:
در صفحهی بعدی که ظاهر میشود، دو دستور آن مهم هستند:
…or push an existing repository from the command line git remote add origin https://github.com/VahidN/test-vscode.git git push -u origin master
در VSCode، با فشردن دکمههای Ctrl+back-tick، کنسول خط فرمان را گشوده و دو دستور فوق را به ترتیب اجرا کنید. این دستورات سبب خواهند شد تا مخزن کد محلی، به مخزن کد GitHub متصل شده و همچنین تغییرات آن به سمت سرور ارسال و با آن هماهنگ شوند.
اکنون اگر به مخزن کد GitHub مراجعه کنیم، میتوان این هماهنگی و ارسال فایلها را مشاهده کرد:
یک گردش کاری دیگر: هم مخزن کد محلی و هم مخزن کد GitHub دارای فایل هستند
فرض کنید مخزن کد GitHub شما هم اکنون دارای تعدادی فایل است و مانند مثال فوق، از ابتدا و بدون افزودن فایلی به آن ایجاد نشدهاست. همچنین مخزن کد محلی نیز دارای تعدادی فایل است (Initialize repository شدهاست) و نمیخواهیم از روش Clone مطلب «کار با یک مخزن کد GitHub از طریق VSCode» استفاده کنیم.
در اینجا نیز با فشردن دکمههای Ctrl+back-tick، کنسول خط فرمان را گشوده و همان سطر اول git remote add origin را اجرا میکنیم:
git remote add origin https://github.com/VahidN/test-vscode.git
git pull origin master --allow-unrelated-histories
همچنین برای هماهنگی تغییرات محلی بعدی با سرور (عملیات push) باید ابتدا branch را تنظیم کرد:
git branch --set-upstream-to=origin/master master