- Functionها حتما باید مقدار بازگشتی داشته باشند ولی مقدار بازگشتی در *SPها به صورت اختیاری است. یک SP میتواند از صفر تا n خروجی داشته باشد.
- Functionها تنها میتوانند پارامترهای ورودی داشته باشند ولی SPها علاوه بر پارامترهای ورودی، میتوانند پارامتر خروجی نیز داشته باشند.
- Functionها میتوانند از داخل SPها صدا زده شوند ولی SPها قابل فراخوانی از داخل Functionها نیستند.
- Functionها تنها میتوانند دستورات Select را اجرا کنند ولی SPها میتوانند تمامی دستورات را از قبیل Select, Delete, Insert و... اجرا نمایند.
- Functionها قابل فراخوانی از طریق دستورات Select هستند ولی SPها این قابلیت را ندارند.
- Functionها قابلیت استفاده به صورت مستقیم را در دستوراتی مانند Having، دارند ولی SPها این گونه نیستند.
- Functionها در هربار استفاده کامپایل میشوند لیکن SPها میتوانند یکبار کامپایل شده، execution plan آنها برای استفاده آتی نگهداری شوند. این مهمترین تفاوت این دو میباشد.
- استثناء و خطاها در SPها قابل دریافت توسط Try...Catch میباشند ولی در Functionها این قابلیت وجود ندارد.
- در SPها میتوان از Transactionها استفاده کرده و آنها را مدیریت نمایید؛ لیکن Functionها این چنین امکاناتی را ندارند.
مستند سازی ASP.NET Core 2x API توسط OpenAPI Swagger - قسمت دوم - شروع به مستند سازی یک API
<Project Sdk="Microsoft.NET.Sdk.Web"> <ItemGroup> <PackageReference Include="Swashbuckle.AspNetCore" Version="5.0.0-rc2" /> </ItemGroup> </Project>
روش ایجاد یک پروژهی کتابخانهای، از کامپوننتهای Blazor
اگر از ویژوال استودیو استفاده میکنید، نوع «Razor Class Library»، پروژههای مخصوص کتابخانههای کامپوننتهای Blazor را آغاز میکند و اگر میخواهید از CLI استفاده کنید، باید از دستور «dotnet new razorclasslib» استفاده کرد؛ که قابلیت تبدیل به بستههای نیوگت را با دستور dotnet pack داشته و به این ترتیب میتوان آنها را به اشتراک گذاشت و یا حتی میتوان ارجاعی از این پروژه را در سایر پروژههای شخصی، مورد استفاده قرار داد.
ساختار پیشفرض فایل csproj اینگونه پروژهها به صورت زیر است:
<Project Sdk="Microsoft.NET.Sdk.Razor"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <SupportedPlatform Include="browser" /> </ItemGroup> <ItemGroup> <PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="5.0.6" /> </ItemGroup> </Project>
روش افزودن فایلهای ثابت مورد استفادهی در کتابخانه
پروژهی پیشفرضی که در اینجا ایجاد میشود، به همراه یک پوشهی wwwroot نیز هست. این پوشه محلی است که باید فایلهای ثابت اشتراکی پروژه را مانند فایلهای CSS و JS مورد استفاده، قرار داد.
این نوع پروژهها از ویژگی Isolated CSS و یا Isolated JS ارائه شدهی در Blazor 5x نیز پشتیبانی میکنند.
روش استفادهی از فایلهای ثابت موجود در یک کتابخانه
این فایلهای ثابت به همراه بستهی نهایی پروژه، به صورت خودکار توزیع میشوند (و نیازی به ارائهی مجزای آنها نیست) و برای استفادهی از آنها در پروژههای دیگر، باید از روش مسیردهی زیر استفاده کرد:
/_content/PackageId/MyImage.png
- PackageId عموما همان نام پروژهی مورد استفادهاست (نام فایل csproj مانند MyBlazorComponentLibrary). هرچند میتوان آنرا به صورت مجزایی در فایل csproj نیز مقدار دهی کرد.
- در این مثال MyImage.png، نام منبعی است که قرار است از آن استفاده کنیم و پیشتر در پوشهی wwwroot کتابخانه، کپی شدهاست و یا حتی میتوان زیر پوشههایی را نیز در اینجا ایجاد و از آنها استفاده کرد؛ مانند:
/_content/MyBlazorComponentLibrary/scripts/HelloWorld.js
<script src="_content/MyBlazorComponentLibrary/exampleJsInterop.js"></script>
روش استفادهی از کتابخانهی نهایی تولید شده
برای استفادهی از کتابخانهی نهایی تولید شده یا میتوان ارجاعی را به فایل csproj آن، به پروژهی خود افزود:
<ItemGroup> <ProjectReference Include="..\MyBlazorComponentLibrary\MyBlazorComponentLibrary.csproj" /> </ItemGroup>
پس از آن، جهت سهولت استفادهی از این کامپوننتهای اشتراکی، بهتر است فضای نام آنها را به فایل Imports.razor_ پروژهی خود افزود؛ تا نیازی به تعریف آنها در تمام کامپوننتهای مورد استفاده نباشد.
10) Practical .NET: Powerful JavaScript With Upshot and Knockout
The Microsoft JavaScript Upshot library provides a simplified API for
retrieving data from the server and caching it at the client for reuse. Coupled
with Knockout, the two JavaScript libraries form the pillars of the Microsoft
client-side programming model.
9) On VB: Database Synchronization with the Microsoft Sync
Framework
The Microsoft Sync Framework is a highly flexible framework
for synchronizing files and data between a client and a master data store. With
great flexibility often comes complexity and confusion, however.
8) C# Corner: Performance Tips for Asynchronous Development in
C#
Visual Studio Async is a powerful development framework, but it's
important to understand how it works to avoid performance hits.
7) 2 Great JavaScript Data-Binding Libraries
JavaScript
libraries help you build powerful, data-driven HTML5 apps.
6) On VB: Entity Framework Code-First Migrations
Code First
Migrations allow for database changes to be implemented all through code.
Through the use of Package Manager Console (PMC), commands can be used to
scaffold database changes.
5) C# Corner: The New Read-Only Collections in .NET 4.5
Some
practical uses for the long-awaited interfaces, IReadOnlyList and
IReadOnlyDictionary, in .NET Framework 4.5.
4) C# Corner: Building a Windows 8 RSS Reader
Eric Vogel
walks through a soup-to-nuts demo for building a Metro-style RSS reader.
3) C# Corner: The Build Pattern in .NET
How to separate
complex object construction from its representation using the Builder design
pattern in C#.
2) Inside Visual Studio 11: A Guided Tour
Visual Studio 2012
(code-named Visual Studio 11 then) is packed with new features to help you be a
more efficient, productive developer. Here's your guided tour.
1) HTML5 for ASP.NET Developers
The technologies bundled as
HTML5 finally support what developers have been trying to get HTML to do for
decades.
پیشنیازهای این سری
در این سری از بانک اطلاعاتی استاندارد مثال به همراه SQL Server 2016، به نام WideWorldImporters استفاده میکنیم. برای دریافت آن، به قسمت releases مثالهای مایکروسافت مراجعه کرده و فایل WideWorldImporters-Full.bak را دریافت کنید. پس از دریافت این فایل، برای restore سریع آن، میتوانید دستور زیر را اجرا کنید که در آن باید مسیر فایل bak دریافتی و همچنین مسیر ایجاد فایلهای mdf/ldf/ndf را مطابق مسیرهای سیستم خودتان اصلاح نمائید (فقط مسیر پوشهها را نیاز است تغییر دهید):
use master; RESTORE DATABASE WideWorldImporters FROM disk='D:\path\WideWorldImporters-Full.bak' WITH MOVE 'WWI_Primary' TO 'D:\SQL_Data\WideWorldImporters.mdf', MOVE 'WWI_Log' TO 'D:\SQL_Data\WideWorldImporters_log.ldf', MOVE 'WWI_UserData' TO 'D:\SQL_Data\WideWorldImporters_UserData.ndf', MOVE 'WWI_InMemory_Data_1' TO 'D:\SQL_Data\WideWorldImporters_InMemory_Data_1'
یافتن اطلاعاتی در مورد کوئریها
SQL Server زمانیکه یک کوئری را اجرا میکند، اطلاعاتی را نیز به همراه آن تولید خواهد کرد که سبب ایجاد یک Query Plan میشود و در آن، اطلاعاتی مانند جداول مورد استفاده، نوع جوینها، ایندکسهای استفاده شده و غیره وجود دارند. علاوه بر آن، Query Statistics نیز قابل دسترسی هستند که در آن مدت زمان اجرای یک کوئری، میزان I/O صورت گرفته و میزان مصرف CPU کوئری، ذکر میشوند. برای دسترسی یافتن به این اطلاعات، میتوان به اشیاء مختلف SQL Server مراجعه کرد؛ مانند dynamic management objects یا به اختصار DMO's، همچنین extended events، traces، query stores و یا حتی management studio. مهمترین تفاوت اینها نیز در نحوهی دسترسی به اطلاعات آنها است که میتواند زنده (live) و یا ذخیره شده در جائی باشند. در اینجا تنها منبعی که امکان مشاهدهی این اطلاعات را به صورت زنده میسر میکند، management studio است. البته live در اینجا به معنای امکان مشاهدهی تمام اطلاعات مرتبط با یک کوئری، مانند آمار و کوئری پلن آن در داخل محیط management studio، پس از اجرای یک کوئری است. در این قسمت بیشتر به روش استخراج اطلاعات آماری کوئریهای زنده میپردازیم و در قسمتهای بعدی، سایر گزینههای نامبرده شده را نیز بررسی خواهیم کرد.
مشاهدهی زندهی دادههای مرتبط با اجرای یک کوئری در management studio
پس از restore بانک اطلاعاتی مثال WideWorldImporters که عنوان شد، در برنامهی Microsoft SQL Server Management Studio، کوئری زیر را اجرا میکنیم:
USE [WideWorldImporters]; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO
اینجا است که نیاز به اطلاعات بیشتری در مورد نحوهی اجرای این کوئری داریم. برای استخراج این اطلاعات، اینبار گزینههای تولید و جمع آوری اطلاعات آماری IO و TIME را روشن میکنیم و سپس همان کوئری قبلی را اجرا خواهیم کرد:
USE [WideWorldImporters]; GO SET STATISTICS IO ON; GO SET STATISTICS TIME ON; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 504 ms. (53 rows affected) Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 10 ms.
استخراج اطلاعات Actual Execution Plan یک کوئری
کوئری را زیر با فرض IO ON و TIME ON حاصل از اجرای کوئری قبل، اجرا میکنیم:
USE [WideWorldImporters]; GO SET STATISTICS XML ON; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO SET STATISTICS XML OFF; GO
SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 7 ms. (53 rows affected) Table 'Countries'. Scan count 0, logical reads 118, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. Table 'StateProvinces'. Scan count 1, logical reads 43, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0. (1 row affected) SQL Server Execution Times: CPU time = 15 ms, elapsed time = 179 ms. SQL Server parse and compile time: CPU time = 0 ms, elapsed time = 0 ms. SQL Server Execution Times: CPU time = 0 ms, elapsed time = 0 ms.
اگر بر روی این XML کلیک کنیم، برگهی جدید نمایش گرافیکی این plan ظاهر میشود:
با کلیک راست بر روی این برگه، میتوان اطلاعات آنرا جهت بررسیهای بعدی و یا به اشتراک گذاری آن ذخیره کرد.
در این plan اگر اشارهگر ماوس را بر روی هر کدام از عناصر آن حرکت دهیم، اطلاعاتی مانند actual number of rows نیز مشاهده میشود، در کنار اطلاعات تخمینی؛ به همین جهت به آن Actual Execution Plan هم گفته میشود.
این یک روش دسترسی به Execution Plan است. روش دوم آن با استفاده از امکانات رابط کاربری خود Management Studio است؛ با فشردن دکمههای Ctrl+M و یا انتخاب گزینهی Include actual execution plan از منوی Query آن. پس از آن کوئری زیر را اجرا کنید:
SET STATISTICS IO ON; GO SET STATISTICS TIME ON; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO
استخراج اطلاعات Estimated Execution Plan یک کوئری
تا اینجا نحوهی استخراج اطلاعات Actual Execution Plan را بررسی کردیم که به همراه اطلاعات دقیق حاصل از اجرای کوئری نیز بود؛ مانند actual number of rows. نوع دیگری از Execution Planها را نیز میتوان از SQL Server درخواست کرد که به آنها Estimated Execution Plan گفته میشود و حاصل اجرای کوئری نیستند؛ بلکه تخمینی هستند از روش اجرای این کوئری توسط SQL Server. برای فعالسازی محاسبهی آن، ابتدا کوئری زیر را در management studio انتخاب کنید:
USE [WideWorldImporters]; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO
همانطور که مشاهده میکنید، اینبار نتیجهی حاصل، به همراه اطلاعاتی مانند actual number of rows نیست و صرفا تخمینی است از روش اجرای این کوئری، توسط SQL Server.
جمع آوری اطلاعات آماری کلاینتها
در منوی Query، گزینهای تحت عنوان Include client statistics نیز وجود دارد. با انتخاب آن، اگر کوئری زیر را اجرا کنیم:
USE [WideWorldImporters]; GO SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [c].[CountryName] = 'United States'; GO
در اینجا مشخص میشود که آیا عملیات insert/update/delete انجام شدهاست. چه تعداد ردیف تحت تاثیر اجرای این کوئری قرار گرفتهاند. چه تعداد تراکنش انجام شدهاست. همچنین اطلاعات آماری شبکه و زمان نیز در اینجا ارائه شدهاند.
در همین حالت، کوئری جدید زیر را با تغییر قسمت where کوئری قبلی، اجرا کنید:
SELECT [s].[StateProvinceName], [s].[SalesTerritory], [s].[LatestRecordedPopulation], [s].[StateProvinceCode] FROM [Application].[Countries] [c] JOIN [Application].[StateProvinces] [s] ON [s].[CountryID] = [c].[CountryID] WHERE [s].[StateProvinceName] LIKE 'O%'; GO
در اینجا حداکثر 10 کوئری را میتوان با هم مقایسه کرد و بیشتر از آن سبب حذف موارد قدیمی از لیست میشود.
عدم نمایش ردیفهای بازگشت داده شدهی توسط کوئری در حین جمع آوری اطلاعات آماری
هربار اجرای یک کوئری در management studio، به همراه بازگشت و نمایش ردیفهای مرتبط با آن کوئری نیز میباشد. اگر میخواهید در حین بررسی کارآیی کوئریها از نمایش این ردیفها صرف نظر کنید (تا بار این برنامه کاهش یابد)، میتوانید از منوی Query، گزینهی Query Options را انتخاب کرده و در قسمت Results، گزینهی Grid آن، گزینهی discard results after execution را انتخاب کنید تا دیگر برگهی results نمایش داده نشود و وقت و منابع را تلف نکند. بدیهی است پس از پایان کار بررسی آماری، نیاز به عدم انتخاب این گزینه خواهد بود.
4.Visual Studio 2017 15.9 منتشر شد
These are the customer-reported issues addressed in 15.9.4:
- Visual Studio 15.9 duplicate loads open files on solution reload.
- All users can now connect to on-premise TFS servers through Team Explorer.
- Visual Studio 15.8.3 no longer expands metadata in ItemDefinitionGroup for project-defined items during GUI builds (worked in Visual Studio 15.8.2).
- Visual Studio has multiple tabs for the same file.
- System.ArgumentException: The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG)).
- LNK4099 PDB not found.
- Asset Catalog empty.
- /analyze fails for C++ code using /ZW.
- C++ compiler code optimization bug.
- Xamarin.iOS can't select image asset for Image View.
- iOS projects referencing a shared project containing image assets in an asset catalog fail to load on windows.
- Image not populating on iOS splashscreen in VS 15.8.6.
- Possible bad codegen on union/bitfield assignment in VS2017 15.8.
- Fix C# UWP Store 1201 Submission Issue.
- Fix C# UWP package creation error APPX1101: Payload contains two or more files with the same destination path 'System.Runtime.CompilerServices.Unsafe.dll'.
- Error MT2002: Failed to resolve 'System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder' reference from 'System.Threading.Tasks.Extensions...'" when building a Xamarin.iOS project.
- Redirecting to a relative url doesn't work when using AndroidClientHandler.
- Debug information for typedefs of unnamed enums compiled with the C compiler is now restored.
- The spectre-mitigated x86 version of delayimp.lib is now built with /Qspectre mitigations enabled.
- Changes were made to how Asset Catalogs in Xamarin.iOS projects are loaded in order to reduce solution load time.
- We have updated Xamarin.Forms templates to use the latest version.
- We have fixed an issue with ASP.NET Core Web Applications being debugged through Kestrel that would show the error message "Unable to configure HTTPS endpoint. No server certificate was specified...".
- Enabling the AppInsights site extension in App Service from Visual Studio now happens through the use of specific Application Settings.
Security Advisory Notices
<?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>
PM>Update-Package -reinstall -Project YourProjectName
<?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>
بعد از build کردن پروژه، در صورت خطا داشتن از Referencesها، System.Reflection و System.Runtime.Extensions را حذف کنید.
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"); }); } } }
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" }; } } }
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" } }; } } }
<package id="Microsoft.Owin.Testing" version="3.0.1" targetFramework="net462" />
در ادامه تست خود را اینگونه مینویسیم
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); } } } }
دریافت و نصب افزونهی SQL Server مخصوص VSCode
برای افزودن این افزونه، ابتدا در برگهی Extensions، عبارت mssql را جستجو کرده و سپس آنرا نصب کنید:
پس از نصب آن، مرحلهی بعد، ایجاد یک فایل خالی با پسوند sql است.
انجام اینکار ضروری است و شبیه به حالت نصب افزونهی #C میباشد. به این ترتیب وابستگیهای اصلی آن دریافت، نصب و فعال خواهند شد. این ابزارها نیز سورس باز بوده و موتور SQL Formatter، اجرای SQL و Intellisense آنرا فراهم میکند و چون مبتنی بر NET Core. تهیه شدهاست، چندسکویی است.
تا اینجا مزیتی را که به دست خواهیم آورد Syntax highlighting و Intellisense جهت درج واژههای کلیدی عبارات SQL است:
و یا اگر بر روی فایل sql جاری کلیک راست کنیم، گزینهی Format Document آن سبب میشود تا کدهای SQL نوشته شده، با فرمتی استاندارد، مرتب و یکدست شوند:
بنابراین اگر علاقمندید تا فایلها و عبارات SQL خود را فرمت کنید، این افزونهی سبک وزن چندسکویی، یک چنین قابلیت توکاری را به همراه دارد.
همچنین اگر علاقمندید به یک کتابخانهی سورس باز چندسکویی SQL Formatter و SQL Parser دات نتی دسترسی داشته باشید، کدهای Microsoft/sqltoolsservice در دسترس هستند.
اتصال به SQL Server و کار با آن
پس از نصب مقدماتی افزونهی mssql، دکمههای ctrl+shift+p (و یا F1) را فشرده و عبارت sql را جستجو کنید:
در اینجا سایر قابلیتهای این افزونهی نصب شده را میتوان مشاهده کرد. در لیست ظاهر شده، گزینهی Connect را انتخاب کنید. بلافاصله گزینهی انتخاب پروفایل ظاهر میشود. چون هنوز پروفایلی را تعریف نکردهایم، گزینهی Create connection profile را انتخاب خواهیم کرد:
در ادامه باید نام سرور را وارد کرد. یا میتوانید نام سرور کامل SQL خود را وارد کنید و یا اگر با LocalDB کار میکنید نیز امکان اتصال به آن با تایپlocaldb\MSSQLLocalDB وجود دارد:
سپس نام بانک اطلاعاتی را که میخواهیم به آن متصل شویم ذکر میکنیم:
در مرحلهی بعد، باید نوع اعتبارسنجی اتصال مشخص شود:
چون در ویندوز هستیم، میتوان گزینهی Integrated را نیز انتخاب کرد (یا همان Windows Authentication).
در آخر، جهت تکمیل کار و دخیرهی این اطلاعات وارد شده، میتوان نام پروفایل دلخواهی را وارد کرد:
اکنون کار اتصال به این بانک اطلاعاتی انجام شده و اگر به status bar دقت کنید، نمایش میدهد که در حال به روز رسانی اطلاعات intellisense است.
برای نمونه اینبار دیگر intellisense ظاهر شده منحصر به درج واژههای کلیدی SQL نیست. بلکه شامل تمام اشیاء بانک اطلاعاتی که به آن متصل شدهایم نیز میباشد:
در ادامه برای اجرا این کوئری میتوان دکمههای Ctrl+Shift+E را فشرد و یا ctrl+shift+p (و یا F1) را فشرده و در منوی ظاهر شده، گزینهی execute query را انتخاب کنید (این گزینه بر روی منوی کلیک راست ظاهر شدهی بر روی فایل sql جاری نیز قرار دارد):
نگاهی به محل ذخیره سازی اطلاعات اتصال به بانک اطلاعاتی
پروفایلی را که در قسمت قبل ایجاد کردیم، در منوی File->Preferences->Settings قابل مشاهده است:
// Place your settings in this file to overwrite the default settings { "workbench.colorTheme": "Default Light+", "files.autoSave": "afterDelay", "typescript.check.tscVersion": false, "terminal.integrated.shell.windows": "cmd.exe", "workbench.iconTheme": "material-icon-theme", "vsicons.dontShowNewVersionMessage": true, "mssql.connections": [ { "server": "(localdb)\\MSSQLLocalDB", "database": "TestASPNETCoreIdentityDb", "authenticationType": "Integrated", "profileName": "testLocalDB", "password": "" } ] }
برای مثال پروفایلی را که تعریف کردیم، در دفعات بعدی انتخاب گزینهی Connect، به صورت ذیل ظاهر میشود:
تهیهی خروجی از کوئری اجرا شده
اگر به نوار ابزار سمت راست نتیجهی کوئری اجرا شده دقت کنید، سه دکمهی تهیهی خروجی با فرمتهای csv، json و اکسل نیز در اینجا قرار داده شدهاست:
برای مثال اگر گزینهی json آنرا انتخاب کنید، بلافاصله نام فایلی را پرسیده و سپس این نتیجه را با فرمت JSON نمایش میدهد:
ضمن اینکه حتی میتوان سطرها و سلولهای خاصی را نیز از این خروجی انتخاب کرد و سپس با کلیک بر روی آنها، تنها از این انتخاب، یک خروجی ویژه را تهیه نمود:
مشاهدهی ساختار اشیاء
اگر بر روی هر کدام از اجزای یک کوئری SQL متصل به بانک اطلاعاتی، کلیک راست کنیم، گزینهی Go to definition نیز ظاهر میشود:
با انتخاب آن، بلافاصله عبارت کامل CREATE TABLE [dbo].[AppRoles] ظاهر میشود که در اینجا میتوان ساختار این جدول را به صورت یک عبارت SQL مشاهده کرد.
تغییر تنظیمات افزونهی MSSql
در منوی File->Preferences->Settings با جستجوی mssql میتوان تنظیمات پیش فرض این افزونه را یافت. برای مثال اگر میخواهید تا SQL Formatter آن به صورت خودکار تمام واژههای کلیدی را با حروف بزرگ نمایش دهد، گزینهی mssql.format.keywordCasing را انتخاب کنید. در کنار آن آیکن قلم ویرایش ظاهر میشود. با کلیک بر روی آن، منوی انتخاب uppercase را خواهیم داشت:
پس از این تغییر، اکنون بر روی صفحه کلیک راست کرده و گزینهی Format Document را انتخاب کنید. در این حالت علاوه بر تغییر فرمت سند SQL جاری، تمام واژههای کلیدی آن نیز uppercase خواهند شد.
انتقال Context و Migrations به یک اسمبلی دیگر
تا اینجا اگر مثال بررسی شده را دنبال کرده باشید، دو پوشهی Entities و Migrations را به همراه فایلهای موجودیتها، Context برنامه و Migrations آنها، در همان پروژهی اصلی برنامه، خواهید داشت:
در ادامه قصد داریم بانک اطلاعاتی آزمایشی برنامه را drop کرده، پوشهی Migrations را حذف و صرفا دو فایل ApplicationDbContextSeedData و DBInitialization آنرا نگه داریم.
کلاس Person را به اسمبلی جدید Entities و کلاس ApplicationDbContext را به اسمبلی جدید DataLayer منتقل میکنیم:
اسمبلی جدید Core1RtmEmptyTest.Entities از نوع NET Core Class Library. است و صرفا حاوی کلاسهای موجودیتهای برنامهاست.
اسمبلی جدید Core1RtmEmptyTest.DataLayer نیز از نوع NET Core Class Library. بوده و حاوی تعاریف Context برنامه، به همراه Migrations و تنظیمات آن خواهد بود.
تا اینجا با این نقل و انتقالات، نیاز است وابستگیهای DataLayer را اصلاح کنیم. بنابراین فایل project.json آنرا گشوده و به نحو ذیل تکمیل نمائید:
{ "version": "1.0.0-*", "dependencies": { "Core1RtmEmptyTest.Entities": "1.0.0-*", "Microsoft.EntityFrameworkCore": "1.0.0", "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0", "Microsoft.Extensions.Configuration.Abstractions": "1.0.0", "NETStandard.Library": "1.6.0" }, "frameworks": { "netstandard1.6": { "imports": "dnxcore50" } } }
وابستگی Microsoft.Extensions.Configuration.Abstractions برای کار با IConfigurationRoot اضافه شدهاست (دسترسی به تنظیمات برنامه از طریق تزریق وابستگیها).
به علاوه اکنون به پروژهی وب اصلی مراجعه کرده و فایل project.json آنرا جهت افزودن ارجاعاتی به این دو اسمبلی جدید، ویرایش کنید:
{ "dependencies": { // same as before "Core1RtmEmptyTest.Entities": "1.0.0-*", "Core1RtmEmptyTest.DataLayer": "1.0.0-*" } }
فعال سازی Migrations و قرار دادن فایلهای آن در اسمبلی Core1RtmEmptyTest.DataLayer
در ادامه اگر مانند قسمت قبل بخواهیم مهاجرتها را اضافه کنیم، به خطای ذیل خواهیم رسید:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest>dotnet ef migrations add InitialDatabase Your target project 'Core1RtmEmptyTest' doesn't match your migrations assembly 'Core1RtmEmptyTest.DataLayer'. Either change your target project or change your migrations assembly.
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef migrations add InitialDatabase No executable found matching command "dotnet-ef"
{ // same as before "tools": { "Microsoft.EntityFrameworkCore.Tools": { "version": "1.0.0-preview2-final", "imports": [ "portable-net45+win8" ] } }, // same as before }
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef migrations add InitialDatabase Could not invoke this command on the startup project 'Core1RtmEmptyTest.DataLayer'. This preview of Entity Framework tools does not support commands on class library projects in ASP.NET Core and .NET Core applications.
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ migrations add InitialDatabase Done. To undo this action, use 'dotnet ef migrations remove'
اعمال کلاسهای Migrations تولید شده به بانک اطلاعاتی
پس از تولید موفقیت آمیز فایلهای مهاجرت، برای اعمال آنها به بانک اطلاعاتی، اینبار نیز دستور را از همان پوشهی DataLayer با پارامتر پروژهی آغازین اجرا میکنیم:
D:\Prog\1395\Core1RtmEmptyTest\src\Core1RtmEmptyTest.DataLayer>dotnet ef --startup-project ../Core1RtmEmptyTest/ database update Applying migration '13950527070105_InitialDatabase'. Done.
بنابراین به صورت خلاصه
- ابتدا قسمت tools تنظیمات پروژهی data layer را برای فعال سازی دستورات خط فرمان EF ویرایش کنید.
- سپس از طریق خط فرمان به پوشهی data layer وارد شوید. اینبار باید دستورات EF را از ریشهی این پوشه، بجای پوشهی اصلی برنامه صادر کرد.
- در اینجا دستورات افزودن مهاجرتها و به روز رسانی بانک اطلاعاتی، همانند قبل هستند. فقط ذکر محل واقع شدن پوشهی آغازین برنامه توسط پارامتر startup-project الزامی است.