اشتراک‌ها
NET 7 Preview 4. منتشر شد

The fourth preview of .NET 7 includes enhancements to observability in the .NET implementation of OpenTelemetry, the addition of properties to track microseconds and nanoseconds in date and time structures, new metrics for caching extensions, performance-boosting “on stack replacement,” APIs to work with .tar archives, and additional features as part of an ongoing effort to improve the performance of and add features to regular expressions in .NET 7.  

NET 7 Preview 4. منتشر شد
اشتراک‌ها
Try catch در C# 6.0
Visual Basic developers can put conditions on a catch block in a try...catch to control which catch block is executed when an error occurs. With C# 6.0, C# developers can now do the same by adding a if test to the catch statement. 
Try catch در C# 6.0
نظرات مطالب
استفاده از Interop.word برای جایگزین کردن مقادیر در تمامی فایل (Footer - Header - ... )
سلام؛ من ازهمین روش شما استفاده کردم چند وقت پیش به وسیله  bookmark:
        private Document oDoc;
        public void createdoc1()
        {
            var realpath="~/template";
            var filePath = Path.Combine(HttpContext.Current.Server.MapPath("~/template"), Lcourseid.Text + ".doc");
            var oWordApplication = new Application();
            DirectoryInfo dir = new DirectoryInfo(Server.MapPath(realpath));
            foreach (FileInfo files in dir.GetFiles())
            {
                files.Delete();
            }
            // To invoke MyMethod with the default argument value, pass  
            // Missing.Value for the optional parameter.
            object missing = System.Reflection.Missing.Value;

            //object fileName = ConfigurationManager.AppSettings["DocxPath"];@"C:\DocXExample.docx";
            string fileName = @"D:\template1.dot";
            //string fileName1 = @"D:\sss.doc";
            object newTemplate = false;

 object docType = 0;
            object isVisible = true;

            //System.Reflection.Missing.Value is used here for telling that method to use default parameter values when method execution
            oDoc = oWordApplication.Documents.Open(fileName, newTemplate, docType, isVisible, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing,
                ref missing, ref missing, ref missing, ref missing, ref missing, ref missing);
           // usable in earlier versions of Microsoft Word v2003  v11
          //  if(Convert.ToInt16(oWordApplication.Version) >=11)
            {
             //Sets or returns a Boolean that represents whether a document is being viewed in reading layout view.
              oDoc.ActiveWindow.View.ReadingLayout = false;
           }

            //The active window is the window that currently has focus.If there are no windows open, an exception is thrown.
            //microsoft.office.tools.word.
            oDoc.Activate();

            if (oDoc.Bookmarks.Exists("Title"))
            {
                oDoc.Bookmarks["Title"].Range.Text = "Test Field Entry from webform";
                oDoc.Bookmarks["Address"].Range.Text = "Address Field Entry from webform";
            }

            oDoc.SaveAs(filePath, ref missing);
            oWordApplication.Documents.Close(ref missing, ref missing, ref missing);
            //oWordApplication.Quit(ref SaveChanges, ref missing, ref missing, ref missing);
            ProcessRequest(filePath, Lcourseid.Text);
ولی این روش مشکلاتی هم داره. اول اینکه باید روی سرور تنظیمات خاصی رو انجام بدی. البته از تنظیمات منظور تنظیمات دسترسی کاربران هست. ولی استفاده از داک ایکس بیشتر استقبال میشه چون دردسرش کمتره.
اشتراک‌ها
انتشار SQL Server 2016 CTP 3.1

New In-Memory OLTP improvements in CTP3.1 include:

  • Unique indexes in memory-optimized tables, to complement the support for unique constraints that was released in CTP3
  • LOB data types varchar(max), nvarchar(max), and varbinary(max) in memory-optimized tables and natively compiled modules
  • Indexes with NULLable key columns in memory-optimized tables

Syntax inputdate AT TIME ZONE timezone.

  • Inputdate: An expression that can be resolved to a smalldatetime, datetime, datetime2, or datetimeoffset value.
  • Timezone: Name of the destination time zone in standard format as enumerated by Windows. Available time zones can be found by querying sys.time_zone_info.

SQL Server Analysis Services (SSAS) updates allow upgrading your existing models to 1200 compatibility level and a JSON editor for SSDT;

SQL Server PowerPivot and Reporting Services/Power View for SharePoint 2016 available now with CTP3.1!
انتشار SQL Server 2016 CTP 3.1
اشتراک‌ها
Visual Studio 2019 version 16.1.2 منتشر شد
Visual Studio 2019 version 16.1.2 منتشر شد
اشتراک‌ها
Clean Code عبارات منطقی

The most important thing I learn in 2015 is that clean code is everything. You can have bad performance or logical errors or even security issues. 

But without clean code you cannot fix anything above, because you don't understand the code. 

Clean Code عبارات منطقی
نظرات مطالب
پیاده سازی CQRS توسط MediatR - قسمت دوم
بهتره در CQRS برای افزایش کارایی، قابلیت مقیاس پذیری و امنیت، از دو تا دیتابیس استفاده بشه 

The query model for reading data and the update model for writing data can access the same physical store, perhaps by using SQL views or by generating projections on the fly. However, it's common to separate the data into different physical stores to maximize performance, scalability, and security, as shown in the next figure. 
مطالب
میان‌افزار جدید Authorization در ASP.NET Core 3.0
در نگارش‌های اولیه‌ی ASP.NET Core، پشتیبانی از authorization، صرفا توسط ویژگی [Authorize]، قابل اعمال به اکشن متد خاصی بود. برای بهبود تنظیم این قابلیت، میان‌افزار جدید Authorization به ASP.NET Core 3.0 اضافه شده‌است و تنظیم آن جهت کار با امکانات امنیتی برنامه، الزامی است؛ در غیر اینصورت در حین مرور این صفحات و قسمت‌های محافظت شده، برنامه با خطای زیر متوقف خواهد شد:
Endpoint xyz contains authorization metadata, but a middleware was not found that supports authorization.
Configure your application startup by adding app.UseAuthorization() inside the call to Configure(..) in the application startup code.


محل صحیح تعریف میان‌افزار Authorization در ASP.NET Core 3.0

توصیه شده‌است میان‌افزار جدید Authorization، با فراخوانی متد UseAuthorization، بلافاصله پس از فراخوانی متد UseAuthentication معرفی شود. در این حالت این میان‌افزار، با یک Policy پیش‌فرض تنظیم می‌شود که قابل تغییر و بازنویسی است:
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}
در مورد مفهوم متد MapDefaultControllerRoute، می‌توانید به نظرات تکمیلی مطلب Endpoint routing مراجعه کنید.
در ASP.NET Core 3.0، پس از تنظیمات فوق است که قطعه کد زیر و اعمال فیلتر Authorize، مجددا کار می‌کند:
public class HomeController : ControllerBase
{
    [Authorize]
    public IActionResult BuyWidgets()
    {
        ...
    }
}


