نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 5 - فعال سازی صفحات مخصوص توسعه دهنده‌ها
یک نکته‌ی تکمیلی
شبیه سازی customErrors در نگارش‌های دیگر ASP.NET که در فایل web.config قابل تنظیم است:
<customErrors mode="On" defaultRedirect="error">
        <error statusCode="404" redirect="error/notfound" />
        <error statusCode="403" redirect="error/forbidden" />
</customErrors>
در ASP.NET Core چنین شکلی را پیدا می‌کند. ابتدا در متد Configure کلاس آغازین برنامه، میان افزارهای مطلب فوق را اضافه می‌کنیم:
        public void Configure(IApplicationBuilder app)
        {
            if (env.IsDevelopment())
            {
                app.UseDatabaseErrorPage();
                app.UseDeveloperExceptionPage();
            }
            app.UseExceptionHandler("/error/index/500");
            app.UseStatusCodePagesWithReExecute("/error/index/{0}");
در اینجا ذکر مسیر کامل اکشن متد Index و کنترلر Error ضروری هستند. سپس این کنترلر چنین محتوایی را خواهد داشت:
    public class ErrorController : Controller
    {
        private readonly ILogger<ErrorController> _logger;

        public ErrorController(ILogger<ErrorController> logger)
        {
            _logger = logger;
        }

        public IActionResult Index(int? id)
        {
            var logBuilder = new StringBuilder();

            var statusCodeReExecuteFeature = HttpContext.Features.Get<IStatusCodeReExecuteFeature>();
            logBuilder.AppendLine($"Error {id} for {Request.Method} {statusCodeReExecuteFeature?.OriginalPath ?? Request.Path.Value}{Request.QueryString.Value}\n");

            var exceptionHandlerFeature = this.HttpContext.Features.Get<IExceptionHandlerFeature>();
            if (exceptionHandlerFeature?.Error != null)
            {
                var exception = exceptionHandlerFeature.Error;
                logBuilder.AppendLine($"<h1>Exception: {exception.Message}</h1>{exception.StackTrace}");
            }

            foreach (var header in Request.Headers)
            {
                var headerValues = string.Join(",", value: header.Value);
                logBuilder.AppendLine($"{header.Key}: {headerValues}");
            }
            _logger.LogError(logBuilder.ToString());

            if (id == null)
            {
                return View("Error");
            }

            switch (id.Value)
            {
                case 401:
                case 403:
                    return View("AccessDenied");
                case 404:
                    return View("NotFound");

                default:
                    return View("Error");
            }
        }
    }
- در اینجا اگر UseExceptionHandler فعال شده باشد، امکان دسترسی به سرویس IExceptionHandlerFeature خواهد بود.
- و اگر UseStatusCodePagesWithReExecute فعال شده باشد، سرویس IStatusCodeReExecuteFeature اطلاعات مسیر اصلی درخواستی را ارائه می‌دهد.
- سپس بر اساس id ارسالی به این اکشن متد می‌توان برای مثال صفحه‌ی 404 (یافت نشد) و یا سایر صفحات دلخواه دیگری را به صورت انتخابی نمایش داد.
مطالب
Performance در AngularJS قدم پنجم
در این مقاله موضوعی را مطرح خواهم کرد که شاید برای خیلی‌ها این نوع کد نویسی خوشایند نباشد. حتی برای خود من هم خوشایند نیست؛ ولی نهایتا در بهبود Performance تاثیر خیلی زیادی دارد. به کد زیر دقت کنید.
<div ng-repeat="item in items">
     <div ng-if="setting.header">{{item.header}}</div>
     <div>{{item.title}}</div>
     <div ng-if="setting.footer">{{item.footer}}</div>
</div>
توضیح کد: فرض کنید سناریوی پروژه ما به این صورت هست که ما یک لیست داریم، شامل 3 فیلد که header، title و footer را در تنظیمات می‌توانیم مشخص کنیم که header و footer در شرایطی نمایش داده شود و در شرایطی نمایش داده نشود و یا حالت‌های دیگر. 

خوب مشکل چیست و راهکار چیست؟
فرض کنید لیست ما شامل 100 رکورد هست و در تنظیمات مشخص کرده‌ایم که header نمایش داده شود و footer نمایش داده نشود. اما اتفاقی بدی که میفتد این است که وقتی لیست در View ساخته می‌شود، 100 بار ng-if مربوط به header و footer چک میشود؛ در جمع 200 بار می‌شود. چه این مقادیر true باشند چه false فرقی نمی‌کند و 200 بار بررسی می‌شود.
راهکار این مشکل به این صورت است که ما باید از ng-if داخل ng-repeat استفاده نکنیم. اما برای پیاده سازی تنظیمات باید ng-if‌ها را قبل از ng-repeat بررسی کنیم. پس مسلما ng-repeatها باید قالب پیش بینی کرده ما را نسبت به ng-if‌ها درست کند. نتیجه‌ی کار به صورت کد زیر است که شاید برای شما هم خوشایند نباشد:
<div ng-if="setting.header && setting.footer">
     <div ng-repeat="item in items">
          <div>{{item.header}}</div>
          <div>{{item.title}}</div>
          <div>{{item.footer}}</div>
     </div>
</div>
<div ng-if="setting.header && setting.footer==false">
     <div ng-repeat="item in items">
          <div>{{item.header}}</div>
          <div>{{item.title}}</div>      
     </div>
</div>
<div ng-if="setting.header==false && setting.footer">
     <div ng-repeat="item in items">         
          <div>{{item.title}}</div>   
          <div>{{item.footer}}</div>   
     </div>
</div>
<div ng-if="setting.header==false && setting.footer==false">
     <div ng-repeat="item in items">         
          <div>{{item.title}}</div>                
     </div>
</div>
درست است من هم با شما موافق هستم که خوشایند نیست. در این کد ما همه‌ی حالت‌ها را پیش بینی و قالب مناسب هر شرط را درست کرده‌ایم. حجم کد چند برابر شده، ولی از لحاظ Performance در ساخت لیست در View در حد 98% بهبود پیدا کرده‌است. همان مثال قبلی را در نظر بگیرید. ng-if مربوط به header و footer در این کد فقط 4 بار بررسی می‌شود. چه 100 رکورد باشد، چه 1000 تا، چه 10 تا رکورد. 
در مورد ng-repeat‌ها هم نگران نباشید فقط یک بار اجرا میشوند. اگر کارکرد ng-if را در مقاله‌ی قبلی من ، خوانده باشید، متوجه‌ی این موضوع می‌شوید که element‌های داخلی و direction‌های AngularJS داخلی ng-if زمانی پردازش می‌شوند که شرط true باشد. از این روش زمانی استفاده کنید که تعداد داده‌ها و حالت‌های زیادی دارید و Performance اهمیت بیشتری دارد. امیدوارم مقاله‌ی مفیدی باشد.
بازخوردهای دوره
انتقال خودکار Data Annotations از مدل‌ها به ViewModelهای ASP.NET MVC به کمک AutoMapper
بخش تزریق وابستگی به خوبی کار میکند اما بخش انتقال خودکار Data Annotations عمل نمی‌کند و انتقال صورت نمی‌گیرد. علیرغم اینکه تمام بخش‌های آن اجرا می‌شود.
توالی کدهای مربوط در global.asax بصورت زیر است:
setDbInitializer();
ModelMetadataProviders.Current = new MappedMetadataProvider(Mapper.Engine.ConfigurationProvider);
var modelValidatorProvider = ModelValidatorProviders.Providers
      .Single(provider => provider is DataAnnotationsModelValidatorProvider);
ModelValidatorProviders.Providers.Remove(modelValidatorProvider);
ModelValidatorProviders.Providers.Add(new MappedValidatorProvider(Mapper.Engine.ConfigurationProvider));
بازخوردهای دوره
تزریق خودکار وابستگی‌ها در برنامه‌های ASP.NET MVC
ممنون؛ مراحل رو به این صورت انجام دادم :
static void InitStructureMap()
{
            ObjectFactory.Initialize(x =>
            {
                x.For<IUnitOfWork>().HybridHttpOrThreadLocalScoped().Use<MyContext>();
                x.Scan(scan =>
                {
                    scan.AssemblyContainingType<INewsService>();
                    scan.WithDefaultConventions();
                });
                
            });

            ControllerBuilder.Current.SetControllerFactory(new StructureMapControllerFactory());
            var container = ObjectFactory.Container;
            GlobalConfiguration.Configuration.Services
                .Replace(typeof(IHttpControllerActivator),
                new StructureMapHttpControllerActivator(container));
            
}
پیاده سازی StructureMapHttpControllerActivator به همان صورت که در لینک معرفی کردید انجام دادم.
ممنون از شما.
نظرات مطالب
رمزنگاری خودکار فیلدها توسط Entity Framework Core
 var encryptedConverter = new ValueConverter<string, string>(
               convertToProviderExpression: v => v, // How to save it: Do nothing --> Save it normally in the DB
               convertFromProviderExpression: v => new string(v.Reverse().ToArray()) // How to report it: Show it encrypted to the user
            );
نظرات مطالب
الگویی برای مدیریت دسترسی همزمان به ConcurrentDictionary
با وجود lazy بودن هم چندین بار امتحان کردم قسمت آپدیت آن فر اخوانی نمی‌شود و همچنان مثل قبل کلیدهای مشابه و تکراری را تولید می‌کند.
 var result = _properties.AddOrUpdate(key
                  k =>
                  {
                      Console.WriteLine("AddValueFactory called for " + k);
                      return new Lazy<int>(() => 1);
                  },
                  (x, y) =>
                  {
                      Console.WriteLine("updateValueFactory called for " + key);
                      return new Lazy<int>(() => y.Value + 1);
                  }).Value;

نظرات مطالب
کارهایی جهت بالابردن کارآیی Entity Framework #3
من EFInteractiveViews رو از nuget نصب کردم.
کد
 using (var ctx = new MyContext())
{
    InteractiveViews
        .SetViewCacheFactory(
            ctx, 
            new FileViewCacheFactory(@"C:\MyViews.xml"));
}

رو هم توی Global.asax متد Application_Start پروژه MVC گزاشتم.
فایل MyViews.xml هم ساخته شد ولی فرق زیادی در سرعت به وجود نیامد.
1) آیا باید حتما تعداد کلاسهای پوکو زیاد باشد؟
2) هر بار که برنامه استارت میشه آیا این فایل ویو ساخته میشه؟ اگر میشه این خودش زمانبر نیست؟ 
نظرات مطالب
jQuery Ajax و نحوه صحیح ارسال مقادیر به یک وب سرویس
من کد زیر رو ارسال می‌کنم ولی مشکلی که وجود داره این هست که نه پارمترها ارسال میشه و نه درخواست آژاکسی هست.صفحه رو واقعا هدایت میکنه به آدرس مورد نظر.
//new group
    $("#NewGroup").on('click', function () {
        var catName = 'new';// $("#appendNodeText").val();
        $.ajax({
            dataType: "json",
            type: "POST",
            url: "@Url.Action(MVC.Categories.NewCategory())",
            data: { name: catName }

        }).done(function (data) {
            alert(data);
        });
    });
نظرات مطالب
اختصاصی کردن Razor برای #C در MVC با استفاده از Extension Method
طبق مطالعات بنده روی سورس MVC خوشبختانه تمامی ViewEngine‌های ارائه شده توسط این FrameWork از کلاس VirtualPathProviderViewEngine  مشتق شدن ، این کلاس Lookuping ویو هارو عهده دار هست. برای اینکه ما جلوی Lookuping پسوند vbhtml رو بگیریم کافیه در هنگام تعریف ViewEngine به صورت زیر بنویسیم :
protected void Application_Start()
{
ViewEngines.Engines.Clear();
var veiwEngine = new RazorViewEngine();
veiwEngine.FileExtensions = new string[] { "cshtml" };
ViewEngines.Engines.Add(veiwEngine);
....
}
نظرات مطالب
انتخاب پویای فیلد ها در LINQ
با سلام؛ با ایجاد ستون ردیف با Select new در LINQ مشکل دارم. طوریکه بصورت اتوماتیک یک ستون ردیف ایجاد نماییم:

var all = (from x in db.tblZones
select new
{
  RowNuber=????????????
  Code = x.xCode,
  Caption = x.xCaption,
  Comment = x.xComments,
  DT_RowId = "tr" + x.xCode.ToString(),

});