اشتراک‌ها
نگاهی به ویژگی‌های Rider

I must say that Rider is pretty impressive. Not only does it offer most features of Visual Studio, even of quite expensive editions, but it even has more.  

نگاهی به ویژگی‌های Rider
مطالب
استفاده از پیاده سازی Katana مربوط به استاندارد Owin در ASP.NET 4.x
قطعا ASP.NET MVC 5.x به عنوان یک فریم ورک بالغ و با امکانات فراوان شناخته میشود که در این مساله هیچ بحثی نیست. اما آیا در همه‌ی پروژه‌ها حتما باید از این فریم ورک استفاده شود؟ امروزه اکثر وب اپلیکیشن‌ها از فریم ورک‌های SPA استفاده میکنند و بنده به وفور در پروژه‌های مختلف شاهد این بوده‌ام که ASP.NET MVCی که در کنار آن استفاده میشود، عملا چیزی بیشتر از یک کنترلر Home و یک متد Index و حداکثر یک Layout، نیستند و معمولا در کنار آن از Web Api استفاده میکنند که حداقل در ASP.NET MVC 5.x چیزی کاملا مجزای از آن به حساب می‌آید. با این حال آیا واقعا از امکانات MVC 5.x استفاده شده است؟! یا فقط اینگونه پروژه‌ها محدودیت‌های MVC را به دوش میکشند؟
در ASP.NET 4.x به صورت معمول ارسال درخواست‌ها بدین صورت است که از سمت کلاینت به IIS و بعد از آن بر روی ISAPI نگاشت میشوند (یا Static File برای فایل‌های استاتیک). پس عملا وابستگی شدیدی به IIS ایجاد شده‌است و اینکه مشکلات این وابستگی چیست در این مقاله نمیگنجد. اگر قرار باشد همین امروز پروژه‌ای شروع شود قطعا ASP.NET 4.x گزینه‌ی معقولی به نظر میرسد؛ اما در پروژه‌های حجیم بیزینسی که باید ماه‌ها و شاید چندین سال بر روی نرم افزار آن کار شود، آیا آن موقع نیز ASP.NET مانند حال گزینه‌ی معقولی است یا بطور مثال ASP.NET Core با امکانات منحصر به فردش جایگزین خواهد شد؟ در نگاه اول وقتی دو پروژه‌ی ASP.NET 4.x و ASP.NET Core را در کنار هم میگذاریم، شاید اختلافات زیاد باشند و ارتقاء نرم افزار به ASP.NET Core سخت و یا حتی غیر ممکن به نظر برسد. اما آیا واقعا هیچ راهی وجود ندارد که هم اکنون نرم افزار خود را با ASP.NET 4.x که کاملا بالغ هم شده شروع کرده و بعد‌ها به ASP.NET Core به روز رسانی شود؟
این‌ها سوال‌هایی است که قطعا قبل از شروع یک پروژه‌ی بزرگ نرم افزاری باید از خود بپرسیم. شاید با نگاه عمیق‌تری بر روی این سوال‌ها بتوان پاسخی مناسب را برای آن‌ها داد. یکی از این راه‌حل‌ها استفاده از استاندارد Owin و پیاده سازی آن به نام Katana است.