روش تعریف فیلتر Authorize به صورت سراسری در ASP.NET Core 3.0

می‌توان AuthorizeFilter را به صورت یک فیلتر سراسری (global filter in MVC) تعریف کرد تا به تمام کنترلرها و اکشن متدها اعمال شود. هرچند این روش هنوز هم در ASP.NET Core 3.0 کار می‌کند، اما روش توصیه شده‌ی جدید آن به صورت زیر است:
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute().RequireAuthorization();
    });
}
در این حالت با اعمال RequireAuthorization به MapDefaultControllerRoute، سبب خواهیم شد تا اعتبارسنجی کاربر برای استفاده‌ی از تمام قسمت‌های برنامه، اجباری شود. در این بین اگر کنترلری و یا اکشن متدی نباید محافظت شود و دسترسی آزادانه‌ی به آ‌ن‌ها مدنظر است، می‌توان از فیلتر AllowAnonymous استفاده کرد:
[AllowAnonymous]
public class HomeController : ControllerBase
{
    ...
}


سفارشی سازی سیاست‌های Authorization در ASP.NET Core 3.0

اگر بخواهیم DefaultPolicy میان‌افزار Authorization را بازنویسی کنیم، می‌توان از متد services.AddAuthorization به صورت زیر استفاده کرد که در آن authentication و داشتن یک Scope خاص را اجباری می‌کند:
public void ConfigureServices(IServiceCollection services)
{
    ...
    
    services.AddAuthorization(options =>
    {
        options.DefaultPolicy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .RequireScope("MyScope")
          .Build();
    });
}


تنظیم سیاست‌های دسترسی، زمانیکه هیچ نوع تنظیمی از پیش تعریف نشده‌است

