اشتراکها
تزریق وابستگی چطور کار میکند؟
نظرات مطالب
مروری بر کاربردهای Action و Func - قسمت اول
نمیتوان. چون در اصل Action و Func به این صورت تعریف شدهاند:
public delegate void Action<in T1, in T2>(T1 arg1, T2 arg2); public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);
+ از زمان C# 7.0 اگر نیاز به نامگذاری این پارامترها را داشتید، میتوانید از tuples به صورت زیر استفاده کنید:
Func<(string firstName, string lastName), string> f = (data) => data.firstName + data.lastName; f(("Foo", "Bar"));
نظرات مطالب
خودکارسازی فرآیند نگاشت اشیاء در AutoMapper
ممنونم. مشکل قبل حل شد.
خطایی صادر میکندبا این عنوان:
اگر دو فیلد IsApplied , Qty هم در متد CreateMappings بصورت دستی map کنم خطایی صادر نمیشود. در صورتیکه قبلا با اتوماتیک مپ میشدند. آیا تغییری در AutoMapperRegistry نیاز هست؟
اگر ویومدل من بدینصورت باشه
public class MyViewModel : IHaveCustomMappings { public int SchedulerId { get; set; } public bool IsApplied { get; set; } public int Qty { get; set; } public void CreateMappings(IMapperConfigurationExpression configuration) { configuration.CreateMap<DomainModels.Models.Scheduler, MyViewModel>() .ForMember(dest => dest.SchedulerId, opt => opt.MapFrom(src => src.Id)); } }
Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
در حین بروز استثناهای Entity framework، میتوان توسط ابزارهای Logging متنوعی مانند ELMAH، جزئیات متداول آنها را برای بررسیهای آتی ذخیره کرد. اما این جزئیات فاقد SQL نهایی تولیدی و همچنین پارامترهای ورودی توسط کاربر یا تنظیم شده توسط برنامه هستند. برای اینکه بتوان این جزئیات را نیز ثبت کرد، میتوان یک IDbCommandInterceptor جدید را طراحی کرد.
کلاس EfExceptionsInterceptor
در اینجا نمونهای از یک پیاده سازی اینترفیس IDbCommandInterceptor را مشاهده میکنید. همچنین طراحی یک متد عمومی که میتواند به جزئیات SQL نهایی و پارامترهای آن دسترسی داشته باشد، در اینترفیس IEfExceptionsLogger ذکر شدهاست.
تهیه یک پیاده سازی سفارشی از IEfExceptionsLogger توسط ELMAH
اکنون که ساختار کلی IDbCommandInterceptor سفارشی برنامه مشخص شد، میتوان پیاده سازی خاصی از آنرا جهت استفاده از ELMAH به نحو ذیل ارائه داد:
در اینجا شیء Command به همراه SQL نهایی تولید و پارامترهای مرتبط است. همچنین interceptionContext.OriginalException جزئیات عمومی استثنای رخ داده را به همراه دارد. میتوان این اطلاعات را پس از اندکی نظم بخشیدن، به متد Raise مربوط به ELMAH ارسال کرد تا جزئیات بیشتری از استثنای رخ داده شده، در لاگهای آن ظاهر شوند.
استفاده از ElmahEfExceptionsLogger جهت طراحی یک Interceptor عمومی
برای استفاده از ElmahEfExceptionsLogger و تهیه یک Interceptor عمومی، میتوان با ارث بری از کلاس Interceptor ابتدای بحث شروع کرد و وهلهای از ElmahEfExceptionsLogger را به سازندهی آن تزریق نمود (یکی از چندین روش ممکن). سپس برای استفاده از آن کافی است به ابتدای متد Application_Start فایل Global.asax.cs مراجعه و در ادامه سطر ذیل را اضافه نمود:
پس از آن جزئیات کلیه استثناهای EF در لاگهای نهایی ELMAH به نحو ذیل ظاهر خواهند شد:
کدهای کامل این پروژه را از اینجا میتوانید دریافت کنید:
ElmahEFLogger
کلاس EfExceptionsInterceptor
در اینجا نمونهای از یک پیاده سازی اینترفیس IDbCommandInterceptor را مشاهده میکنید. همچنین طراحی یک متد عمومی که میتواند به جزئیات SQL نهایی و پارامترهای آن دسترسی داشته باشد، در اینترفیس IEfExceptionsLogger ذکر شدهاست.
public interface IEfExceptionsLogger { void LogException<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext); } using System.Data.Common; using System.Data.Entity.Infrastructure.Interception; namespace ElmahEFLogger { public class EfExceptionsInterceptor : IDbCommandInterceptor { private readonly IEfExceptionsLogger _efExceptionsLogger; public EfExceptionsInterceptor(IEfExceptionsLogger efExceptionsLogger) { _efExceptionsLogger = efExceptionsLogger; } public void NonQueryExecuted(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } public void NonQueryExecuting(DbCommand command, DbCommandInterceptionContext<int> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } public void ReaderExecuted(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } public void ReaderExecuting(DbCommand command, DbCommandInterceptionContext<DbDataReader> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } public void ScalarExecuted(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } public void ScalarExecuting(DbCommand command, DbCommandInterceptionContext<object> interceptionContext) { _efExceptionsLogger.LogException(command, interceptionContext); } } }
تهیه یک پیاده سازی سفارشی از IEfExceptionsLogger توسط ELMAH
اکنون که ساختار کلی IDbCommandInterceptor سفارشی برنامه مشخص شد، میتوان پیاده سازی خاصی از آنرا جهت استفاده از ELMAH به نحو ذیل ارائه داد:
using System; using System.Data.Common; using System.Data.Entity.Infrastructure.Interception; using Elmah; namespace ElmahEFLogger.CustomElmahLogger { public class ElmahEfExceptionsLogger : IEfExceptionsLogger { /// <summary> /// Manually log errors using ELMAH /// </summary> public void LogException<TResult>(DbCommand command, DbCommandInterceptionContext<TResult> interceptionContext) { var ex = interceptionContext.OriginalException; if (ex == null) return; var sqlData = CommandDumper.LogSqlAndParameters(command, interceptionContext); var contextualMessage = string.Format("{0}{1}OriginalException:{1}{2} {1}", sqlData, Environment.NewLine, ex); if (!string.IsNullOrWhiteSpace(contextualMessage)) { ex = new Exception(contextualMessage, new ElmahEfInterceptorException(ex.Message)); } try { ErrorSignal.FromCurrentContext().Raise(ex); } catch { ErrorLog.GetDefault(null).Log(new Error(ex)); } } } }
استفاده از ElmahEfExceptionsLogger جهت طراحی یک Interceptor عمومی
public class ElmahEfInterceptor : EfExceptionsInterceptor { public ElmahEfInterceptor() : base(new ElmahEfExceptionsLogger()) { } }
DbInterception.Add(new ElmahEfInterceptor());
پس از آن جزئیات کلیه استثناهای EF در لاگهای نهایی ELMAH به نحو ذیل ظاهر خواهند شد:
کدهای کامل این پروژه را از اینجا میتوانید دریافت کنید:
ElmahEFLogger
نظرات اشتراکها
پیاده سازی ساده Google Recaptcha در ASP.NET MVC
یک راه دیگر :
public static class AsyncHelper { private static readonly TaskFactory _taskFactory = new TaskFactory(CancellationToken.None, TaskCreationOptions.None, TaskContinuationOptions.None, TaskScheduler.Default); public static TResult RunSync<TResult>(Func<Task<TResult>> func) => _taskFactory .StartNew(func) .Unwrap() .GetAwaiter() .GetResult(); public static void RunSync(Func<Task> func) => _taskFactory .StartNew(func) .Unwrap() .GetAwaiter() .GetResult(); }
نحوه استفاده
AsyncHelper.RunSync(() => client. IsAcceptAsync ( response , secretkey ));
گشتم پیدا کردم. اینترفیس IParbadOptionsProvider با اینترفیس IGatewayAccountSource جایگزین شدهاست. لطفا آموزش بالا را هم آپدیت بفرمایید. من همچین چیزی پیاده سازی کردم:
public class MellatAccountProvider : IGatewayAccountSource<MellatGatewayAccount> { private readonly ParbadMellatSettings _settingsService; public MellatAccountProvider(ParbadMellatSettings settingsService) { _settingsService = settingsService; } public async Task AddAccountsAsync(IGatewayAccountCollection<MellatGatewayAccount> accounts) { // var settings = _settingsService.TerminalId(); accounts.Add(new MellatGatewayAccount { TerminalId = _settingsService.TerminalId, UserName = _settingsService.UserName, UserPassword = _settingsService.UserPassword }); }
یک نکتهی تکمیلی: چگونه برنامههای ASP.NET Core را به صورت دستی ریاستارت کنیم؟
با توجه به چندسکویی بودن ASP.NET Core، برای نمونه در لینوکس، تغییراتی مانند تغییر در web.config، سبب ریاستارت برنامه نمیشوند. در این حالت برای بارگذاری تغییرات، میتوان از روش دستی ریاستارت برنامه استفاده کرد:
[Authorize(Roles = "Admin")] public class AdminController : Controller { private readonly IApplicationLifetime _applicationLifetime; public AdminController(IApplicationLifetime appLifetime) { _applicationLifetime = appLifetime; } public IActionResult Shutdown() { _applicationLifetime.StopApplication(); return Content("Done"); } }
معادل مطلب «Lazy loading در تزریق وابستگیها به کمک StructureMap» در ASP.NET Core
ابتدا سرویس مدنظر به صورت معمولی ثبت میشود و سپس نمونهی Lazy آن بر اساس این سرویس تعریف خواهد شد.
اکنون امکان تعریف و تزریق این سرویس به صورت Lazy در سازندهی کنترلرها وجود خواهد داشت:
public void ConfigureServices(IServiceCollection services) { // ... services.AddScoped<IEmailService, EmailService>() .AddScoped(x => new Lazy<IEmailService>(() => x.GetRequiredService<IEmailService>())); // ... }
اکنون امکان تعریف و تزریق این سرویس به صورت Lazy در سازندهی کنترلرها وجود خواهد داشت:
public class EmailController : Controller { private readonly Lazy<IEmailService> _emailService; public EmailController(Lazy<IEmailService> emailService) { _emailService = emailService; }
دلال یا Middle man در دسته الگوهای «کدهایی بیش از اندازه وابسته به هم» قرار میگیرد. زمانیکه یک کلاس، تنها کاری را که انجام میدهد، هدایت فراخوانی به کلاس دیگری باشد، با این الگو مواجه هستیم. تشخیص این کد بد بو معمولا بسیار آسان است.
به طور مثال:
public class ProductQuery { public dynamic GetProductsByCustomerId(int id) { return new ExpandoObject(); } } public class CustomerQuery { private readonly ProductQuery _productQuery; public CustomerQuery(ProductQuery productQuery) { _productQuery = productQuery; } public dynamic GetProducts(int customerId) { return _productQuery.GetProductsByCustomerId(customerId); } } public static class Programm { static void Main(string[] args) { var query = new CustomerQuery(new ProductQuery()); var products = query.GetProducts(1); } }
در کلاس ProductQuery، متدی برای دریافت تمامی محصولات مربوط به یک مشتری وجود دارد. در کلاس CustomerQuery نیز یک متد برای دریافت تمامی محصولات مشتری وجود دارد. در این مثال متد GetProducts در کلاس CustomerQuery را میتوان «متد حسود» نیز نامید. این نوع استفاده از متد، «الگوی دلال» نیز است. زمانیکه تمامی متدهای یک کلاس به این صورت باشند، آن کلاس به عنوان دلال شناخته میشود.
چرا چنین بویی به راه میافتد
معمولا به چند دلیل با این کد بد بو مواجه خواهیم شد:
- انتقال مسئولیتهای یک کلاس به کلاسی دیگر به مرور زمان و تبدیل متدهای آن به هدایت کنندگان فراخوانی.
- عدم تشخیص درست مسئولیتهای یک کلاس و اجبار به افزودن هدایت کنندگان فراخوانی در کلاسهای دیگر. این حالت معمولا زمانی اتفاق میافتد که یک کلاس، مسئولیتهای زیادی داشته باشد و کلاسهای مختلف، صرفا نیاز به هدایت فراخوانی به این کلاس را داشته باشند.
- عدم استفاده مناسب از الگوهای طراحی.
روشهای اصلاح این کد بد بو
روش کلی برای اصلاح چنین بوی بدی، حذف متدها و کلاسهای هدایت کننده فراخوانی و تغییر تمامی استفاده کنندگان از آنها است. در مثال بالا میتوان متد GetProducts از کلاس CustomerQuery را حذف و تمامی فراخوانیهای آن را به متد GetProductsByCustomerId از کلاس ProductQuery انتقال داد، یا بلعکس.
چه کدهایی دلال نیستند
زمانیکه کلاس هدایت کننده فرخوانی به صورت عمدی ساخته شده باشد، معمولا با چنین الگویی روبرو نیستیم. مانند استفاده از الگوهای طراحی زیر:
- Chain of responsibility
- Decorator
- Proxy
- Adapter
هر کدام از الگوهای طراحی ذکر شده در بالا به دلایل خاصی ایجاد میشوند و علارغم شباهت زیاد آنها با کد بد بوی دلال، شرایط مربوط به کد بد بود را دارا نمیباشند و معمولا نیازی به اعمال تغییری در آنها نیست. با مطالعه و بررسی دقیق الگوهای طراحی میتوان از تشخیص اشتباه این الگوی بد جلوگیری کرد.