برای شروع پروژه ابتدا یک پروژه‌ی ASP.NET 4.x از نوع empty را بسازید.
برای راحت شدن کار، ابتدا packages.config را باز کرده و کد‌های زیر را جایگزین آن نمایید:
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.AspNet.OData" version="6.0.0" targetFramework="net462" />
  <package id="Microsoft.AspNet.SignalR.Core" version="2.2.1" targetFramework="net462" />
  <package id="Microsoft.AspNet.SignalR.Owin" version="1.2.2" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Client" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Core" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.AspNet.WebApi.Owin" version="5.2.3" targetFramework="net462" />
  <package id="Microsoft.CodeDom.Providers.DotNetCompilerPlatform" version="1.0.2" targetFramework="net462" />
  <package id="Microsoft.Extensions.DependencyInjection" version="1.0.0" targetFramework="net462" />
  <package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="1.0.0" targetFramework="net462" />
  <package id="Microsoft.Net.Compilers" version="1.3.2" targetFramework="net462" developmentDependency="true" />
  <package id="Microsoft.OData.Core" version="7.0.0" targetFramework="net462" />
  <package id="Microsoft.OData.Edm" version="7.0.0" targetFramework="net462" />
  <package id="Microsoft.Owin" version="3.0.1" targetFramework="net462" />
  <package id="Microsoft.Owin.FileSystems" version="3.0.1" targetFramework="net462" />
  <package id="Microsoft.Owin.Host.SystemWeb" version="3.0.1" targetFramework="net462" />
  <package id="Microsoft.Owin.Security" version="3.0.1" targetFramework="net462" />
  <package id="Microsoft.Owin.StaticFiles" version="3.0.1" targetFramework="net462" />
  <package id="Microsoft.Spatial" version="7.0.0" targetFramework="net462" />
  <package id="Newtonsoft.Json" version="9.0.1" targetFramework="net462" />
  <package id="Owin" version="1.0" targetFramework="net462" />
  <package id="System.Collections" version="4.0.11" targetFramework="net462" />
  <package id="System.Collections.Concurrent" version="4.0.12" targetFramework="net462" />
  <package id="System.ComponentModel" version="4.0.1" targetFramework="net462" />
  <package id="System.Diagnostics.Debug" version="4.0.11" targetFramework="net462" />
  <package id="System.Globalization" version="4.0.11" targetFramework="net462" />
  <package id="System.Linq" version="4.1.0" targetFramework="net462" />
  <package id="System.Linq.Expressions" version="4.1.0" targetFramework="net462" />
  <package id="System.Reflection" version="4.1.0" targetFramework="net462" />
  <package id="System.Resources.ResourceManager" version="4.0.1" targetFramework="net462" />
  <package id="System.Runtime.Extensions" version="4.1.0" targetFramework="net462" />
  <package id="System.Threading" version="4.0.11" targetFramework="net462" />
  <package id="System.Threading.Tasks" version="4.0.11" targetFramework="net462" />
</packages>
ما پکیج‌های OData و SignlarR , WebApi, Owin را اضافه نموده‌ایم و دستور زیر را برای اضافه شدن ارجاعات اجرا می‌کنیم:
PM>Update-Package -reinstall -Project YourProjectName
اکنون عملا تمام پکیج‌های لازم را برای شروع به کار، در اختیار داریم (اگر از dotNetFrameWork نسخه‌ی پایین‌تری بطور مثال 4.6.1 استفاده میکنید، بعد از اجرای دستور فوق، targetFramework شما به 461 اصلاح خواهد شد).
حال میخواهیم کمی کار اختیاری را نیز بر روی وب کانفیگ انجام دهیم که به performance نرم افزار شما بهبود قابل ملاحظه‌ای را می‌افزاید. کد‌های زیر را در وب کانفیگ جایگزین نمایید:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="owin:AppStartup" value="OwinKatanaTest.OwinAppStartup, OwinKatanaTest" />
    <!-- Owin App Startup Class -->
    <add key="webpages:Enabled" value="false" />
    <!-- Disable asp.net web pages. Note that based on our current configuration, asp.net web forms, mvc and web pages won't work. This configuration is for owin stuffs only, for example asp.net web api & odata, signalr, etc. -->
  </appSettings>
  <system.web>
    <compilation debug="true" defaultLanguage="c#" enablePrefetchOptimization="true" optimizeCompilations="true" targetFramework="4.6.2">
      <assemblies>
        <remove assembly="*" />
        <!-- To improve app startup performance, our app will continue its work without this compilations, these are required for asp.net web forms, mvc and web pages. -->
        <add assembly="OwinKatanaTest" />
      </assemblies>
    </compilation>
    <httpRuntime targetFramework="4.6.2" />
    <httpModules>
      <!-- No need to these modules and handlers, owin handler itself will do everything for us -->
      <clear />
    </httpModules>
    <httpHandlers>
      <clear />
    </httpHandlers>
    <sessionState mode="Off" />
  </system.web>
  <system.codedom>
    <compilers>
      <compiler language="c#;cs;csharp" extension=".cs" type="Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider, Microsoft.CodeDom.Providers.DotNetCompilerPlatform, Version=1.0.2.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" warningLevel="4" compilerOptions="/langversion:6 /nowarn:1659;1699;1701" />
    </compilers>
  </system.codedom>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-9.0.0.0" newVersion="9.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="Microsoft.AspNet.SignalR.Core" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.2.1.0" newVersion="2.2.1.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Reflection" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Http" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
  <system.webServer>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="false">
      <!-- We're not going to remove all modules, some modules such as static & dynamic compression modules are really cool (-: -->
      <remove name="RewriteModule" />
      <remove name="OutputCache" />
      <remove name="Session" />
      <remove name="WindowsAuthentication" />
      <remove name="FormsAuthentication" />
      <remove name="DefaultAuthentication" />
      <remove name="RoleManager" />
      <remove name="FileAuthorization" />
      <remove name="UrlAuthorization" />
      <remove name="AnonymousIdentification" />
      <remove name="Profile" />
      <remove name="UrlMappingsModule" />
      <remove name="ServiceModel-4.0" />
      <remove name="UrlRoutingModule-4.0" />
      <remove name="ScriptModule-4.0" />
      <remove name="Isapi" />
      <remove name="IsapiFilter" />
      <remove name="DigestAuthentication" />
      <remove name="WindowsAuthentication" />
      <remove name="ServerSideInclude" />
      <remove name="DirectoryListing" />
      <remove name="DefaultDocument" />
      <remove name="CustomError" />
      <remove name="Cgi" />
    </modules>
    <defaultDocument>
      <!-- Default docs will be configured using owin static files middleware -->
      <files>
        <clear />
      </files>
    </defaultDocument>
    <handlers>
      <!-- Only use this handler for all requests -->
      <clear />
      <add name="Owin" verb="*" path="*" type="Microsoft.Owin.Host.SystemWeb.OwinHttpHandler, Microsoft.Owin.Host.SystemWeb" />
    </handlers>
    <httpProtocol>
      <customHeaders>
        <clear />
      </customHeaders>
    </httpProtocol>
  </system.webServer>