با تنظیم FallbackPolicy، می‌توان تمام endpointهایی را که توسط فیلتر [Authorize] و یا ()RequireAuthorization محافظت نشده‌اند، محافظت کرد.
DefaultPolicy توسط فیلتر [Authorize] و یا ()RequireAuthorization مورد استفاده قرار می‌گیرد؛ اما FallbackPolicy زمانی بکار خواهد رفت که هیچ نوع سیاست دسترسی تنظیم نشده‌باشد. حالت پیش‌فرض FallbackPolicy، پذیرش تمام درخواست‌ها بدون اعتبارسنجی است.
کارکرد مثال زیر با مثال‌های قبلی که از DefaultPolicy استفاده می‌کردند، یکی است و هدف آن، اجبار به اعتبارسنجی کاربران در همه‌جا (تمام endpoints)، منهای مواردی است که از فیلتر AllowAnonymous استفاده می‌شود:
public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthorization(options =>
    {
        options.FallbackPolicy = new AuthorizationPolicyBuilder()
          .RequireAuthenticatedUser()
          .RequireScope("MyScope")
          .Build();
    });
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

[AllowAnonymous]
public class HomeController : ControllerBase
{
}


امکان اعمال سفارشی میان‌افزار Authorization به Endpointهای مجزا

برای مثال در مبحث «بررسی سلامت برنامه»، فریم‌ورک، اعتبارسنجی درخواست‌های آن‌را پیش بینی نکرده‌است؛ اما اینبار می‌توان اعتبارسنجی را به endpoint آن اعمال کرد:
public void Configure(IApplicationBuilder app)
{
    ...

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints
            .MapHealthChecks("/healthz")
            .RequireAuthorization(new AuthorizeAttribute(){ Roles = "admin", });
    });
}
همانطور که مشاهده می‌کنید، در اینجا RequireAuthorization، به صورت سفارشی به یک endpoint خاص اعمال شده‌است و تنظیمات آن، با تنظیمات سایر قسمت‌های برنامه یکی نیست.
نظرات مطالب
مدیریت فایلهای یک پروژه نرم افزاری با استفاده از Subversion
بله. در قسمت استفاده از tortoisesvn در کتابچه فوق، نحوه‌ی صحیح move کردن فایل‌ها با تصویر توضیح داده شده است.
یا اگر نیاز به توضیحات بیشتری بود به مقاله زیر رجوع کنید (که همان روش فوق را توضیح داده است):
http://www.lostechies.com/blogs/joshua_lockwood/archive/2007/09/12/subversion-tip-of-the-day-moving-files.aspx
مطالب
تزریق وابستگی‌ها در ASP.NET Core - بخش 2 - ثبت اولین سرویس
یک پروژه‌ی ASP.NET Core را با قرار دادن نسخه‌ی NET Core. بر روی 3.1 و با استفاده از قالب Model View Controller ایجاد کنید. در اینجا نام پروژه را AspNetCoreDependencyInjection گذاشته‌ام. حالا در  پوشه‌ی Models، فایلی را با نام HomeViewModel.cs با محتویاتی به صورت زیر اضافه کنید:
public class HomeViewModel
{
     public string Id { get; set; }
     public string Message { get; set; }
     public DateTime DateTime { get; set; }
}

اکنون به پوشه‌ی Views بروید و فایل Index.cshtml را به این صورت تغییر دهید:

@model AspNetCoreDependencyInjection.Models.HomeViewModel
@{
ViewData["Title"] = "Home";
}

<div>
<div>
<div>
<p>
<b>Id : </b><span>@Model.Id</span> <br />
<b>Date And Time : </b><span> @Model.DateTime </span> <br/>
<b>Message : </b><span>@Model.Message</span>
</p>
</div>
</div>
</div>
و فایل MessageServiceA.cs را به پروژه اضافه کنید:
using AspNetCoreDependencyInjection.Services;

namespace AspNetCoreDependencyInjection.ServicesImplentaions
{
    public class MessageServiceAA 
    {
        public string Message()
        {
            return "A message from MessageServiceAA";
        }
    }
}
و همچنین فایل GuidHelper.cs را نیز اضافه می‌کنیم:
namespace AspNetCoreDependencyInjection.Helpers
{
    public class GuidProvider
    {
        private readonly Guid _serviceGuid;

