DuoCode is an alternative compiler, powered by Microsoft® Roslyn, and integrated in Visual Studio.
It magically cross-compiles your C# 6.0 code into high-quality readable JavaScript code, enabling rapid development of web applications utilizing the extensive features of the C# language, the Visual Studio IDE, and the .NET Framework base class libraries.
in this article, I will show how to take a medium-small demo app written using Visual Studio 2013, ASP.NET 4.5, VC 5, and Entity Framework 6 and turn it into a working ASP.NET 5 app employing Visual Studio 2015, MVC 6 and Entity Framework 7. And the new app will happily run on either the .NET 4.6 CLR or the .NET Core CLR. Let's get started.
No Authentication
اگر گزینه No Authentication را انتخاب کنید، پروژه ایجاد شده صفحاتی را برای ورود به سایت نخواهد ساخت. همچنین رابط کاربری ای برای نمایش کاربر فعلی، کلاسهای موجودیتها برای یک دیتابیس عضویت و رشتههای اتصالی نیز وجود نخواهند داشت.
- سیستم عضویت جدید بجای استفاده از ماژول ASP.NET Forms Authentication بر پایه OWIN نوشته شده است. این بدین معنا است که از یک مکانیزم احراز هویت واحد میتوانید در اپلیکیشنهای ASP.NET Web Forms, MVC, Web API و SignalR استفاده کنید.
- سیستم عضویت جدید توسط Entity Framework Code First مدیریت میشود و شامل تمامی کلاسهایی است که نماینده جداول و موجودیتها هستند. این بدین معنا است که روی الگوی دیتابیس کنترل کامل دارید. سفارشی سازی و تغییر اطلاعات کاربران و پروفایل هایشان بسیار سادهتر است، تنها لازم است برای اعمال تغییرات از Code First Migrations استفاده کنید.
- asp.net/identity
- Create an ASP.NET MVC 5 App with Facebook and Google OAuth2 and OpenID Sign-on
- Web API - External Authentication Services
- Adding External Logins to your ASP.NET application in Visual Studio 2013
اگر گزینه Organizational Accounts را انتخاب کنید پروژه ایجاد شده برای استفاده از (Windows Identity Foundation (WIF پیکربندی خواهد شد. این فریم ورک برای احراز هویت کاربران از (Windows Azure Active Directory (WAAD استفاده میکند که شامل Office 365 نیز میشود.
از این گزینه برای احراز هویت کاربرانی استفاده کنید که در قالب یک OWIN Tenant تعریف میشوند. برای مثال سایتی با نام Company.com داریم که برای کارمندان این سازمان از طریق company.onmicrosoft.com قابل دسترسی خواهد بود. نمیتوانید WAAD را طوری پیکربندی کنید که کاربران tenantهای دیگر نیز به اپلیکیشن شما دسترسی داشته باشند.
Domain
نام دامنهای در WAAD که میخواهید اپلیکیشن را برای آن پیکربندی کنید، مثلا company.onmicrosoft.com. اگر از custom domain ها استفاده میکنید مانند company.com بجای company.onmicrosoft.com میتوانید این اطلاعات را اینجا وارد کنید.
سطح دسترسی
اگر اپلیکیشن نیاز به کوئری گرفتن یا بروز رسانی اطلاعات پوشهها (directory information) را توسط Graph API دارد، از گزینههای Single Sign-On, Read Directory Data و یا Single Sign-On, Read and Write Directory Data استفاده کنید. در غیر اینصورت گزینه Single Sign-On را رها کنید. برای اطلاعات بیشتر به Application Access Levels و Using the Graph API to Query Windows Azure AD مراجعه کنید.
Application ID URI
بصورت پیش فرض، قالب پروژه یک شناسه application ID URI برای شما تولید میکند، که این کار با الحاق نام پروژه شما به نام دامنه WAAD صورت میگیرد. برای مثال، اگر نام پروژه Example باشد و نام دامنه contoso.onmicrosoft.com، شناسه خروجی https://contoso.onmicrosoft.com/Example میشود. اگر میخواهید بصورت دستی این فیلد را مقدار دهی کنید، گزینه More Options را انتخاب کنید. این شناسه باید با //:https شروع شود.
بصورت پیش فرض، اگر اپلیکیشنی که در WAAD تهیه و تدارک دیده شده است، شناسهای یکسان با شناسه موجود در پروژه Visual Studio داشته باشد، پروژه شما به اپلیکیشن موجود در WAAD متصل خواهد شد. اگر میخواهید تدارکات جدیدی ببینید تیک گزینه Overwrite the application entry if one with the same ID already exists را حذف کنید.
اگر تیک این گزینه حذف شده باشد، و ویژوال استودیو اپلیکیشنی با شناسهای یکسان را پیدا کند، عددی به آخر URI اضافه خواهد شد. مثلا فرض کنید نام پروژه Example است و اپلیکیشنی نیز با شناسه https://contoso.onmicrosoft.com/Example در WAAD وجود دارد. در این صورت اپلیکیشن جدیدی با شناسه ای مانند https://contoso.onmicrosoft.com/Example_ 20130619330903 ایجاد میشود.
تهیه و تدارک اپلیکیشن در WAAD
برای آنکه یک اپلیکیشن WAAD ایجاد کنید و یا پروژه را به یک اپلیکیشن موجود متصل کنید، ویژوال استودیو به اطلاعات ورود یک مدیر کل برای دامنه مورد نظر، نیاز دارد. هنگامی که در دیالوگ Configure Authentication روی OK کلیک میکنید، اطلاعات ورود یک مدیر کل از شما درخواست میشود و نهایتا هنگامیکه روی Create Project کلیک میکنید، ویژوال استودیو اپلیکیشن شما را در WAAD پیکربندی میکند.
برای اطلاعات بیشتر درباره نحوه استفاده از مدل احراز هویت Cloud - Single Organization به لینکهای زیر مراجعه فرمایید:
- Windows Azure Authentication
- Adding Sign-On to Your Web Application Using Windows Azure AD
- Developing ASP.NET Apps with Windows Azure Active Directory
از این گزینه برای احراز هویت کاربرانی استفاده کنید که در WAAD tenantهای متعددی تعریف شدهاند. برای مثال، نام سایت contoso.com است و برای کارمندان دو سازمان از طریق آدرسهای contoso.onmicrosoft.com و fabrikam.onmicrosoft.com قابل دسترسی خواهد بود. نحوه پیکربندی این مدل نیز مانند قسمت قبلی است.
برای اطلاعات بیشتر درباره احراز هویت Cloud - Multi Organization به لینکهای زیر مراجعه کنید:
- Easy Web App Integration with Windows Azure Active Directory, ASP.NET & Visual Studio
- Developing Multi-Tenant Web Applications with Windows Azure AD
این گزینه را هنگامی انتخاب کنید که کاربران در (Windows Server Active Directory (AD تعریف شده اند و نمیخواهید از WAAD استفاده کنید. از این مدل برای ایجاد وب سایتهای اینترنت و اینترانت میتوانید استفاده کنید. برای یک وب سایت اینترنتی از (Active Directory Federation Services (ADFS استفاده کنید.
برای یک وب سایت اینترانتی، میتوانید کلا این گزینه را رها کنید و از Windows Authentication استفاده کنید. در صورت استفاده از گزینه Windows Authentication لازم نیست تا آدرس سند متادیتا (metadata document URL) را فراهم کنید، همچنین توجه داشته باشید که Windows Authentication امکان کوئری گرفتن از پوشهها و کنترل سطوح دسترسی در Active Directory را ندارد.
On-Premises Authority
آدرس سند متادیتا. این سند اطلاعاتی درباره مختصات Authority دارد که اپلیکیشن از آنها برای به پیش بردن روند احراز هویت و ورود به سایت استفاده میکند.
Application ID URI
یک شناسه منحصر به فرد که AD از آن برای شناسایی اپلیکیشن استفاده میکند. میتوانید این فیلد را خالی رها کنید تا ویژوال استودیو بصورت خودکار اپلیکیشنی بدین منظور بسازد.
قدمهای بعدی
در این مقاله با مدلهای مختلف احراز هویت در اپلیکیشنهای Visual Studio 2013 آشنا شدید و برخی تغییرات و امکانات جدید نیز بررسی شدند. برای اطلاعات تکمیلی به ASP.NET and Web Tools for Visual Studio 2013 Release Notes مراجعه کنید.
بررسی کارآیی کوئریها در SQL Server - قسمت هشتم - بررسی عملگرهای Merge Join و Sort در یک Query Plan
بررسی عملگر merge join
ابتدا در management studio از منوی Query، گزینهی Include actual execution plan را انتخاب میکنیم. سپس کوئریهای زیر را اجرا میکنیم:
USE [WideWorldImporters]; GO SET STATISTICS IO ON; GO SELECT [p].[PurchaseOrderID], [pl].[PurchaseOrderLineID] FROM [Purchasing].[PurchaseOrders] [p] JOIN [Purchasing].[PurchaseOrderLines] [pl] ON [p].[PurchaseOrderID] = [pl].[PurchaseOrderID]; GO
در اینجا یک merge join انجام شده، چون اطلاعات رسیدهی به آن، از پیش مرتب شدهاست. از این جهت که جدول PurchaseOrders دارای یک clustered index تعریف شدهی بر روی PurchaseOrderID است:
ALTER TABLE [Purchasing].[PurchaseOrders] ADD CONSTRAINT [PK_Purchasing_PurchaseOrders] PRIMARY KEY CLUSTERED ( [PurchaseOrderID] ASC )
CREATE NONCLUSTERED INDEX [FK_Purchasing_PurchaseOrderLines_PurchaseOrderID] ON [Purchasing].[PurchaseOrderLines] ( [PurchaseOrderID] ASC )
اما بهینه سازی کوئریهای SQL Server، همیشه در یک چنین شرایطی، از merge join استفاده نمیکند. برای مثال کوئری زیر نیز دقیقا از لحاظ تعریف ایندکس بر روی OrderID، وضعیت مشابهی با کوئری قبلی دارد:
SELECT [o].[OrderID], [ol].[OrderLineID] FROM [Sales].[Orders] [o] JOIN [Sales].[OrderLines] [ol] ON [o].[OrderID] = [ol].[OrderID]; GO
اگر به میزان ضخامت پیکانهای این پلن، با پلن قبلی دقت کنید، مشاهده میکنید که ضخامت آنها در اینجا افزایش یافتهاست. این افزایش ضخامت پیکانها، بیانگر افزایش میزان اطلاعات ارسالی به قسمتهای مختلف است (حدود 231 هزار ردیف) به همراه اسکن بالایی بر روی ایندکس [FK_Sales_Orders_SalespersonPersonID] است (بر روی PersonID بجای OrderID) و دومی بر روی [NCCX_Sales_OrderLines]. چون ایندکس OrderID سنگین است و تعداد ردیف زیادی را شامل میشود، بهینه ساز ترجیح دادهاست تا از ایندکس دیگری استفاده کند که I/O کمتری را به همراه دارد. در اینحالت دیگر merger join میسر نبوده و از hash match استفاده کردهاست.
اگر OrderID انتخاب شده را از جدول OrderLines تهیه کنیم، چه اتفاقی رخ میدهد؟ (در کوئری قبلی، OrderID از جدول Orders انتخاب شده بود)
SELECT [ol].[OrderID], [ol].[OrderLineID] FROM [Sales].[Orders] [o] JOIN [Sales].[OrderLines] [ol] ON [o].[OrderID] = [ol].[OrderID];
یک بازنویسی ساده و دریافت دو ستون از یک جدول سبب شدهاست تا بهینه سازی کوئری، join تشکیل شده را غیرضروری دانسته و مستقیم عمل کند.
اهمیت مرتب شده بودن اطلاعات در تشکیل Joinهای بهینه
کوئری زیر را در نظر بگیرید که در آن یک select * را داریم (که یک ضد الگو است):
SELECT * FROM [Sales].[Orders] [o] JOIN [Sales].[OrderLines] [ol] ON [o].[OrderID] = [ol].[OrderID]; GO
جدول OrderLines دارای یک non-clustered index، فقط بر روی ستون OrderID است؛ اما با select * نوشته شده، تمام ستونهای آنرا درخواست کردهایم (و نه فقط OrderID را)؛ به همین جهت اطلاعات آن پیش از ارسال به merge join باید توسط عملگر sort مرتب شود و همانطور که مشاهده میکنید، هزینهی این عملگر در این پلن، 82 درصد کل است.
تاثیر order by بر روی کوئری پلن تشکیل شده
دو کوئری زیر را در نظر بگیرید که تفاوت دومی با اولی، در داشتن یک ORDER BY است:
SELECT TOP 1000 * FROM [Sales].[OrderLines]; GO SELECT TOP 1000 * FROM [Sales].[OrderLines] ORDER BY [Description]; GO
اولی، تمام clustered index را اسکن نمیکند و جائیکه 1000 ردیف را از آن بازگشت میدهد، متوقف میشود.
اما در دومی چون نیاز به مرتب سازی اطلاعات بر اساس یک ستون بودهاست، عملگر sort مشاهده میشود. اسکن آن نیز بر روی کل اطلاعات است (پیکان مرتبط با آن، نسبت به پلن قبلی ضخیمتر است) و سپس آنها را مرتب میکند.
برای بهبود این وضعیت، تعداد ستونهای بازگشت داده شده را محدود کرده و سپس بر اساس آنها، ایندکس صحیحی را طراحی میکنیم:
بنابراین اینبار بجای select *، تعداد مشخصی از ستونها را بازگشت میدهیم:
SELECT [CustomerID], [OrderDate], [ExpectedDeliveryDate] FROM [Sales].[Orders] ORDER BY [CustomerID]; GO
CREATE NONCLUSTERED INDEX [IX_Sales_Orders_CustomerID_Dates] ON [Sales].[Orders]( [CustomerID] ASC ) INCLUDE ( [OrderDate], [ExpectedDeliveryDate] ) ON [USERDATA]; GO
پشتیبانی از XML Schema در SQL Server
XML Schema معرف ساختار، نوع دادهها و المانهای یک سند XML است. البته باید درنظر داشت که تعریف XML Schema کاملا اختیاری است و اگر تعریف شود مزیت اعتبارسنجی دادههای در حال ذخیره سازی در بانک اطلاعاتی را به صورت خودکار به همراه خواهد داشت. در این حالت به نوع دادهای XML دارای اسکیما، typed XML و به نوع بدون اسکیما، untyped XML گفته میشود.
به یک نوع XML، چندین اسکیمای مختلف را میتوان نسبت داد و به آن XML schema collection نیز میگویند.
XML schema collections پیش فرض و سیستمی
تعدادی XML Schema پیش فرض در SQL Server تعریف شدهاند که به آنها sys schema collections گفته میشود.
Prefix - Namespace xml = http://www.w3.org/XML/1998/namespace xs = http://www.w3.org/2001/XMLSchema xsi = http://www.w3.org/2001/XMLSchema-instance fn = http://www.w3.org/2004/07/xpath-functions sqltypes = http://schemas.microsoft.com/sqlserver/2004/sqltypes xdt = http://www.w3.org/2004/07/xpath-datatypes (no prefix) = urn:schemas-microsoft-com:xml-sql (no prefix) = http://schemas.microsoft.com/sqlserver/2004/SOAP
اگر علاقمند باشید تا این تعاریف را مشاهده کنید به مسیر Program Files\Microsoft SQL Server\version\Tools\Binn\schemas\sqlserver در جایی که SQL Server نصب شدهاست مراجعه نمائید. برای مثال در مسیر Tools\Binn\schemas\sqlserver\2006\11\events فایل events.xsd قابل مشاهده است و یا در مسیر Tools\Binn\schemas\sqlserver\2004\07 اسکیمای ابزارهای query processor و show plan قابل بررسی میباشد.
مهمترین آنها را در پوشه Tools\Binn\schemas\sqlserver\2004\sqltypes در فایل sqltypes.xsd میتوانید ملاحظه کنید. اگر به محتوای آن دقت کنید، قسمتی از آن به شرح ذیل است:
<xsd:simpleType name="char"> <xsd:restriction base="xsd:string"/> </xsd:simpleType> <xsd:simpleType name="nchar"> <xsd:restriction base="xsd:string"/> </xsd:simpleType> <xsd:simpleType name="varchar"> <xsd:restriction base="xsd:string"/> </xsd:simpleType> <xsd:simpleType name="nvarchar"> <xsd:restriction base="xsd:string"/> </xsd:simpleType> <xsd:simpleType name="text"> <xsd:restriction base="xsd:string"/> </xsd:simpleType> <xsd:simpleType name="ntext"> <xsd:restriction base="xsd:string"/> </xsd:simpleType>
<xsd:simpleType name="datetime"> <xsd:restriction base="xsd:dateTime"> <xsd:pattern value="((000[1-9])|(00[1-9][0-9])|(0[1-9][0-9]{2})|([1-9][0-9]{3}))-((0[1-9])|(1[012]))-((0[1-9])|([12][0-9])|(3[01]))T(([01][0-9])|(2[0-3]))(:[0-5][0-9]){2}(\.[0-9]{2}[037])?"/> <xsd:maxInclusive value="9999-12-31T23:59:59.997"/> <xsd:minInclusive value="1753-01-01T00:00:00.000"/> </xsd:restriction> </xsd:simpleType>
تعریف XML Schema و استفاده از آن جهت تعریف یک strongly typed XML
XML Schema مورد استفاده در SQL Server حتما باید در بانک اطلاعاتی ذخیره شود و برای خواندن آن، برای مثال از فایل سیستم استفاده نخواهد شد.
CREATE XML SCHEMA COLLECTION invcol AS '<xs:schema ... targetNamespace="urn:invoices"> ... </xs:schema> ' CREATE TABLE Invoices( id int IDENTITY PRIMARY KEY, invoice XML(invcol) )
در ادامه نحوهی تعریف یک اسکیمای نمونه قابل مشاهده است:
CREATE XML SCHEMA COLLECTION geocol AS '<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" targetNamespace="urn:geo" elementFormDefault="qualified" xmlns:tns="urn:geo"> <xs:simpleType name="dim"> <xs:restriction base="xs:int" /> </xs:simpleType> <xs:complexType name="Point"> <xs:sequence> <xs:element name="X" type="tns:dim" minOccurs="0" maxOccurs="unbounded" /> <xs:element name="Y" type="tns:dim" minOccurs="0" maxOccurs="unbounded" /> </xs:sequence> </xs:complexType> <xs:element name="Point" type="tns:Point" /> </xs:schema>'
اکنون برای آزمایش اسکیمای تعریف شده، جدول geo_tab را به نحو ذیل تعریف میکنیم و سپس سعی در insert دو رکورد در آن خواهیم کرد:
declare @geo_tab table( id int identity primary key, point xml(content geocol) ) insert into @geo_tab values('<Point xmlns="urn:geo"><X>10</X><Y>20</Y></Point>') insert into @geo_tab values('<Point xmlns="urn:geo"><X>10</X><Y>test</Y></Point>')
در این مثال، insert اول با موفقیت انجام خواهد شد؛ اما insert دوم با خطای ذیل متوقف میشود:
XML Validation: Invalid simple type value: 'test'. Location: /*:Point[1]/*:Y[1]
یافتن محل ذخیره سازی اطلاعات اسکیما در SQL Server
اگر علاقمند باشید تا با محل ذخیره سازی اطلاعات اسکیما، نوعهای تعریف شده و حتی محل استفاده از آنها در بانکهای اطلاعاتی مختلف موجود آشنا شوید و گزارشی از آنها تهیه کنید، میتوانید از کوئریهای ذیل استفاده نمائید:
select * from sys.xml_schema_collections select * from sys.xml_schema_namespaces select * from sys.xml_schema_elements select * from sys.xml_schema_attributes select * from sys.xml_schema_types select * from sys.column_xml_schema_collection_usages select * from sys.parameter_xml_schema_collection_usages
محتوای اسکیمای ذخیره شده به شکل xsd تعریف شده، ذخیره سازی نمیشود. بلکه اطلاعات آن تجزیه شده و سپس در جداول سیستمی SQL Server ذخیره میگردند. هدف از اینکار، بالا بردن سرعت اعتبارسنجی typed XMLها است.
بنابراین بدیهی است در این حالت اطلاعاتی مانند commnets موجود در xsd تهیه شده در بانک اطلاعاتی ذخیره نمیگردند.
برای بازیابی اطلاعات اسکیمای ذخیره شده میتوان از متد xml_schema_namespace استفاده کرد:
declare @x xml select @x = xml_schema_namespace(N'dbo', N'geocol') print convert(varchar(max), @x)
نحوهی ویرایش یک schema collection موجود
چند نکته:
- امکان alter یک schema collection وجود دارد.
- میتوان یک schema جدید را به collection موجود افزود.
- امکان افزودن (و نه تغییر) نوعهای یک schema موجود، میسر است.
- امکان drop یک اسکیما از collection موجودی وجود ندارد. باید کل collection را drop کرد و سپس آنرا تعریف نمود.
- جداولی با فیلدهای nvarchar را میتوان به فیلدهای XML تبدیل کرد و برعکس.
- امکان تغییر یک فیلد XML به حالت untyped و برعکس وجود دارد.
فرض کنید که میخواهیم اسکیمای متناظر با یک ستون XML را تغییر دهیم. ابتدا باید آن ستون XML ایی را Alter کرده و قید اسکیمای آنرا برداریم. سپس باید اسکیمای موجود را drop و مجددا ایجاد کرد. همانطور که پیشتر ذکر شد، اگر اسکیمایی در حال استفاده باشد، قابل drop نیست. در ادامه مجددا باید ستون XML ایی را تغییر داده و اسکیمای آنرا معرفی کرد.
روش دوم مدیریت این مساله، اجازه دادن به حضور بیش از یک اسکیما در مجموعه است. به عبارتی نگارشبندی اسکیما که به نحو ذیل قابل انجام است:
alter XML SCHEMA COLLECTION geocol add @x
نحوهی import یک فایل xsd و ذخیره آن به صورت اسکیما
اگر بخواهیم یک فایل xsd موجود را به عنوان xsd معرفی کنیم میتوان از دستورات ذیل کمک گرفت:
declare @x xml set @x = (select * from openrowset(bulk 'c:\path\file.xsd', single_blob) as x) CREATE XML SCHEMA COLLECTION geocol2 AS @x
از openrowset برای خواندن یک فایل xml موجود، جهت insert محتوای آن در بانک اطلاعاتی نیز میتوان استفاده کرد.
محدودیتهای XML Schema در SQL Server
تمام استاندارد XML Schema در SQL Server پشتیبانی نمیشود و همچنین این مورد از نگارشی به نگارشی دیگر نیز ممکن است تغییر یافته و بهبود یابد. برای مثال در SQL Server 2005 از xs:any پشتیبانی نمیشود اما در SQL Server 2008 این محدودیت برطرف شدهاست. همچنین مواردی مانند xs:include، xs:redefine، xs:notation، xs:key، xs:keyref و xs:unique در SQL Server پشتیبانی نمیشوند.
یک نکتهی تکمیلی
برنامهای به نام xsd.exe به همراه Visual Studio ارائه میشود که قادر است به صورت خودکار از یک فایل XML موجود، XML Schema تولید کند. اطلاعات بیشتر
5.Visual Studio 2017 15.8 منتشر شد
These are the customer-reported issues addressed in 15.8.5:
- Debugger tooltip does not expand in Xamarin.iOS debugging session.
- Debugger won't let me leave execution point (Android).
- After updating to 15.8.1, data tip does not show when debugging.
- Debugger data tip does not expand [Editor].
- Exception:MSB0001: Internal MSBuild Error: Already registered for build-time.
- Wrong path to resource in manifest for ClickOnce after upgrading to VS 15.8.1.
- ClickOnce Manifest error in 15.8.
- ClickOnce Publish is missing certain references.
- ClickOnce: Language file copied to wrong location.
- Reference missing in the ClickOnce publish folder.
- Compiling non-.NET SDK style F# projects results in an internal MSBuild error unless MSBuild parallelism is set to 1.
- F# is not NGEN'd in Visual Studio.
- F# deploys the FSharp.Core 4.5.0.0 binary in the 4.4.3.0 location.
Details of What's New in 15.8.5
Visual Studio Tools for Xamarin
Visual Studio Tools for Xamarin now supports Xcode 10, which allows you to build and debug apps for iOS 12, tvOS 12, and watchOS 5. See how to get ready for iOS 12 and our introduction to iOS 12 for more details on the new features available.
Full Stack ASP.NET Core 2.0 MVC Forum Build
Topics Covered:
- Setting up a new ASP .NET Core 2.0 MVC web application with Identity user authentication in Visual Studio
- Separating Web, Services, and Data Access Layers in our solution
- Setting up tests with NUnit and .NET Core virtual in-memory database
- Debugging / Fixing bugs
- Implementing the MVC (Model-View-Controller) pattern
- Dependency Injection of Services into our Controllers
- Using input forms to pass data from our Views to our Controllers
- Azure file storage for Profile Image uploads
- Azure SQL database hosting
- SQL Database seeding for starting the application with a super-user
- Code-first database migrations
- Writing SQL queries to inspect data in our database
- Deploying the application to Azure.