</configuration>
1) AppSettings برای کانفیگ Owin startup خواهد بود (در ادامه‌ی مقاله آن را مینویسیم).
2) در تگ compilation اسمبلی‌های اضافی را حذف مینماییم (برای بهبود performance از آنجایی که به asp.net web form یا mvc احتیاجی نداریم).
3) حذف http module و http handler در system.web (مربوط به iis 6).
4) در تگ system.codedom کامپایلر مربوط به vb را حذف مینماییم.
5) در تگ system.webserver ماژول‌ها و هندلر‌های اضافی را پاک مینماییم.
6) تگ defaultdocument، به دلیل اینکه از static file مربوط به owin استفاده میکنیم.
7) custom headers‌ها را نیز پاک میکنیم.

بعد از build کردن پروژه، در صورت خطا داشتن از References‌ها، System.Reflection و System.Runtime.Extensions را حذف کنید.
یک ریشه جدید را به نام Model ساخته و مدل‌های آزمایشی Product و Category را که هر دو فقط حاوی دو پراپرتی Id, Name میباشند، به آن اضافه کنید.

در root پروژه یک کلاس به نام OwinAppStartup را با محتوای زیر بسازید
using Microsoft.AspNet.SignalR;
using Microsoft.OData;
using Microsoft.OData.Edm;
using Owin;
using OwinKatanaTest.Model;
using OwinKatanaTest.ODataControllers;
using System.Collections.Generic;
using System.Web.Http;
using System.Web.OData.Builder;
using System.Web.OData.Extensions;
using System.Web.OData.Routing.Conventions;