        public GuidProvider()
        {
            _serviceGuid = Guid.NewGuid();
        }

        public Guid GetNewGuid() => Guid.NewGuid();

        public string GetGuidAsFormatedString(string prefix = "") => getFormatedGuid(_serviceGuid, prefix);

        private string getFormatedGuid(Guid guid, string prefix = "")
        {
            var guidString = guid.GetHashCode().ToString("x");
            if (string.IsNullOrEmpty(prefix) == false)
                guidString = new StringBuilder($"{prefix}-").Append(guidString).ToString();
            return guidString;
        }
    }
}

حالا درون کنترل HomeController، این تغییرات را انجام می‌دهیم:

private readonly ILogger<HomeController> _logger;
private readonly MessageServiceAA _messageService;
private readonly GuidProvider _ guidProvider;

public HomeController(ILogger<HomeController> logger)
{
            _logger = logger;
            _messageService = new MessageServiceAA();
            _guidProvider = new GuidProvider();
}

public IActionResult Index()
{
            var model = new HomeViewModel()
            {
                Id = _ guidProvider.GetGuidAsFormatedString(),
                Message = _messageService.Message(),
                DateTime = DateTime.Now,
            };
            return View(model);
}

همانطور که می‌بینید، در کد بالا، کنترلر HomeController، به دو شیء از کلاس‌ها و یا سرویس‌های GuidProvider و MessageServiceAA به صورت مستقیم وابسته شده‌است و با هر تغییری در هر کدام از این سرویسها، باید دوباره کامپایل شود. علاوه بر این اگر بخواهیم پیاده سازی‌های مختلفی را برای هر کدام از این موارد، ارائه دهیم، به مشکل بر می‌خوریم. خب بیاید تغییراتی را در کد بالا بدهیم تا مشکلات ذکر شده را حل کنیم.

برای این منظور پوشه‌ای را به نام Services می‌سازیم و اینترفیسی را به نام IMessageBrokerA ایجاد می‌کنیم و سپس کاری می‌کنیم که MessageServiceAA از این اینترفیس ارث بری کند:

namespace AspNetCoreDependencyInjection.Services
{
    public interface IMessageServiceA
    {
        string Message();
    }
}

و حالا می‌خواهیم با استفاده از تزریق وابستگی، وابستگی کنترلر HomeController را از کلاس MessageBrokerAA لغو کرده و آن را به اینترفیس IMessageBrokerA (انتزاع) وابسته کنیم. در اینجا ما از تکنیک تزریق درون سازنده یا Constructor Injection استفاده می‌کنیم.


تزریق درون سازنده

در این تکنیک، ما لیستی از وابستگی‌های مورد نیاز را به عنوان پارامترهای ورودی سازنده‌ی کلاس، تعریف می‌کنیم:
private readonly ILogger<HomeController> _logger;
private readonly IMessageServiceA _messageService;
private readonly GuidProvider _guidHelper;
public HomeController(ILogger<HomeController> logger , IMessageServiceA messageService)
{
        _logger = logger;
        _messageService = messageService;
        _messageService = new MessageServiceAA();
        _guidHelper = new GuidProvider();
}
و حالا اگر برنامه را اجرا کنیم، با خطایی روبه رو می‌شویم که در آن می‌گوید امکان واکشی (Resolve) سرویس‌های مورد نظر وجود ندارد. این خطا به دلیل ثبت نشدن اینترفیس IMessageServiceA و پیاده سازی آن، درون Microsoft Dependency Injection Container است   DI Container‌ها معمولا باید در زمان شروع برنامه، پیکربندی و مقدار دهی شودند، تا در ادامه‌ی چرخه‌ی حیات برنامه، بتوانند سرویس‌ها و اشیاء مورد نیاز را به کلاس‌هایی که نیاز دارند، واکشی و تزریق کنند. اولین مرحله از کار با DI Container‌ها، ثبت کردن سرویس‌ها درون آنهاست.
در ASP.NET Core از IServiceCollection برای ثبت کردن سرویس‌های برنامه‌ی خودمان استفاده می‌کنیم. تمامی سرویس‌هایی را که انتظار داریم توسط DI Container به کلاس‌هایی تزریق شوند، باید درون IServiceCollection ثبت گردند. تمام سرویس‌هایی که به وسیله‌ی IServiceCollection ثبت شده‌اند، پس از ساخته شدن، توسط اینترفیس IServiceProvider قابل واکشی هستند.

بنابراین دو اینترفیس حیاتی برای کار کرد صحیح Microsoft Dependency Injection Container درون ASP.NET Core وجود دارند:
  • IServiceCollection : برای ثبت سرویس‌ها
  • IServiceProvider : برای واکشی سرویس‌ها

در ASP.NET Core معمول‌ترین مکان برای ثبت کردن سرویس‌ها درون Container، به صورت پیش فرض درون کلاس Startup و درون متد ConfigureServices انجام می‌گیرد.
به صورت پیش فرض کلاس Startup دو متد دارد:
  • ConfigureServices : برای پیکربندی و ثبت سرویس‌های درونی DI Container استفاده می‌شود.
  • Configure : برای تنظیمات pipeline میان افزارها ( Middlewares ) بکار می‌رود.

در اینجا پیاده سازی پیش فرض کلاس Startup را می‌بینیم که البته کدهای درون متد Configure را برای درگیر نکردن ذهن شما، مخفی کرده‌ایم: 
public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            //  کدها جهت خوانایی بیشتر مخفی شده اند
        }
    }

همانطورکه می‌بینید، متد ConfigureService پارامتر IServiceCollection را می‌گیرد که به وسیله‌ی WebHost در زمان اجرای برنامه، مقدار دهی می‌شود.

تعداد زیادی Extension method برای IServiceCollection وجود دارند که برای پشتیبانی از ثبت کردن سرویس‌های مختلف در سناریوهای گوناگون به کار می‌روند. در اینجا ما از نسخه‌ی 3.1 چارچوب ASP.NET Core استفاده می‌کنیم. برای همین هم برای ثبت سرویس‌های پیش فرض فریمورک MVC از متد توسعه‌ی services.AddControllersWithViews()    استفاده می‌کنیم.  متد توسعه‌ی AddControllersWithViews() سرویس‌هایی را که معمولا در فریم ورک MVC استفاده می‌شوند، درون IServiceCollection ثبت می‌کند. در نسخه‌های قبلی چارچوب ASP.NET Core،  مانند نسخه‌های 2.1 و 2.2 برای این کار از متد توسعه‌ی AddMvc() استفاده می‌شد.

در Microsoft Dependency Injection Container ، معمولا  ترتیب ثبت سرویس‌ها مهم نیست.

خب، اولین سرویس اختصاصی برنامه‌ی خودمان را با چرخه‌ی حیات Transient و زیر سرویس پیشین، به شکل زیر ثبت می‌کنیم :

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            services.AddTransient<IMessageServiceA, MessageServiceAA>();
        }
همانطور که می‌بینید، در اینجا ما از متد AddTransient() استفاده کرده‌ایم. متد AddTransient() درون فضای نام Microsoft.Extensions.DependencyInjection قرار دارد. این متد Overload ‌های گوناگونی دارد و ما از نوعی از آن استفاده کرده‌ایم که دو نوع generic را می‌پذیرد و تعریف آن به صورت زیر است: 
public static IServiceCollection AddTransient<TService, TImplementation>(this IServiceCollection services)
در اینجا TService ، اینترفیس سرویس ماست. این نوع، همان نوعی است که کلاس‌های ما می‌توانند به آن وابسته باشند. پارامتر دوم، از نوع TImplemention است که پیاده سازی مورد نظر برای TService را ثبت می‌کند. TImplmention   نوعی است که Container در زمان واکشی و تزریق TService از آن نمونه سازی کرده و به کلاس مورد نظر تزریق می‌کند.

در اینجا وقتی ما برای IMessageServiceA ، پیاده سازی MessageServiceA را ثبت می‌کنیم، از این به بعد DI Container، هر زمانیکه در لیست پارامترهای سازنده‌ی یک کلاس، IMessageServiceA را مشاهده کند، بررسی می‌کند که چه کلاسی به عنوانی پیاده سازی این اینترفیس ثبت شده‌است، سپس از آن نمونه سازی می‌کند و درون سازنده‌ی مورد نظر تزریق می‌کند. خب، حالا برنامه را دوباره اجرا کنید؛ می‌بینید که برنامه اجرا می‌شود.

 
در ادامه ابتدا در مورد روش‌های مختلف ثبت سرویس‌ها و بعد روش‌های واکشی سرویس‌ها را بررسی می‌کنیم.