namespace OwinKatanaTest
{
    public class OwinAppStartup
    {
        public void Configuration(IAppBuilder owinApp)
        {
            owinApp.Map("/odata", innerOwinAppForOData =>
            {
                HttpConfiguration webApiODataConfig = new HttpConfiguration();
                webApiODataConfig.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

                webApiODataConfig.Formatters.Clear();

                IEnumerable<IODataRoutingConvention> conventions = ODataRoutingConventions.CreateDefault();

                ODataModelBuilder modelBuilder = new ODataConventionModelBuilder(webApiODataConfig);

                modelBuilder.Namespace = modelBuilder.ContainerName = "Test";
                var categoriesSetConfig = modelBuilder.EntitySet<Category>("Categories");
                var getBestCategoryFunctionConfig = categoriesSetConfig.EntityType.Collection.Function(nameof(CategoriesController.GetBestCategory));
                getBestCategoryFunctionConfig.ReturnsFromEntitySet<Category>("Categories");

                IEdmModel edmModel = modelBuilder.GetEdmModel();

                webApiODataConfig.MapODataServiceRoute("default", "", builder =>
                {
                    builder.AddService(ServiceLifetime.Singleton, sp => conventions);
                    builder.AddService(ServiceLifetime.Singleton, sp => edmModel);
                });

                innerOwinAppForOData.UseWebApi(webApiODataConfig);

            });

            owinApp.Map("/api", innerOwinAppForWebApi =>
            {
                HttpConfiguration webApiConfig = new HttpConfiguration();
                webApiConfig.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;

                webApiConfig.MapHttpAttributeRoutes();

                webApiConfig.Routes.MapHttpRoute(name: "default", routeTemplate: "{controller}/{action}", defaults: new { action = RouteParameter.Optional });

                innerOwinAppForWebApi.UseWebApi(webApiConfig);
            });

            owinApp.Map("/signalr", innerOwinAppForSignalR =>
            {
                innerOwinAppForSignalR.RunSignalR(new HubConfiguration
                {
                    EnableDetailedErrors = true
                });
            });

            owinApp.UseStaticFiles();

            owinApp.Run(async context =>
            {
                await context.Response.WriteAsync("owin katana");
            });
        }
    }
}
در وب کانفیگ، کار مربوط به استارتاپ را انجام دادیم و دیگر نیازی به قید کردن آن نیست. نگاشت اول، کانفیگ OData، دومی برای web api و همچنین سومی کانفیگ SignalR میباشد.
سپس یک پوشه‌ی جدید را به نام ODataControllers حاوی کلاسی با نام CategoriesController بدین گونه بسازید:
using OwinKatanaTest.Model;
using System.Web.Http;
using System.Web.OData;

namespace OwinKatanaTest.ODataControllers
{
    public class CategoriesController : ODataController
    {
        [HttpGet]
        public Category GetBestCategory()
        {
            return new Category { Id = 1, Name = "Test" };
        }
    }
}
و همچنین یک پوشه دیگر را به نام ApiControllers  به نام ProductsController با محتوای زیر:
using OwinKatanaTest.Model;
using System.Collections.Generic;
using System.Web.Http;

namespace OwinKatanaTest.ApiControllers
{
    public class ProductsController : ApiController
    {
        [HttpGet]
        [Route("products/{categoryId}")]
        public List<Product> GetProductsByCategoryId(int categoryId)
        {
            return new List<Product>
            {
                new Product { Id = 1 , Name = "Test" }
            };
        }
    }
}
حالا میتوانیم یه پروژه‌ی یونیت تست نوشته و کلیات مراحل فوق را تست نماییم. unit test را به پروژه اضافه کنید و reference پروژه‌ی اصلی خود را بدان اضافه کنید.
مانند پروژه‌ی قبلی، package.config را اضافه کرده و همه‌ی پکیج‌های قبلی به علاوه پکیج زیر را اضافه کنید:
<package id="Microsoft.Owin.Testing" version="3.0.1" targetFramework="net462" />
update-package فراموش نشود

در ادامه تست خود را اینگونه مینویسیم
using Microsoft.Owin.Testing;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using OwinKatanaTest;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace Test
{
    [TestClass]
    public class Test
    {
        [TestMethod]
        public async Task TestWebApi()
        {
            using (TestServer server = TestServer.Create<OwinAppStartup>())
            {
                HttpResponseMessage apiResponse = await server.HttpClient.GetAsync("/api/products/1");
                apiResponse.EnsureSuccessStatusCode();
                Assert.AreEqual(HttpStatusCode.OK, apiResponse.StatusCode);
            }
        }

        [TestMethod]
        public async Task TestOData()
        {
            using (TestServer server = TestServer.Create<OwinAppStartup>())
            {
                HttpResponseMessage odataResponse = await server.HttpClient.GetAsync("odata/Categories/Test.GetBestCategory");
                odataResponse.EnsureSuccessStatusCode();
                Assert.AreEqual(HttpStatusCode.OK, odataResponse.StatusCode);
            }
        }
    }
}
الان باید solution شما چیزی شبیه به این باشد:

بعد از اجرای تست‌ها، باید تیک سبز کنارشان ایجاد شود.
بعد از خواندن این مقاله شاید متوجه شده باشید که چقدر pipeline این پروژه شبیه به پروژه‌های ASP.NET Coreی است؛ یا بهتر است تصحیح کنم به عکس. بلکه ASP.NET Core هست که خیلی شبیه به این میباشد!
عملا سرویس‌های شما کاملا مجزا شده‌اند و میتوانید به راحتی یک فریم ورک SPA را به پروژه‌ی خود اضافه کرده و برای Authentication هم Single Sign On Identity Server بسیار مناسب میباشد. بدون اینکه حتی برنامه نویسان بیزینسی پروژه‌ی شما متوجه بشوند، با تغییراتی در کانفیگ این پروژه، می‌توان آن را بروزرسانی نمود.
لینک دانلود پروژه OwinKatanaTest.zip 
اشتراک‌ها
دوره پیاده سازی minimal API با دات نت 7

.NET 7 minimal API from scratch | FULL COURSE | clean architecture, repository pattern, CQRS MediatR

In this course I want to provide you a project structure and code organization to get you started with real .NET 7 minimal API projects. It's a full course on this topic where I start from creating and explaining the project structure, setting up different layers using EF Core, repository pattern, CQRS and MediatR. The biggest part of the video is however around the .NET 7 minimal API, taking you from the initial setup, explaining route handlers, implementing all CRUD operations and so on. Last but not least, this course walks you through the process of refactoring the .NET 7 minimal API so that it becomes readable, maintainable and scalable. At the end, you'll have a full project structure organized according to modern architectural patterns that you can take as a template for your own projects.

Contents
1. Intro: 00:00
2. Structuring the solution: 01:00
3. Coding the domain layer: 05:25
4. Coding the data access layer: 08:22
5. Creating repositories: 11:17
6. Adding migrations and database update: 22:30
7. CQRS with MediatR: 29:07
8. Route and rout handlers: 52:06
9. Dependency injection: 55:52
10. Implementing GET by ID : 57:40
11. Implementing POST route: 01:00:26
12. Implementing GET all route: 01:03:41
13. Implement PUT and DELETE: 01:04:57
14. Testing with Postman: 01:09:01
15. Is there a problem? 01:12:41
16. Refactoring service registrations: 01:15:49
17. Refactoring route registrations: 01:20:01
18. Automatic registration of endpoints: 01:26:28
19. Introducing route groups:  01:31:43
20. Extract lambdas into instance methods: 01:34:31
21: Model validation with endpoint filters: 01:45:58
22. Global exception handling: 01:55:10
23. Conclusions: 01:59:49 

دوره پیاده سازی minimal API با دات نت 7
نظرات مطالب
ASP.NET MVC #22
با سلام؛ بلافاصله بعد از استفاده (ایجاد) Index_cshtml. fa .resx خطای زیر به وجود می‌آید
|Error1Task could not find "AL.exe" using the SdkToolsPath "" or the registry key 
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0A\WinSDK-NetFx40Tools-x86".
 Make sure the SdkToolsPath is set and the tool exists in the correct processor specific location 
under the SdkToolsPath and that the Microsoft Windows SDK is installed MvcAppProject
به نظرتان اشکال کجاست؟ راه حل چیست؟
اشتراک‌ها
چگونه در گیت‌هاب، لاگ تغییرات را به صورت خودکار تولید کنیم؟

Stop writing your changelogs manually

How do you usually keep track of the changes in your projects? Do you use GitHub releases? Do you update your changelogs manually? In this article, I will explain how I handle this topic. This is just one way of doing it, feel free to stick around if you are interested in the topic 🔥

چگونه در گیت‌هاب، لاگ تغییرات را به صورت خودکار تولید کنیم؟
اشتراک‌ها
معرفی WebAssembly بر روی Server

WebAssembly is moving beyond the browser and is pitched to become a foundational element of modern cloud-native architecture. It lets any language compile to universal binaries that run on any OS or processor, robustly sandboxed and with great performance. This session covers a new approach to running .NET in WASI environments. You’ll see how your existing .NET code could be built into WASI-compliant modules, plus the opportunities this opens. This is experimental, not yet a committed product. 

معرفی WebAssembly بر روی Server