Manual ASP - MVC - IOC
Manual ASP - MVC - IOC
These tutorials will help you understand ASP.NET Core web application step by step.
Tutorials are broken down into chapters, where each chapter contains a number of related
topics that are packed with easy to understand explanations and real-world examples.
These tutorials are designed for beginners and professionals who want learn how to build
ASP.NET Core web applications step by step.
Prerequisites
Basic knowledge of C#, HTML, Visual Studio, and Object Oriented Programming is
required.
ASP.NET Core
ASP.NET Core is a free, open-source and cloud optimized web framework which can run
on Windows, Linux, or Mac. You can say that it is the new version of ASP.NET. The
framework is a complete rewrite from scratch in order to make it open source, modular and
cross-platform. It was initially launched as ASP.NET 5 but then it was renamed to
ASP.NET Core.
ASP.NET Core is a modular framework distributed as NuGet packages. This allows us to
include packages that are required in our application.
ASP.NET Core applications run on both, .NET Core and traditional .NET framework
(.NET Framework 4.x).
ASP.NET Core is an open source framework supported by Microsoft and the community,
so you can also contribute or download the source code from the respective repositories on
Github.
.NET Core
Many people are confused between ASP.NET Core and .NET Core. Please note that
ASP.NET Core and .NET Core are not the same. They are different, just like ASP.NET and
.NET Framework are different.
.NET Core is a fast, lightweight, modular and open source framework for creating web
applications and services that run on Windows, Linux and Mac. So, it is a platform on
which ASP.NET Core application runs.
.NET Core is named "Core" because it includes core features of the .NET framework. The
main objective of .NET Core is to make .NET framework open source, and cross-platform
compatible so that it can be used in resource-constrained environments. It includes
minimum features that are required to run a basic .NET Core app and other advanced
features that can be included as a package from NuGet.
As you can see above, .NET Core includes .NET Compiler platform Roslyn, .NET Core
runtime CoreCLR, .NET Core framework CoreFX and ASP.NET Core . ASP.NET Core is
a part of .NET Core SDK so you don't need to install ASP.NET Core separately. ASP.NET
Core and .NET Core is a part of .NET Foundation.
.NET Core comes under MIT or Apache 2 licenses. Visit .NET Core repository on Github
to contribute or download the source code.
Supports Multiple Platforms: ASP.NET Core applications can run on Windows, Linux, and
Mac. So you don't need to build different apps for different platforms using different
frameworks.
Fast: ASP.NET Core no longer depends on System.Web.dll for browser-server
communication. ASP.NET Core allows us to include packages which we need for our
application. This reduces the request pipeline and improves the performance and
scalability.
IoC Container: It includes built-in IoC container for automatic dependency injection which
makes it maintainable and testable.
Integration with Modern UI Frameworks: It allows you to use and manage modern UI
frameworks such as AngularJS, ReactJS, Umber, Bootstrap etc. using Bower (a package
manager for the web).
Hosting: ASP.NET Core web application can be hosted on multiple platforms with any web
server such as IIS, Apache etc. It is not dependent only on IIS as a standard .NET
Framework.
Code Sharing: It allows you to build a class library which can be used with other .NET
frameworks such as .NET Framework 4.x or Mono. Thus a single code based can be shared
across frameworks.
Side-by-Side App Versioning: ASP.NET Core runs on .NET Core which supports
simultaneous running of multiple versions of applications.
Smaller Deployment Footprint: ASP.NET Core application runs on .NET Core which is
smaller than full .NET Framework. So, the application which uses only a part of .NET
CoreFX will have smaller deployment size. This reduces the deployment foot print.
ASP.NET Core is a part of .NET Core SDK, so you don't need to install it separately. As of
this writing, the current release is .NET Core 1.1. Read .NET Core Release Notes to know
more about all the releases.
Install .NET Core SDK
.NET Core SDK can be installed on the platform you are using such as Windows, Linux or
Mac.
Note:
.NET Core Runtime and .NET Core SDK are different things. .NET Core Runtime is only used to
run .NET Core application whereas .NET Core SDK includes tools and libraries to develop .NET Core
applications. To setup a development environment, we need to install .NET Core SDK for the
platform we use for the development such as Windows, Linux or Mac.
As you can see above, click on the Download .NET Core SDK button to download the
latest version of .NET Core SDK installer. It will download .NET Core 2.0 SDK as of this
writing.
Alternatively,
Download .NET Core SDK: Download .NET Core SDK for different platform from here.
Download .NET Core Runtime: Download .NET Core Runtime for different platform
from here. Remember, .NET Core runtime is used only to run .NET Core application but
not for the development.
After downloading installer, click on it to start the installation of .NET Core 2.0 SDK.
IDE
You can develop, restore, build and run .NET Core application either with Visual Studio or
with command line interface for .NET Core. Here, we will use Visual Studio 2017 to
develop .NET Core 2.0 applications.
You can download Visual Studio 2017 installer from the same page
https://www.microsoft.com/net/core. Click on the Download Visual Studio button to
download Visual Studio 2017 Community edition. Alternatively, you can go to
https://www.visualstudio.com/downloads/ and download installer for the specific Visual
Studio edition.
If you do not use Visual Studio for .NET core application development for some reason and
want to use different IDE then you can use command-line interface to create, compile,
build, restore and run .NET Core application.
.NET Core SDK installation also installs command-line interface for the selected platform.
It installs the latest stable version of the tools and put them on your PATH so you can run
dotnet from the Console.
Once installed, you can verify it by opening command prompt and type dotnet and press
Enter. This will display installed version and usage information as shown below.
After installation, let's create our first ASP.NET Core application in the next chapter.
The first step is to open Visual Studio. Click on File->New, and click on Projects.
In the New Project dialog box, click on the Templates node. Expand the Templates node,
then expand Visual C#, and click on the Web template.
ASP.NET Project Templates
As shown above, the middle pane on the New Project dialog box includes the following
two templates for ASP.NET Web projects:
Here, we want to create a cross-platform ASP.NET Core web application. So, select
ASP.NET Core Web Application template. Give the appropriate name, location, and the
solution name for the ASP.NET Core application. In this example, we will give the name
MyFirstCoreApp, and click on the OK button. This will open another popup as shown
below.
As you can see, we can select the version of the framework we want to use in our
application. We are going to use .NET Core 2.0 framework here. So select ASP.NET Core
2.0 in the dropdown as shown below.
ASP.NET Core Version
Now, select an Empty ASP.NET Core template in order to understand the basics of
ASP.NET core web application. We will not use Docker support or authentication here, so
click on OK to create an ASP.NET core web application as shown below.
ASP.NET Core Web Project in Visual Studio
Wait for some time till Visual Studio restores the packages in the project. Restoring process
means Visual Studio will automatically add, update or delete configured dependencies as
NuGet packages in the project. The entire project structure of the created project will look
like below.
ASP.NET Core Project Structure
We will understand the project structure in the next chapter. To run this web application, go
to Debug menu and click on Start without Debugging, or press Ctrl + F5. This will open the
browser and display the following result.
The above output "Hello World!" comes from the Configure method of Startup class in
the Startup.cs file in the project. Open Startup.cs file and see Configure method. Change
"Hello World!" string to something else and it will change the output accordingly. Learn
about Startup class in the Startup.cs chapter.
You can also see the IIS express icon on the system tray. Right click on it. You can see the
ASP.NET sites currently running in your development machine.
ASP.NET
Core app in System tray
This is how we can create a new cross-platform ASP.NET core application that runs
on .NET Core. Learn about the ASP.NET Core project structure in the next chapter.
The following is a default project structure when you create an empty ASP.NET Core
application in Visual Studio.
The above solution explorer displays project solution. We can change it to folder view by
clicking Solution and Folders icon and selecting Folder View option. This displays the
solution explorer with all project folders and files as shown below.
Solution Explorer - Folder View
Note:
ASP.NET Core project files and folders are synchronized with physical files and folders. If you add a
new file or folder in project folder then it will directly reflect in the solution explorer. You don't
need to add it in the project explicitly by right clicking on the project.
.csproj
ASP.NET Core 1.0 does not create .csproj file, instead, it uses .xproj and project.json files
to manage the project. This has changed in ASP.NET Core 2.0. Visual Studio now
uses .csproj file to manage projects. We can edit the .csproj settings by right clicking on the
project and selecting Edit <project-name>.csproj as shown below.
Edit .csproj
The csproj file includes settings related to targeted .NET Frameworks, project folders,
NuGet package references etc.
Dependencies
The Dependencies in the ASP.NET Core 2.0 project contain all the installed server-side
NuGet packages as well as client-side frameworks such as jQuery, AngularJS, Bootstrap
etc. These client-side dependencies are managed using Bower in Visual Studio.
Dependencies
As you can see above, dependencies node in solution explorer displays installed NuGet
packages. This also includes bower folder which has all the client-side frameworks library
installed it using Bower.
Properties
The Properties node includes launchSettings.json file which includes Visual Studio profiles
of debug settings. The following is a default launchSettings.json file.
launchSettings.json
We can also edit settings from the debug tab of project properties. Right click on the project
-> select Properties -> click Debug tab.
Project Properties
In the debug tab, select a profile which you want to edit as shown above. You may change
environment variables, url etc.
In the standard ASP.NET application, static files can be served from the root folder of an
application or any other folder under it. This has been changed in ASP.NET Core. Now,
only those files that are in the web root - wwwroot folder can be served over an http
request. All other files are blocked and cannot be served by default.
Generally, there should be separate folders for the different types of static files such as
JavaScript, CSS, Images, library scripts etc. in the wwwroot folder as shown below.
wwwroot
You can access static files with base URL and file name. For example, we can access above
site.css file in the css folder by http://localhost:<port>/css/app.css.
Remember, you need to include a middleware for serving static files in the Configure
method of Startup.cs. Learn more about it in Serving Static File section.
ASP.NET Core - Program.cs
ASP.NET Core web application is actually a console project which starts executing from
the entry point public static void Main() in Program class where we can create a host
for the web application.
The steps for creating a host in ASP.NET Core 1.x is slightly different in ASP.NET Core
2.x. Let's understand Program class in ASP.NET Core 1.x application so that it will be easy
to understand it in ASP.NET Core 2.x.
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace MyFirstCoreApp
{
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.Build();
host.Run();
}
}
}
Every ASP.NET Core web application requires a host to be executed. In the above Main()
method, we configure a web hosting environment for the ASP.NET Core 1.x web
application. A host must implement IWebHost interface. Let's understand the above code
step by step.
The WebHostBuilder class is the helper class to create and configure a host for a web
application. So, first of all we will have to create an object of it.
Note:
WebHostBuilder class is included in .NET Core API. However, we can create our own helper class
by implementing IWebHostBuilder interface for custom hosting requirement.
.UseKestrel()
ASP.NET Core application can be a cross-platform application so it can be used with any
web server, and not only IIS. Hence, there will be an external web server such as IIS,
Apache, Nginx etc. which will dispatch http requests to the internal web server Kestrel.
Learn more about web servers in ASP.NET Core here.
.UseContentRoot(Directory.GetCurrentDirectory())
The UseContentRoot() method specifies the current directory as a root directory which
will be src folder in the default ASP.NET Core project. The content root directory
determines where the content files are located such as MVC view files, CSS, images etc.
.UseIISIntegration()
The UseIISIntegration() method specifies the IIS as the external web server or the
reverse proxy server.
.UseStartup<Startup>()
The UseStartup<startup>() method specifies the Startup class to be used by the web
host. Visual Studio creates Startup.cs by default with every new ASP.NET Core
application. This Startup class is like Global.asax of .NET framework where you can
configure request pipeline (middleware). We may give any other name to the Startup class
instead of Startup. We just need to specify it as a generic parameter in UseStartup<T>()
method. You will learn about it in the next chapter.
And lastly, the Build() method returns an instance of IWebHost using the configuration
specified above.
So now, we have built our hosting environment and it's time to start the web application.
host.Run();
The Run() method starts the web application and blocks the calling thread till the host is
shutdown. The command line application will become web application from this point
onwards.
Thus, ASP.NET Core application starts from the Main() method of the Program class
where you can build the hosting environment and start the web application.
Program.cs
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
namespace MyFirstCoreApp
{
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
As you can see above, the Main() method calls method expression BuildWebHost() to
build web host with pre-configured defaults. The BuildWebHost expression can also be
written as a method that returns IWebHost as shown below.
The WebHost is a static class which can be used for creating an instance of IWebHost and
IWebHostBuilder with pre-configured defaults. The CreateDefaultBuilder() method
creates a new instance of WebHostBuilder with pre-configured defaults. Internally, it
configures Kestrel, IISIntegration and other configurations. The following is
CreateDefaultBuilder() method from the source code on GitHub.
CreateDefaultBuilder()
public static IWebHostBuilder CreateDefaultBuilder(string[] args)
{
var builder = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
var env = hostingContext.HostingEnvironment;
if (env.IsDevelopment())
{
var appAssembly = Assembly.Load(new
AssemblyName(env.ApplicationName));
if (appAssembly != null)
{
config.AddUserSecrets(appAssembly, optional: true);
}
}
config.AddEnvironmentVariables();
if (args != null)
{
config.AddCommandLine(args);
}
})
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging
"));
logging.AddConsole();
logging.AddDebug();
})
.UseIISIntegration()
.UseDefaultServiceProvider((context, options) =>
{
options.ValidateScopes =
context.HostingEnvironment.IsDevelopment();
});
return builder;
}
As you can see above, the CreateDefaultBuilder method creates an instance of
WebHostBuilder and sets up Kestrel, content root directory, IIS integration which is same
as ASP.NET Core 1.x Main() method.
Thus, Program.cs in ASP.NET Core 2.x makes it easy for us to setup a web host.
ASP.NET Core application must include Startup class. It is like Global.asax in the
traditional .NET application. As the name suggests, it is executed first when the application
starts.
The startup class can be configured using UseStartup<T>() method at the time of
configuring the host in the Main() method of Program class as shown below.
The name "Startup" is by ASP.NET Core convention. However, we can give any name to
the Startup class, just specify it as the generic parameter in the UseStartup<T>() method.
For example, to name the Startup class as MyStartup, specify it as
.UseStartup<MyStartup>().
Open Startup class in Visual Studio by clicking on the Startup.cs in the solution explorer.
The following is a default Startup class in ASP.NET Core 2.x.
startup.cs
As you can see, Startup class includes two public methods: ConfigureServices and
Configure.
The Startup class must include a Configure method and can optionally include
ConfigureService method.
ConfigureServices()
The ConfigureServices method is a place where you can register your dependent classes
with the built-in IoC container. After registering dependent class, it can be used anywhere
in the application. You just need to include it in the parameter of the constructor of a class
where you want to use it. The IoC container will inject it automatically.
ASP.NET Core refers dependent class as a Service. So, whenever you read "Service" then
understand it as a class which is going to be used in some other class.
The Configure method is a place where you can configure application request pipeline for
your application using IApplicationBuilder instance that is provided by the built-in IoC
container.
ASP.NET Core introduced the middleware components to define a request pipeline, which
will be executed on every request. You include only those middleware components which
are required by your application and thus increase the performance of your application.
As you can see, the Configure method includes three parameters IApplicationBuilder,
IHostingEnvironment, and ILoggerFactory by default. These services are framework
services injected by built-in IoC container.
At run time, the ConfigureServices method is called before the Configure method. This is
so that you can register your custom service with the IoC container which you may use in
the Configure method.
We created our first ASP.NET Core application using Visual Studio in the previous
chapter. Visual Studio internally uses this CLI to restore, build and publish an application.
Other higher level IDEs, editors and tools can use CLI to support .NET Core applications.
The .NET Core CLI is installed with .NET Core SDK for selected platforms. So we don't
need to install it separately on the development machine. We can verify whether the CLI is
installed properly by opening command prompt in Windows and writing dotnet and
pressing Enter. If it displays usage and help as shown below then it means it is installed
properly.
Command Structure
All the commands start with driver named dotnet. The driver starts the execution of the
specified command. After dotnet, we can supply command (also known as verb) to perform
a specific action. Each command can be followed by arguments and options. The following
are .NET Core 2.x CLI commands.
Run Runs source code without any explicit compile or launch commands.
Project Modification
Description
Commands
dotnet install script Script used to install the .NET Core CLI tools and the shared runtime.
Let's create, restore, build, and run .NET Core console application using command-line
interface without using Visual Studio.
To create a new .NET Core project, we have to use new command followed by template
name argument. We can create console, class library, web, mvc, webapi, razor, angular,
react etc. projects using CLI. Use console template to create a new .NET Core console
application.
The following creates new console project in the current directory with the same name as
current directory.
The following command creates a new console project named MyConsoleApp. The -n or --
name option species the name of a project.
After creating a project, navigate to the project directories in command prompt to apply
project specific commands which is C:\MyConsoleApp in our case.
We often need to add NuGet package reference for different purposes. For example, apply
the following command to add Newtonsoft.json package to our console project.
This will add Newtonsoft.json package to our project. We can verify it by opening .csproj
file.
Restore Packages
To restore packages or to update existing packages, we can use restore command as below.
C:\MyConsoleApp>dotnet restore
Build Project
Run project
To run our console project, apply dotnet run command as shown below.
As you can see above, it displays an output "Hello World!".
Getting Help
We can get help on any .NET Core CLI commands by typing -h or -help at the end of the
command we want to get help on. For example, dotnet new -h will display help on the new
command, arguments and options we can use with it, as shown below.
Thus, we can use .NET Core command-line interface to create, restore packages, build, run,
and publish different types of .NET Core applications.
ASP.NET Core framework contains simple out-of-the-box IoC container which does not
have as many features as other third party IoC containers. If you want more features such as
auto-registration, scanning, interceptors, or decorators then you may replace built-in IoC
container with a third party container.
In order to let the IoC container automatically inject our application services, we first need
to register them with IoC container.
Consider the following example of simple ILog interface and its implementation class. We
will see how to register it with built-in IoC container and use it in our application.
ASP.NET Core allows us to register our application services with IoC container, in the
ConfigureServices method of the Startup class. The ConfigureServices method
includes a parameter of IServiceCollection type which is used to register application
services.
Let's register above ILog with IoC container in ConfigureServices() method as shown
below.
As you can see above, Add() method of IServiceCollection instance is used to register a
service with an IoC container. The ServiceDescriptor is used to specify a service type and
its instance. We have specified ILog as service type and MyConsoleLogger as its instance.
This will register ILog service as a singleton by default. Now, an IoC container will create
a singleton object of MyConsoleLogger class and inject it in the constructor of classes
wherever we include ILog as a constructor or method parameter throughout the application.
Thus, we can register our custom application services with an IoC container in ASP.NET
Core application. There are other extension methods available for quick and easy
registration of services which we will see later in this chapter.
Built-in IoC container manages the lifetime of a registered service type. It automatically
disposes a service instance based on the specified lifetime.
1. Singleton: IoC container will create and share a single instance of a service throughout the
application's lifetime.
2. Transient: The IoC container will create a new instance of the specified service type every
time you ask for it.
3. Scoped: IoC container will create an instance of the specified service type once per
request and will be shared in a single request.
The following example shows how to register a service with different lifetimes.
services.Add(new ServiceDescriptor(typeof(ILog),
typeof(MyConsoleLogger), ServiceLifetime.Transient)); // Transient
services.Add(new ServiceDescriptor(typeof(ILog),
typeof(MyConsoleLogger), ServiceLifetime.Scoped)); // Scoped
}
Extension Methods for Registration
ASP.NET Core framework includes extension methods for each types of lifetime;
AddSingleton(), AddTransient() and AddScoped() methods for singleton, transient and
scoped lifetime respectively.
The following example shows the ways of registering types (service) using extension
methods.
services.AddTransient<ILog, MyConsoleLogger>();
services.AddTransient(typeof(ILog), typeof(MyConsoleLogger));
services.AddScoped<ILog, MyConsoleLogger>();
services.AddScoped(typeof(ILog), typeof(MyConsoleLogger));
}
Constructor Injection
Once we register a service, the IoC container automatically performs constructor injection
if a service type is included as a parameter in a constructor.
For example, we can use ILog service type in any MVC controller. Consider the following
example.
return View();
}
}
Sometimes we may only need dependency service type in a single action method. For this,
use [FromServices] attribute with the service type parameter in the method.
return View();
}
}
Property Injection
Built-in IoC container does not support property injection. You will have to use third party
IoC container.
return View();
}
}
Typically, there will be multiple middleware in ASP.NET Core web application. It can be
either framework provided middleware, added via NuGet or your own custom middleware.
We can set the order of middleware execution in the request pipeline. Each middleware
adds or modifies http request and optionally passes control to the next middleware
component. The following figure illustrates the execution of middleware components.
Middlewares build the request pipeline. The following figure illustrates the ASP.NET Core
request processing.
Configure Middleware
We can configure middleware in the Configure method of the Startup class using
IApplicationBuilder instance. The following example adds a single middleware using
Run method which returns a string "Hello World!" on each request.
});
We used Run extension method to add middleware. The following is the signature of the
Run method:
Method Signature:
public static void Run(this IApplicationBuilder app, RequestDelegate
handler)
Method Signature:
public delegate Task RequestDelegate(HttpContext context);
As you can see above, the Run method accepts a method as a parameter whose signature
should match with RequestDelegate. Therefore, the method should accept the
HttpContext parameter and return Task. So, you can either specify a lambda expression or
specify a function in the Run method. The lambda expression specified in the Run method
above is similar to the one in the example shown below.
The above MyMiddleware function is not asynchronous and so will block the thread till the
time it completes the execution. So, make it asynchronous by using async and await to
improve performance and scalability.
//or
Mostly there will be multiple middleware components in ASP.NET Core application which
will be executed sequentially. The Run method adds a terminal middleware so it cannot call
next middleware as it would be the last middleware in a sequence. The following will
always execute the first Run method and will never reach the second Run method.
Example: Use()
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
await context.Response.WriteAsync("Hello World From 1st
Middleware!");
await next();
});
The above example will display Hello World From 1st Middleware!Hello World
From 2nd Middleware! in the browser.
Thus, we can use Use() method to configure multiple middlewares in the order we like.
ASP.NET Core is a modular framework. We can add server side features we need in our
application by installing different plug-ins via NuGet. There are many middleware plug-ins
available which can be used in our application.
Middleware Description
StaticFiles Adds support for serving static files and directory browsing.
Diagnostics Adds support for reporting and handling exceptions and errors.
Diagnostics Middleware
Let's install and use Diagnostics middleware. Diagnostics middleware is used for reporting
and handling exceptions and errors in ASP.NET Core, and diagnosing Entity Framework
Core migrations errors.
This package includes following middleware and extension methods for it.
We can call respective Use* extension methods to use the above middleware in the
configure method of Startup class.
Let's add welcomePage middleware which will display welcome page for the root path.
Example: Add Diagnostics Middleware
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseWelcomePage();
//other code removed for clarity
}
The above example will display the following welcome page for each request.
This way we can use different Use* extension methods to include different middleware.
Next, learn how to implement logging functionality in the ASP.NET Core application.
Before we see how to implement logging in ASP.NET Core application, let's understand
the important logging interfaces and classes available in ASP.NET Core framework. The
following are built-in interfaces and classes available for logging under
Microsoft.Extensions.Logging namespace .
1. ILoggingFactory
2. ILoggingProvider
3. ILogger
4. LoggingFactory
Logging Infrastructure
ILoggerFactory
The ILoggerFactory is the factory interface for creating an appropriate ILogger type
instance and also to add ILoggerProvider instance.
ILoggerFactory:
public interface ILoggerFactory : IDisposable
{
ILogger CreateLogger(string categoryName);
void AddProvider(ILoggerProvider provider);
}
ASP.NET Core runtime creates an instance of LoggerFactory class and registers it for
ILoggerFactory with the built-in IoC container when the application starts. Thus, we can
use ILoggerFactory interface anywhere in your application. The IoC container will pass
an instance of LoggerFactory to your application wherever it encounters ILoggerFactory
type.
ILoggerProvider
ILoggerProvider:
public interface ILoggerProvider : IDisposable
{
ILogger CreateLogger(string categoryName);
}
ILogger
ILogger:
public interface ILogger
{
void Log<TState>(LogLevel logLevel, EventId eventId, TState state,
Exception exception, Func<TState, Exception, string> formatter);
bool IsEnabled(LogLevel logLevel);
IDisposable BeginScope<TState>(TState state);
}
Built-in Logging Providers
There are different logging providers available as NuGet packages which we can use to
send log output to the different medium such as console, debug window, EventSource etc.
ASP.NET Core ships with the following providers:
1. Console
2. Debug
3. EventSource
4. EventLog
5. TraceSource
6. Azure App Service
Console Logger
1. ConsoleLoggingProvider
2. ConsoleLogger
3. ConsoleLoggerExtension
4. ConsoleLoggerSettings
5. ConsoleLoggerScope
As you can see in the above figure, the ConsoleLogger implements ILogger and
ConsoleLoggingProvider implements ILoggingProvider. The
ConsoleLoggerExtensions class includes extension method AddConsole() which adds
console logger to LoggerFactory.
Now, let's use console logger to display log output to the console in both ASP.NET Core
1.x and 2.x application.
"dependencies": {
"Microsoft.NETCore.App": {
"version": "1.0.1",
"type": "platform"
},
"Microsoft.AspNetCore.Diagnostics": "1.0.0",
"Microsoft.AspNetCore.Server.IISIntegration": "1.0.0",
"Microsoft.AspNetCore.Server.Kestrel": "1.0.1",
"Microsoft.Extensions.Logging.Console": "1.0.0"
}
Visual Studio will restore the packages automatically as soon as project.json is saved.
Now, in order to use console logger, we first need to configure it. First, we need to add
ConsoleLoggerProvider to the providers list using LoggerFactory. As you can see in the
LoggerFactory class above, it provides AddProvider() method which adds our custom
ILoggerProvider type instance to the list. The
Microsoft.Extensions.Logging.Console package includes all necessary classes. So, we
can add ConsoleLoggerProvider instance as shown below.
We can also use AddConsole() extension method instead of configuring console logger
manually as shown below.
This step is applicable for both ASP.NET Core 1.x and 2.x application.
Now, we can create logs and see it on the console by getting an instance of ILogger using
LoggerFactory and start logging as shown below.
loggerFactory.AddConsole();
We can also use ILogger anywhere in our application. IoC container will inject
ConsoleLogger instance wherever it sees ILogger. For example, we can use ILogger in
the MVC-controller as shown below.
return View();
}
}
You will see the above log on the console when you browse
http://localhost:5000/home/index.
We can use any of the above mentioned built-in logging providers by following the same
process.
Log Levels
Log levels indicate the importance or severity of the log messages. Built-in log providers
include extension methods to indicate log levels.
Extension
Log Level Severity Description
Method
Trace 0 LogTrace() Log messages only for tracing purpose for the developers
We can use extension method to indicate level of the log messages as shown below.
if (String. IsNullOrEmpty(id))
{
_logger.LogWarning(LoggingEvents.GET_ITEM_NOTFOUND,
"Index({ID}) NOT FOUND", id);
return NotFound();
}
return View();
}
}
Third-party Logging Providers
The following are some logging providers that work with ASP.NET Core:
Ope
n Project Properties
This will open properties page. Click on Debug tab and you will see Environment Variables
as shown below.
Environment Variable
You may change the value as per your need. This value will be saved in the
launchSettings.json file as shown below.
launchsettings.json
We can get the value of an environment variable in our code to execute some additional
code based on its value. The IHostingEnvironment service includes EnvironmentName
property which contains the value of ASPNETCORE_ENVIRONMENT variable. ASP.NET Core
also includes extension methods to check the environment such as IsDevelopment(),
IsStating(), IsEnvironment() and IsProduction().
The IHostingEnvironment service is provided by ASP.NET hosting layer and can be used
anywhere in your application via Dependency Injection. The following example shows how
we can check the environment variable in the Configure method of Startup class.
Example: Access Environment Variable
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsEnvironment("Development"))
{
// code to be executed in development environment
if (env.IsDevelopment())
{
// code to be executed in development environment
if (env.IsStaging())
{
// code to be executed in staging environment
if (env.IsProduction())
{
// code to be executed in production environment
}
}
Learn all about exception handling in ASP.NET Core application and how this environment
variable can be used there, in the next chapter.
By default, ASP.NET Core returns a simple status code for any exception that occurs in an
application. Consider the following example of Configure method which throws an error.
1. UseDeveloperExceptionPage
2. UseExceptionHandler
UseDeveloperExceptionPage
Exception Handling
As you can see above, the developer exception page includes 4 tabs: Stack, Query, Cookies,
and Headers. Stack tab displays information of stack trace, which indicates where exactly
an error occurred. Query tab displays information about query string. Cookies tab displays
information about cookies set by the request and Headers tab displays information about
headers.
UseExceptionHandler
In MVC Core application, we might want some other controller to handle all exceptions
and display custom user friendly error messages. The UseExceptionHandler extension
method allows us to configure custom error handling route. This is useful when an
application runs under production environment.
Example: Exception Handler in MVC
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment() || env.IsStaging())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
HomeController:
public class HomeController : Controller
{
public HomeController()
{
}
Error.cshtml
@{
ViewData["Title"] = "Error";
}
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your
request.</h2>
<h3>Development Mode</h3>
<p>
Swapping to <strong>Development</strong> environment will display
more detailed information about the error that occurred.
</p>
<p>
<strong>Development environment should not be enabled in deployed
applications</strong>, as it can result in sensitive information from
exceptions being displayed to end users. For local debugging, development
environment can be enabled by setting the
<strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to
<strong>Development</strong>, and restarting the application.
</p>
Exception Handling
Note:
Visual Studio automatically creates Error.cshtml under Home folder when you create ASP.NET
Core project with MVC template.
To install StaticFiles middleware in ASP.NET Core 1.x application, open NuGet package
manager by right clicking on project in the solution explorer and select Manage NuGet
Packages... Search for staticfiles in the search box in the browse tab. This will display
Microsoft.AspNetCore.StaticFiles middleware as shown below.
Click on the Install button on the right pane to install it. Once installed, the
Microsoft.AspNetCore.StaticFiles is automatically included in the dependencies
section of the project.json.
StaticFiles
Dependency in project.json
By default, all the static files of a web application should be located in the web root folder
wwwroot. To understand this, let's create a simple default.html in the wwwroot folder with
the following content.
Default.html
Now, to serve the above Default.html static file, we must add StaticFiles middleware in the
Configure() method of Startup file as shown below.
As you can see above, the app.UseStaticFiles() method adds StaticFiles middleware
into the request pipeline. The UseStaticFiles is an extension method included in the
StaticFiles middleware so that we can easily configure it.
Now, open the browser and send http request http://localhost:<port>/default.html which
will display default.html as a response as shown below.
Serving HTML File
This way we can serve any other file stored in wwwroot folder or sub-folder. For example,
consider the following test.js file in the wwwroot folder.
test.js
Suppose, you want to serve files from the outside of web root folder (wwwroot). For
example, you include images in the following Images folder as shown below.
Serving Static Files
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(),
@"Images")),
RequestPath = new PathString("/app-images")
});
}
As you can see, we used FileProvider option to specify Images folder from which static
files will be served. The RequestPath option specifies the relative path in the URL which
maps to the static folder.
As we have seen above, default.html or test.js was served on the specific request for it.
However, what if we want to serve default html file on the root request?
Currently, when you send http://localhost:<port> request, it will be handled by run method
and display the following result.
Note:
FileServer
Example: UseFileServer
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseFileServer();
1. Portable Application
2. Self-contained application
Portable Application
Portable applications are applications which expect .NET Core runtime on the deployment
machines. It cannot be run on a machine which does not have .NET Core runtime installed.
.NET
Core Portable Application
Self-contained Application
Self-contained applications are applications which include .NET Core runtime when we
publish it. It can run on a machine which does not have .NET Core runtime installed.
.NET Frameworks
These frameworks use different framework class libraries. It means code written in one
framework cannot be used with other frameworks. For example, a console application
developed with .NET Framework cannot run on .NET Core or vice-versa. Thus, code-
sharing is not allowed.
It would be nice to write code once and share with other applications with different .NET
frameworks. Isn't it?
Code Sharing
To solve this problem of code sharing, we can use the following three approaches:
Creating portable class library to share code with other .NET frameworks is not a new thing
in .NET. Learn about it here.
Learn about how to target multiple frameworks in ASP.NET Core application for code
sharing in the next chapter.
We can create .NET Core application and configure multiple target frameworks for it so
that it can run with all the configured target frameworks. To demonstrate this, let's
create .NET Core 2.0 console application which can run with .NET Core as well as
traditional .NET framework in Visual Studio 2017.
The first step is to create a new project in Visual Studio 2017 by clicking on File -> New
Project.. This will open New Project popup as shown below.
Create .NET Core 2.x Console Application
In the New Project popup, select Console Application (.NET Core), provide the appropriate
name and click OK. This will create new console project as shown below.
Console Application
Now, we can configure multiple frameworks by editing .csproj file. So, right click on the
project in solution explorer and select Edit <project-name>.csproj as shown below.
Edit .csproj
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.0</TargetFramework>
</PropertyGroup>
</Project>
Here, we will support two more frameworks .NET Framework 4.0 & 4.6. So include net40
and net46 monikers respectively as shown below. Look at TFMs for all supported target
frameworks here.
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net45;net46</TargetFrameworks>
</PropertyGroup>
</Project>
As soon as you save the above .csproj file, Visual Studio will load and include the
references for .NET 4.5 and .NET 4.6 into Dependencies section as shown below.
Multi Frameworks Dependencies
Now, open program.cs and let's add framework specific code using preprocessor conditions
#if and #elif as shown below.
Program.cs
using System;
namespace MultiFrameworkConsole
{
public class Program
{
public static void Main(string[] args)
{
#if NET40
Console.WriteLine("Target framework: .NET Framework 4.0");
#elif NET45
Console.WriteLine("Target framework: .NET Framework 4.5");
#else
Console.WriteLine("Target framework: .NET Core 2.0");
#endif
Console.ReadKey();
}
}
}
As you can see above, to write framework specific code, use symbol with condition
for .NET framework moniker and replace the dot with an underscore and change lowercase
letters to uppercase.
To run the application for specific framework, click on the run dropdown and select a
targeted framework as shown below.
Multi
Frameworks Dependencies
Now, run the application and you will see the following output.
Framework Specific References
Sometimes you may need to include specific references for a particular framework. For
example, .NET Core 2.0 meta package already includes System.Net reference which is not
included in .NET 4.0 and 4.5. So, we need to include it in .csproj file using conditional
reference as shown below.
.csproj:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.0;net45;net46</TargetFrameworks>
</PropertyGroup>
</Project>
Now, System.Net reference will be added to .NET 4.0 & 4.5 and System.Net specific code
will be executed for all frameworks.
ASP.NET MVC Tutorials
ASP.NET MVC tutorials cover all the features of ASP.NET MVC. You will learn basic to
advance level features of ASP.Net MVC. Basic tutorials have used MVC 5, but it is
applicable to all the previous versions and upcoming versions of MVC as well.
These tutorials are designed for beginners and professionals who want to learn ASP.NET
MVC 5 step by step.
Prerequisites
MVC Architecture
In this section, you will get an overview of MVC architecture. The MVC architectural
pattern has existed for a long time in software engineering. All most all the languages use
MVC with slight variation, but conceptually it remains the same.
MVC stands for Model, View and Controller. MVC separates application into three
components - Model, View and Controller.
Model: Model represents shape of the data and business logic. It maintains the data of the
application. Model objects retrieve and store model state in a database.
View: View is a user interface. View display data using model to the user and also enables
them to modify the data.
Controller: Controller handles the user request. Typically, user interact with View, which
in-tern raises appropriate URL request, this request will be handled by a controller. The
controller renders the appropriate view with the model data as a response.
The following figure illustrates the interaction between Model, View and Controller.
MVC Architecture
The following figure illustrates the flow of the user's request in ASP.NET MVC.
Reque
st/Response in MVC Architecture
As per the above figure, when the user enters a URL in the browser, it goes to the server
and calls appropriate controller. Then, the Controller uses the appropriate View and Model
and creates the response and sends it back to the user. We will see the details of the
interaction in the next few sections.
Points to Remember :
Area
Asynchronous controller
Html helper methods with
lambda expression
.Net 10-Mar-
MVC 2.0 VS 2008, DataAnnotations attributes
3.5/4.0 2010
Client side validation
Custom template
Scaffolding
Unobtrusive javascript
validation
Razor view engine
13-Jan- Global filters
MVC 3.0 VS 2010 .Net 4.0
2011 Remote validation
Dependency resolver for IoC
ViewBag
You can develop ASP.NET MVC application with appropriate version of Visual Studio and
.NET framework, as you have seen in the previous section of version history.
Here, we will use MVC v5.2, Visual Studio 2017 Community edition and .NET framework
4.6 to create our first MVC application.
First of all, open a Visual Studio 2017 Community edition and select File menu -> New ->
Project as shown below.
Create a New Project in Visual Studio
From the New Project dialog as shown below, expand Visual C# node and select Web in
the left pane, and then select ASP.NET Web Application (.NET Framework) in the
middle pane. Enter the name of your project MyMVCApplication. (You can give any
appropriate name for your application). Also, you can change the location of the MVC
application by clicking on Browse.. button. Finally, click OK.
Create MVC Project in Visual Studio
From the New ASP.NET Web Application dialog, select MVC (if not selected already) as
shown below.
Create MVC Application
You can also change the authentication by clicking on Change Authentication button.
You can select appropriate authentication mode for your application as shown below.
Select Authenctication Type
Here, we are keeping the default authentication for our application which is No
Authentication. Click OK to continue.
Wait for some time till Visual Studio creates a simple MVC project using default template
as shown below.
First MVC Application
Now, press F5 to run the project in debug mode or Ctrl + F5 to run the project without
debugging. It will open home page in the browser as shown below.
Run MVC Application
MVC 5 project includes JavaScript and CSS files of bootstrap 3.0 by default. So you can
create responsive web pages. This responsive UI will change its look and feel based on the
screen size of the different devices. For example, top menu bar will be changed in the
mobile devices as shown below.
Responsive MVC Application
So in this way, you can create your first MVC 5 application using Visual Studio 2013 for
Web.
App_Data
App_Data folder can contain application data files like LocalDB, .mdf files, xml files and
other data related files. IIS will never serve files from App_Data folder.
App_Start
App_Start folder can contain class files which will be executed when the application starts.
Typically, these would be config files like AuthConfig.cs, BundleConfig.cs,
FilterConfig.cs, RouteConfig.cs etc. MVC 5 includes BundleConfig.cs, FilterConfig.cs and
RouteConfig.cs by default. We will see significance of these files later.
App_Start Folder
Content
Content folder contains static files like css files, images and icons files. MVC 5 application
includes bootstrap.css, bootstrap.min.css and Site.css by default.
Content Folder
Controllers
Controllers folder contains class files for the controllers. Controllers handles users' request
and returns a response. MVC requires the name of all controller files to end with
"Controller". You will learn about the controller in the next section.
Controller Folder
fonts
Fonts folder
Models
Models folder contains model class files. Typically model class includes public properties,
which will be used by application to hold and manipulate application data.
Scripts
Scripts folder contains JavaScript or VBScript files for the application. MVC 5 includes
javascript files for bootstrap, jquery 1.10 and modernizer by default.
Scripts Folder
Views
Views folder contains html files for the application. Typically view file is a .cshtml file
where you write html and C# or VB.NET code.
Views folder includes separate folder for each controllers. For example, all the .cshtml
files, which will be rendered by HomeController will be in View > Home folder.
Shared folder under View folder contains all the views which will be shared among
different controllers e.g. layout files.
View Folder
Global.asax
Global.asax allows you to write code that runs in response to application level events, such
as Application_BeginRequest, application_start, application_error, session_start,
session_end etc.
Packages.config
Packages.config file is managed by NuGet to keep track of what packages and versions you
have installed in the application.
Web.config
Web.config file contains application level configurations.
Learn how MVC framework handles request using routing in the next section.
Routing in MVC
In the ASP.NET Web Forms application, every URL must match with a specific .aspx file.
For example, a URL http://domain/studentsinfo.aspx must match with the file
studentsinfo.aspx that contains code and markup for rendering a response to the browser.
Routing is not specific to MVC framework. It can be used with ASP.NET Webform
application or MVC application.
ASP.NET introduced Routing to eliminate needs of mapping each URL with a physical
file. Routing enable us to define URL pattern that maps to the request handler. This request
handler can be a file or class. In ASP.NET Webform application, request handler is .aspx
file and in MVC, it is Controller class and Action method. For example,
http://domain/students can be mapped to http://domain/studentsinfo.aspx in ASP.NET
Webforms and the same URL can be mapped to Student Controller and Index action
method in MVC.
Route
Route defines the URL pattern and handler information. All the configured routes of an
application stored in RouteTable and will be used by Routing engine to determine
appropriate handler class or file for an incoming request.
Configure a Route
Every MVC application must configure (register) at least one route, which is configured by
MVC framework by default. You can register a route in RouteConfig class, which is in
RouteConfig.cs under App_Start folder. The following figure illustrates how to configure
a Route in the RouteConfig class .
The same way, you can configure other routes using MapRoute method of RouteCollection.
This RouteCollection is actually a property of RouteTable class.
URL Pattern
The URL pattern is considered only after domain name part in the URL. For example, the
URL pattern "{controller}/{action}/{id}" would look like
localhost:1234/{controller}/{action}/{id}. Anything after "localhost:1234/" would be
considered as controller name. The same way, anything after controller name would be
considered as action name and then value of id parameter.
Routing in MVC
If the URL doesn't contain anything after domain name then the default controller and
action method will handle the request. For example, http://lcoalhost:1234 would be handled
by HomeController and Index method as configured in the defaults parameter.
The following table shows which Controller, Action method and Id parameter would
handle different URLs considering above default route.
You can also configure a custom route using MapRoute extension method. You need to
provide at least two parameters in MapRoute, route name and url pattern. The Defaults
parameter is optional.
You can register multiple custom routes with different names. Consider the following
example where we register "Student" route.
routes.MapRoute(
name: "Student",
url: "students/{id}",
defaults: new { controller = "Student", action = "Index"}
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id =
UrlParameter.Optional }
);
}
}
As shown in the above code, URL pattern for the Student route is students/{id}, which
specifies that any URL that starts with domainName/students, must be handled by
StudentController. Notice that we haven't specified {action} in the URL pattern because we
want every URL that starts with student should always use Index action of
StudentController. We have specified default controller and action to handle any URL
request which starts from domainname/students.
MVC framework evaluates each route in sequence. It starts with first configured route and
if incoming url doesn't satisfy the URL pattern of the route then it will evaluate second
route and so on. In the above example, routing engine will evaluate Student route first and
if incoming url doesn't starts with /students then only it will consider second route which is
default route.
The following table shows how different URLs will be mapped to Student route:
Route Constraints
You can also apply restrictions on the value of parameter by configuring route constraints.
For example, the following route applies a restriction on id parameter that the value of an id
must be numeric.
So if you give non-numeric value for id parameter then that request will be handled by
another route or, if there are no matching routes then "The resource could not be found"
error will be thrown.
Register Routes
Now, after configuring all the routes in RouteConfig class, you need to register it in the
Application_Start() event in the Global.asax. So that it includes all your routes into
RouteTable.
Points to Remember :
1. Routing plays important role in MVC framework. Routing maps URL to physical file or class
(controller class in MVC).
2. Route contains URL pattern and handler information. URL pattern starts after domain
name.
3. Routes can be configured in RouteConfig class. Multiple custom routes can also be
configured.
4. Route constraints applies restrictions on the value of parameters.
5. Route must be registered in Application_Start event in Global.ascx.cs file.
Controller
In this section, you will learn about the Controller in ASP.NET MVC.
The Controller in MVC architecture handles any incoming URL request. Controller is a
class, derived from the base class System.Web.Mvc.Controller. Controller class contains
public methods called Action methods. Controller and its action method handles incoming
browser requests, retrieves necessary model data and returns appropriate responses.
In ASP.NET MVC, every controller class name must end with a word "Controller". For
example, controller for home page must be HomeController and controller for student must
be StudentController. Also, every controller class must be located in Controller folder of
MVC folder structure.
Now, let's add a new empty controller in our MVC application in Visual Studio.
MVC will throw "The resource cannot be found" error when you do not append
"Controller" to the controller class name.
In the previous section we learned how to create our first MVC application, which in turn
created a default HomeController. Here, we will create a new StudentController.
In the Visual Studio, right click on the Controller folder -> select Add -> click on
Controller..
Add New Controller
Note:
Scaffolding is an automatic code generation framework for ASP.NET web applications. Scaffolding
reduces the time taken to develop a controller, view etc. in MVC framework. You can develop a
customized scaffolding template using T4 templates as per your architecture and coding standard.
Adding Controller
Add Scaffold dialog contains different templates to create a new controller. We will learn
about other templates later. For now, select "MVC 5 Controller - Empty" and click Add.
It will open Add Controller dialog as shown below
Adding Controller
In the Add Controller dialog, enter the name of the controller. Remember, controller name
must end with Controller. Let's enter StudentController and click Add.
Adding Controller
This will create StudentController class with Index method in StudentController.cs file
under Controllers folder, as shown below.
Example: Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
// GET: Student
public ActionResult Index()
{
return View();
}
}
}
As you can see above, the StudentController class is derived from Controller class. Every
controller in MVC must derived from this abstract Controller class. This base Controller
class contains helper methods that can be used for various purposes.
Now, we will return a dummy string from Index action method of above StudentController.
Changing the return type of Index method from ActionResult to string and returning
dummy string is shown below. You will learn about ActionResult in the next section.
Example: Controller
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
// GET: Student
public string Index()
{
return "This is Index action method of
StudentController";
}
}
}
We have already seen in the routing section that the URL request http://localhost/student or
http://localhost/student/index is handled by the Index() method of StudentController class,
shown above. So let's invoke it from the browser and you will see the following page in the
browser.
Controller
Points to Remember :
1. A Controller handles incomming URL requests. MVC routing sends request to appropriate
controller and action method based on URL and configured Routes.
2. All the public methods in the Controlle class are called Action methods.
3. A Controller class must be derived from System.Web.Mvc.Controller class.
4. A Controller class name must end with "Controller".
5. New controller can be created using different scaffolding templates. You can create
custom scaffolding template also.
Action method
In this section, you will learn about the action method of controller class.
All the public methods of a Controller class are called Action methods. They are like any
other normal methods with the following restrictions:
1. Action method must be public. It cannot be private or protected
2. Action method cannot be overloaded
3. Action method cannot be a static method.
Action Method
As you can see in the above figure, Index method is a public method and it returns
ActionResult using the View() method. The View() method is defined in the Controller
base class, which returns the appropriate ActionResult.
Every controller can have default action method as per configured route in RouteConfig
class. By default, Index is a default action method for any controller, as per configured
default root as shown below.
Default Route:
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}/{name}",
defaults: new { controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
However, you can change the default action name as per your requirement in RouteConfig
class.
ActionResult
MVC framework includes various result classes, which can be return from an action
methods. There result classes represent different types of responses such as html, file,
string, json, javascript etc. The following table lists all the result classes available in
ASP.NET MVC.
Result Class Description
FileContentResult/ FilePathResult/
Represents the content of a file
FileStreamResult
The ActionResult class is a base class of all the above result classes, so it can be return type
of action methods which returns any type of result listed above. However, you can specify
appropriate result class as a return type of action method.
The Index() method of StudentController in the above figure uses View() method to return
ViewResult (which is derived from ActionResult). The View() method is defined in base
Controller class. It also contains different methods, which automatically returns particular
type of result as shown in the below table.
Base Controller
Result Class Description
Method
FileContentResult,
FilePathResult, Represents the content of a file File()
FileStreamResult
As you can see in the above table, View method returns ViewResult, Content method
returns string, File method returns content of a file and so on. Use different methods
mentioned in the above table, to return different types of results from an action method.
Every action methods can have input parameters as normal methods. It can be primitive
data type or complex type parameters as shown in the below example.
return RedirectToAction("Index");
}
[HttpDelete]
public ActionResult Delete(int id)
{
// delete student from the database whose id matches with specified
id
return RedirectToAction("Index");
}
By default, the values for action method parameters are retrieved from the request's data
collection. The data collection includes name/values pairs for form data or query string
values or cookie values. Model binding in ASP.NET MVC automatically maps the URL
query string or form data collection to the action method parameters if both names are
matching. Visit model binding section for more information on it.
Points to Remember :
1. All the public methods in the Controller class are called Action methods.
2. Action method has following restrictions.
- Action method must be public. It cannot be private or protected.
- Action method cannot be overloaded.
- Action method cannot be a static method.
3. ActionResult is a base class of all the result type which returns from Action method.
4. Base Controller class contains methods that returns appropriate result type e.g. View(),
Content(), File(), JavaScript() etc.
5. Action method can include Nullable type parameters.
Action Selectors
Action selector is the attribute that can be applied to the action methods. It helps routing
engine to select the correct action method to handle a particular request. MVC 5 includes
the following action selector attributes:
1. ActionName
2. NonAction
3. ActionVerbs
ActionName
ActionName attribute allows us to specify a different action name than the method name.
Consider the following example.
Example: ActionName
public class StudentController : Controller
{
public StudentController()
{
[ActionName("find")]
public ActionResult GetById(int id)
{
// get student from the database
return View();
}
}
NonAction selector attribute indicates that a public method of a Controller is not an action
method. Use NonAction attribute when you want public method in a controller but do not
want to treat it as an action method.
For example, the GetStudent() public method cannot be invoked in the same way as action
method in the following example.
Example: NonAction
public class StudentController : Controller
{
public StudentController()
{
[NonAction]
public Student GetStudnet(int id)
{
return studentList.Where(s => s.StudentId ==
id).FirstOrDefault();
}
}
Points to Remember :
1. MVC framework routing engine uses Action Selectors attributes to determine which action
method to invoke.
2. Three action selectors attributes are available in MVC 5
- ActionName
- NonAction
- ActionVerbs
3. ActionName attribute is used to specify different name of action than method name.
4. NonAction attribute marks the public method of controller class as non-action method. It
cannot be invoked.
ActionVerbs
In this section, you will learn about the ActionVerbs selectors attribute.
The ActionVerbs selector is used when you want to control the selection of an action
method based on a Http request method. For example, you can define two different action
methods with the same name but one action method responds to an HTTP Get request and
another action method responds to an HTTP Post request.
MVC framework supports different ActionVerbs, such as HttpGet, HttpPost, HttpPut,
HttpDelete, HttpOptions & HttpPatch. You can apply these attributes to action method to
indicate the kind of Http request the action method supports. If you do not apply any
attribute then it considers it a GET request by default.
The following figure illustrates the HttpGET and HttpPOST action verbs.
ActionVerbs
Http
Usage
method
To retrieve the information from the server. Parameters will be appended in
GET
the query string.
POST To create a new resource.
PUT To update an existing resource.
HEAD Identical to GET except that server do not return message body.
OPTIONS method represents a request for information about the
OPTIONS
communication options supported by web server.
DELETE To delete an existing resource.
PATCH To full or partial update the resource.
The following example shows different action methods supports different ActionVerbs:
Example: ActionVerbs
public class StudentController : Controller
{
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult PostAction()
{
return View("Index");
}
[HttpPut]
public ActionResult PutAction()
{
return View("Index");
}
[HttpDelete]
public ActionResult DeleteAction()
{
return View("Index");
}
[HttpHead]
public ActionResult HeadAction()
{
return View("Index");
}
[HttpOptions]
public ActionResult OptionsAction()
{
return View("Index");
}
[HttpPatch]
public ActionResult PatchAction()
{
return View("Index");
}
}
You can also apply multiple http verbs using AcceptVerbs attribute. GetAndPostAction
method supports both, GET and POST ActionVerbs in the following example:
Example: AcceptVerbs
[AcceptVerbs(HttpVerbs.Post | HttpVerbs.Get)]
public ActionResult GetAndPostAction()
{
return RedirectToAction("Index");
}
Points to Remember :
1. ActionVerbs are another Action Selectors which selects an action method based on
request methods e.g POST, GET, PUT etc.
2. Multiple action methods can have same name with different action verbs. Method
overloading rules are applicable.
3. Multiple action verbs can be applied to a single action method using AcceptVerbs
attribute.
Model represents domain specific data and business logic in MVC architecture. It maintains
the data of the application. Model objects retrieve and store model state in the persistance
store like a database.
Model class holds data in public properties. All the Model classes reside in the Model
folder in MVC folder structure.
Adding a Model
Open our first MVC project created in previous step in the Visual Studio. Right click on
Model folder -> Add -> click on Class..
In the Add New Item dialog box, enter class name 'Student' and click Add.
Create Model Class
This will add new Student class in model folder. Now, add Id, Name, Age properties as
shown below.
So in this way, you can create a model class which you can use in View. You will learn
how to implement validations using model later.
ASP.NET MVC views are stored in Views folder. Different action methods of a single
controller class can render different views, so the Views folder contains a separate folder
for each controller with the same name as controller, in order to accommodate multiple
views. For example, views, which will be rendered from any of the action methods of
HomeController, resides in Views > Home folder. In the same way, views which will be
rendered from StudentController, will resides in Views > Student folder as shown below.
Note:
Shared folder contains views, layouts or partial views which will be shared among multiple views.
Microsoft introduced the Razor view engine and packaged with MVC 3. You can write a
mix of html tags and server side code in razor view. Razor uses @ character for server side
code instead of traditional <% %>. You can use C# or Visual Basic syntax to write server
side code inside razor view. Razor view engine maximize the speed of writing code by
minimizing the number of characters and keystrokes required when writing a view. Razor
views files have .cshtml or vbhtml extension.
.vbhtml Visual Basic Razor view. Supports Visual Basic with html tags.
Learn Razor syntax in the next section. Let's see how to create a new view using Visual
Studio 2013 for Web with MVC 5.
We have already created StudentController and Student model in the previous section.
Now, let's create a Student view and understand how to use model into view.
We will create a view, which will be rendered from Index method of StudentContoller. So,
open a StudentController class -> right click inside Index method -> click Add View..
Create a View
In the Add View dialogue box, keep the view name as Index. It's good practice to keep the
view name the same as the action method name so that you don't have to specify view name
explicitly in the action method while returning the view.
Select the scaffolding template. Template dropdown will show default templates available
for Create, Delete, Details, Edit, List or Empty view. Select "List" template because we
want to show list of students in the view.
View
Now, select Student from the Model class dropdrown. Model class dropdown automatically
displays the name of all the classes in the Model folder. We have already created Student
Model class in the previous section, so it would be included in the dropdown.
View
Check "Use a layout page" checkbox and select _Layout.cshtml page for this view and then
click Add button. We will see later what is layout page but for now think it like a master
page in MVC.
This will create Index view under View -> Student folder as shown below:
View
Views\Student\Index.cshtml:
@model IEnumerable<MVC_BasicTutorials.Models.Student>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.StudentName)
</th>
<th>
@Html.DisplayNameFor(model => model.Age)
</th>
<th></th>
</tr>
</table>
As you can see in the above Index view, it contains both Html and razor codes. Inline razor
expression starts with @ symbol. @Html is a helper class to generate html controls. You
will learn razor syntax and html helpers in the coming sections.
In
dex.cshtml
Note:
Every view in the ASP.NET MVC is derived from WebViewPage class included in System.Web.Mvc
namespace.
Points to Remember :
1. View is a User Interface which displays data and handles user interaction.
2. Views folder contains separate folder for each controller.
3. ASP.NET MVC supports Razor view engine in addition to traditional .aspx engine.
4. Razor view files has .cshtml or .vbhtml extension.
Example: StudentController
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
// GET: Student
public ActionResult Index()
{
return View();
}
}
}
Example: Student Model class
namespace MVC_BasicTutorials.Models
{
public class Student
{
public int StudentId { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
}
}
Example: Index.cshtml to display student list
@model IEnumerable<MVC_BasicTutorials.Models.Student>
@{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
<p>
@Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
@Html.DisplayNameFor(model => model.StudentName)
</th>
<th>
@Html.DisplayNameFor(model => model.Age)
</th>
<th></th>
</tr>
</table>
Now, to run it successfully, we need to pass a model object from controller to Index view.
As you can see in the above Index.cshtml, it uses IEnumerable of Student as a model
object. So we need to pass IEnumerable of Student model from the Index action method of
StudentController class as shown below.
return View(studentList);
}
}
As you can see in the above code, we have created a List of student objects for an example
purpose (in real life applicatoin, you can fetch it from the database). We then pass this list
object as a parameter in the View() method. The View() method is defined in base
Controller class, which automatically binds model object to the view.
Now, you can run the MVC project by pressing F5 and navigate to http://localhost/Student.
You will see following view in the browser.
Razor Syntax
Razor is one of the view engine supported in ASP.NET MVC. Razor allows you to write
mix of HTML and server side code using C# or Visual Basic. Razor view with visual basic
syntax has .vbhtml file extension and C# syntax has .cshtml file extension.
Compact: Razor syntax is compact which enables you to minimize number of characters
and keystrokes required to write a code.
Easy to Learn: Razor syntax is easy to learn where you can use your familiar language C#
or Visual Basic.
Intellisense: Razor syntax supports statement completion within Visual Studio.
Inline expression
Start with @ symbol to write server side C# or VB code with Html code. For example,
write @Variable_Name to display a value of a server side variable. For example,
DateTime.Now returns a current date and time. So, write @DateTime.Now to display
current datetime as shown below. A single line expression does not require a semicolon at
the end of the expression.
C# Razor Syntax
<h1>Razor syntax demo</h1>
<h2>@DateTime.Now.ToShortDateString()</h2>
Output:
Razor syntax demo
08-09-2014
Multi-statement Code block
You can write multiple line of server side code enclosed in braces @{ ... }. Each line
must ends with semicolon same as C#.
Write if-else condition starting with @ symbol. The if-else code block must be enclosed in
braces { }, even for single statement.
<h2>Student Detail:</h2>
<ul>
<li>Student Id: @Model.StudentId</li>
<li>Student Name: @Model.StudentName</li>
<li>Age: @Model.Age</li>
</ul>
Output:
Student Detail:
- Student Id: 1
- Student Name: John
- Age: 18
Declare Variables
Declare a variable in a code block enclosed in brackets and then use those variables inside
html with @ symbol.
if(1 > 0)
{
str = "Hello World!";
}
}
<p>@str</p>
Output:
Hello World!
So this was some of the important razor syntaxes. Visit asp.net to learn razor syntax in
detail.
Points to Remember :
HTML Helpers
In this section, you will learn what are Html helpers and how to use them in the razor view.
HtmlHelper class generates html elements using the model class object in razor view. It
binds the model object to html elements to display value of model properties into html
elements and also assigns the value of the html elements to the model properties while
submitting web form. So always use HtmlHelper class in razor view instead of writing html
tags manually.
The following figure shows the use of HtmlHelper class in the razor view.
HTML Helpers
As you can see in the above figure, @Html is an object of HtmlHelper class . (@ symbol is
used to access server side object in razor syntax). Html is a property of type HtmlHelper
included in base class of razor view WebViewPage. ActionLink() and DisplayNameFor() is
extension methods included in HtmlHelper class.
There are many extension methods for HtmlHelper class, which creates different html
controls.
The following table lists HtmlHelper methods and html control each method generates.
Strogly Typed
HtmlHelper Html Control
HtmlHelpers
The difference between calling the HtmlHelper methods and using an html tags is that the
HtmlHelper method is designed to make it easy to bind to view data or model data.
HtmlHelper - TextBox
Learn how to generate textbox control using HtmlHelper in razor view in this section.
HtmlHelper class includes two extension methods which creates a textbox (<input
type="text">) element in razor view: TextBox() and TextBoxFor(). The TextBox() method
is loosely typed method whereas TextBoxFor() is a strongly typed method.
We will use following Student model with TextBox() and TextBoxFor() method.
Example: Student Model
public class Student
{
public int StudentId { get; set; }
[Display(Name="Name")]
public string StudentName { get; set; }
public int Age { get; set; }
public bool isNewlyEnrolled { get; set; }
public string Password { get; set; }
}
TextBox()
The Html.TextBox() method creates <input type="text" > element with specified name,
value and html attributes.
TextBox method has many overloads. Please visit MSDN to know all the overloads of
TextBox() method.
The TextBox() method is a loosely typed method because name parameter is a string. The
name parameter can be a property name of model object. It binds specified property with
textbox. So it automatically displays a value of the model property in a textbox and visa-
versa.
In the above example, the first parameter is "StudentName" property of Student model class
which will be set as a name & id of textbox. The second parameter is a value to display in a
textbox, which is null in the above example because TextBox() method will automatically
display a value of the StudentName property in the textbox. The third parameter will be set
as class attribute. HtmlAttributes parameter is an object type, so it can be anonymous object
and attributes name will be its properties starting with @ symbol.
You can also specify any name for the textbox. However, it will not be bind to a model.
Example: Html.TextBox() in Razor View
@Html.TextBox("myTextBox", "This is value", new { @class = "form-control"
})
Html Result:
<input class="form-control"
id="myTextBox"
name="myTextBox"
type="text"
value="This is value" />
TextBoxFor
TextBoxFor helper method is a strongly typed extension method. It generates a text input
element for the model property specified using a lambda expression. TextBoxFor method
binds a specified model object property to input text. So it automatically displays a value of
the model property in a textbox and visa-versa.
In the above example, the first parameter in TextBoxFor() method is a lambda expression
which specifies StudentName property to bind with the textbox. It generates an input text
element with id & name set to property name. The value attribute will be set to the value of
a StudentName property e.g John. The following figure shows the input text element
genered by above example.
HtmlHelper - TextArea
Learn how to generate TextArea control using HtmlHelper in razor view in this section.
HtmlHelper class includes two extension methods to generate a multi line <textarea>
element in a razor view: TextArea() and TextAreaFor(). By default, it creates textarea with
rows=2 and cols=20.
We will use the following Student model with the TextArea() and TextAreaFor() method.
The Html.TextArea() method creates <textarea rows="2" cols="20" > element with
specified name, value and html attributes.
TextArea method has many overloads. Please visit MSDN to know all the overloads of
TextArea method.
The TextArea() method is a loosely typed method because the name parameter is a string.
The name parameter can be a property name of model object. It binds a specified property
with the textarea. So it automatically displays a value of the model property in a textarea
and visa-versa.
In the above example, the first parameter is the "Description" property of Student model
class which will be set as a name & id of textarea. The second parameter is a value to
display in a textarea, which is null in the above example because TextArea() method will
automatically display a value of the Description property in the textarea. The third
parameter will be set as class attribute. HtmlAttributes parameter is an object type, so it can
be anonymous object and attributes name will be its properties starting with @ symbol.
You can also specify any name for the textarea. However, it will not be bound to a model.
TextAreaFor
TextAreaFor helper method is a strongly typed extension method. It generates a multi line
<textarea> element for the property in the model object specified using a lambda
expression. TextAreaFor method binds a specified model object property to textarea
element. So it automatically displays a value of the model property in a textarea and visa-
versa.
In the above example, the first parameter in TextAreaFor() method is a lambda expression
that specifies the model property to be bound with the textarea element. We have specified
Description property in the above example. So, it generates <textarea> element with id &
name set to property name - Description. The value of textarea will be set to the value of a
Description property.
HtmlHelper - CheckBox
Learn how to generate checkbox control using HtmlHelper in razor view in this section.
We will use following Student model with CheckBox() and CheckBoxFor() method.
In the above example, first parameter is "isNewlyEnrolled" property of Student model class
which will be set as a name & id of textbox. The second parameter is a boolean value,
which checks or unchecks the checkbox.
CheckBoxFor
In the above example, the first parameter in CheckBoxFor() method is a lambda expression
that specifies the model property to be bound with the checkbox element. We have
specified isNewlyEnrolled property in the above example. So, it generates <input
type="checkbox"> element with id & name set to property name - isNewlyEnrolled. The
value attribute will be set to the value of a isNewlyEnrolled boolean property.
In the above Html result, notice that it has generated additional hidden field with the same
name and value=false. This is because when you submit a form with a checkbox, the value
is only posted if the checkbox is checked. So, if you leave the checkbox unchecked then
nothing will be sent to the server when in many situations you would want false to be sent
instead. As the hidden input has the same name as the checkbox, then if the checkbox is
unchecked you'll still get a 'false' sent to the server.
HtmlHelper - RadioButton
Learn how to generate radio button control using HtmlHelper in razor view in this section.
We will use the following Student model with the RadioButton() and RadioButtonFor()
method.
The Html.RadioButton() method creates an radio button element with a specified name,
isChecked boolean and html attributes.
RadioButton() method Signature
In the above example, we have created two radio button for the "Gender" property. The
second parameter is a value which will be sent to the server, if respective radio button is
checked. If the Male radio button is selected, then the string value "Male" will be assigned
to a model property Gender and submitted to the server. The above example creates two
radio buttons as shown below.
RadioButtonFor
<input id="Gender"
name="Gender"
type="radio"
value="Female" />
HtmlHelper - DropDownList
Learn how to generate dropdownlist control using HtmlHelper in razor view in this section.
HtmlHelper class includes two extension methods to generate a <select> element in a razor
view: DropDownList() and DropDownListFor().
We will use the following Student model with DropDownList() and DropDownListFor()
method.
The Html.DropDownList() method generates a select element with specified name, list
items and html attributes.
@model Student
@Html.DropDownList("StudentGender",
new SelectList(Enum.GetValues(typeof(Gender))),
"Select Gender",
new { @class = "form-control" })
Html Result:
<select class="form-control" id="StudentGender" name="StudentGender">
<option>Select Gender</option>
<option>Male</option>
<option>Female</option>
</select>
In the above example, the first parameter is a property name for which we want to display
list items. The second parameter is list of values to be included in the dropdownlist. We
have used Enum methods to get the Gender enum values. The third parameter is a label
which will be the first list item and the fourth parameter is for html attributes like css to be
applied on the dropdownlist.
Please note that you can add MyMVCApp.Models namespace into <namespaces> section in
web.config in the Views folder instead of using @using to include namespces in all the
views.
DropDownListFor
The following example creates dropdown list for the above Gender enum.
@model Student
HtmlHelper class includes two extension methods to generate a hidden field (<input
type="hidden">) element in a razor view: Hidden() and HiddenFor().
We will use the following Student model with Hidden() and HiddenFor() method.
Example: Student Model
public class Student
{
public int StudentId { get; set; }
[Display(Name="Name")]
public string StudentName { get; set; }
public int Age { get; set; }
public bool isNewlyEnrolled { get; set; }
public string Password { get; set; }
}
Hidden()
The Html.Hidden() method generates a input hidden field element with specified name,
value and html attributes.
Hidden() method has many overloads. Please visit MSDN to know all the overloads of
Hidden() method.
The following example creates a hidden field for StudentId property of Student model. It
binds StudentId with the hidden field, so that it can assign value of StudentId to the hidden
field and visa-versa.
@Html.Hidden("StudentId")
Html Result:
<input id="StudentId"
name="StudentId"
type="hidden"
value="1" />
HiddenFor
HiddenFor helper method is a strongly typed extension method. It generates a hidden input
element for the model property specified using a lambda expression. HiddenFor method
binds a specified model object property to <input type="hidden">. So it automatically sets
a value of the model property to hidden field and visa-versa.
In the above example, the first parameter in HiddenFor() method is a lambda expression
that specifies the model property to be bind with the hidden field. We have specified
StudentId property in the above example. So, it generates input text element with id &
name set to property name. The value attribute will be set to the value of a StudentId
property which is 1 in the above example.
Please notice that it has created data- attribute of html5 that is used for the validation in
ASP.Net MVC.
HtmlHelper - Password
Learn how to generate Password field using HtmlHelper in razor view in this section.
HtmlHelper class includes two extension methods to generate a password field (<input
type="password">) element in a razor view: Password() and PasswordFor().
We will use following Student model with Password() and PasswordFor() method.
The Html.Password() method generates a input password element with specified name,
value and html attributes.
Password() method has many overloads. Please visit MSDN to know all the overloads of
Password() method.
@Html.Password("OnlinePassword")
Html Result:
<input
id="OnlinePassword"
name="OnlinePassword"
type="password"
value="" />
The above example will create password field for "OnlinePassword" property as shown
below.
PasswordFor()
In the above example, the first parameter in PasswordFor() method is a lambda expression
that specifies the model property to be bind with the password textbox. We have specified
Password property in the above example. So, it generates input password element with id &
name set to property name. The value attribute will be set to the value of a Password
property which is "mypassword" in the above example.
HtmlHelper class includes two extension methods to generate html string : Display() and
DisplayFor().
We will use the following Student model with the Display() and DisplayFor() method.
The Html.Display() is a loosely typed method which generates a string in razor view for the
specified property of model.
Display() method has many overloads. Please visit MSDN to know all the overloads of
Display() method
DisplayFor helper method is a strongly typed extension method. It generates a html string
for the model object property specified using a lambda expression.
In the above example, we have specified StudentName property of Student model using
lambda expression in the DisplayFor() method. So, it generates a html string with the value
of StudentName property, which is "Steve" in the above example.
HtmlHelper - Label
Learn how to create <label> element using HtmlHelper in razor view in this section.
HtmlHelper class includes two extension methods to generate html label : Label() and
LabelFor().
We will use following Student model with to demo Label() and LabelFor() method.
The Html.Label() method generates a <label> element for a specified property of model
object.
Label() method Signature: MvcHtmlString Label(string expression, string
labelText, object htmlAttributes)
Label() method has many overloads. Please visit MSDN to know all the overloads of
Label() method
In the above example, we have specified a StudentName property as a string. So, it will
create <label> element that display Name.
You can specify another label text instead of property name as shown below.
LabelFor helper method is a strongly typed extension method. It generates a html label
element for the model object property specified using a lambda expression.
In the above example, we have specified the StudentName property of Student model using
lambda expression in the LabelFor() method. So, it generates <label> and set label text to
the same as StudentName property name.
HtmlHelper - Editor
We have seen different HtmlHelper methods used to generated different html elements in
the previous sections. ASP.NET MVC also includes a method that generates html input
elements based on the datatype. Editor() or EditorFor() extension method generates html
elements based on the data type of the model object's property.
The following table list the html element created for each data type by Editor() or
EditorFor() method.
We will use the following model class with Editor and EditorFor method.
Editor() method requires a string expression parameter to specify the property name. It
creats a html element based on the datatype of the specified property.
StudentId: @Html.Editor("StudentId")
Student Name: @Html.Editor("StudentName")
Age: @Html.Editor("Age")
Password: @Html.Editor("Password")
isNewlyEnrolled: @Html.Editor("isNewlyEnrolled")
Gender: @Html.Editor("Gender")
DoB: @Html.Editor("DoB")
In the above example, we have specified property names of Student model as a string. So,
Editor() method created the appropriate input elements based on the datatype as shown in
the above figure.
EditorFor
EditorFor() method is a strongly typed method. It requires the lambda expression to specify
a property of the model object.
In the above example of EditorFor() method, we have specified the property name using the
lambda expression. The result would be the same as the Editor() method as shown in the
above figure.
Model Binding
In this section, you will learn about model binding in MVC framework.
To understand the model binding in MVC, first let's see how you can get the http request
values in the action method using traditional ASP.NET style. The following figure shows
how you can get the values from HttpGET and HttpPOST request by using the Request
object directly in the action method.
Accessing
Request Data
As you can see in the above figure, we use the Request.QueryString and Request
(Request.Form) object to get the value from HttpGet and HttpPOST request. Accessing
request values using the Request object is a cumbersome and time wasting activity.
With model binding, MVC framework converts the http request values (from query string
or form collection) to action method parameters. These parameters can be of primitive type
or complex type.
HttpGET request embeds data into a query string. MVC framework automatically converts
a query string to the action method parameters. For example, the query string "id" in the
following GET request would automatically be mapped to the id parameter of the Edit()
action method.
Model
Binding
You can also have multiple parameters in the action method with different data types.
Query string values will be converted into paramters based on matching name.
return View();
}
Binding to Complex type
Model binding also works on complex types. Model binding in MVC framework
automatically converts form field data of HttpPOST request to the properties of a complex
type parameter of an action method.
Now, you can create an action method which includes Student type parameter. In the
following example, Edit action method (HttpPost) includes Student type parameter.
return RedirectToAction("Index");
}
So now, MVC framework will automatically maps Form collection values to Student type
parameter when the form submits http POST request to Edit action method as shown
below.
Model Binding
So thus, it automatically binds form fields to the complex type parameter of action method.
FormCollection
You can also include FormCollection type parameter in the action method instead of
complex type, to retrieve all the values from view form fields as shown below.
Model Binding
Bind Attribute
ASP.NET MVC framework also enables you to specify which properties of a model class
you want to bind. The [Bind] attribute will let you specify the exact properties a model
binder should include or exclude in binding.
In the following example, Edit action method will only bind StudentId and StudentName
property of a Student model.
return RedirectToAction("Index");
}
return RedirectToAction("Index");
}
The Bind attribute will improve the performance by only bind properties which you needed.
Inside Model Binding
As you have seen that Model binding automatically converts request values into a primitive
or complex type object. Model binding is a two step process. First, it collects values from
the incoming http request and second, populates primitive type or complex type with these
values.
Value providers are responsible for collecting values from request and Model Binders are
responsible for populating values.
Model
Binding in MVC
Default value provider collection evaluates values from the following sources:
MVC includes DefaultModelBinder class which effectively binds most of the model types.
The Edit view will be rendered on the click of the Edit button in Index view. The following
figure describes the complete set of editing steps.
Editing Steps in MVC
1. The user clicks on the Edit link in Index view which will send HttpGET request
http://localhost/student/edit/{Id} with corresponding Id parameter in the query string. This
request will be handled by HttpGET Edit action method.(by default action method handles
HttpGET request if no attribute specified)
2. HttpGet Edit action method will fetch student data from the database, based on the
supplied Id parameter and render the Edit view with that particular Student data.
3. The user can edit the data and click on the Save button in the Edit view. The Save button
will send a HttpPOST request http://localhost/Student/Edit with the Form data collection.
4. The HttpPOST Edit action method in StudentController will finally update the data into
the database and render an Index page with the refreshed data using the RedirectToAction
method as a fourth step.
So this will be the complete process in order to edit the data using Edit view in ASP.NET
MVC.
[Display( Name="Name")]
public string StudentName { get; set; }
Step: 1
We have already created an Index view in the previous section using a List scaffolding
template which includes an Edit action link as shown below.
Index View
An Edit link sends HttpGet request to the Edit action method of StudentController with
corresponding StudentId in the query string. For example, an Edit link with student John
will append a StudentId=1 query string to the request url because John's StudentId is 1.
Likewise all the Edit link will include a respective StudentId in the query string.
Step 2:
Now, create a HttpGET Edit action method in StudentController. The Index view shown
above will send the StudentId parameter to the HttpGet Edit action method on the click of
the Edit link.
The HttpGet Edit() action method must perform two tasks, first it should fetch the student
information from the underlaying data source, whose StudentId matches with the StudentId
in the query string. Second, it should render Edit view with the student information so that
the user can update it.
So, the Edit() action method should have a StudentId parameter. MVC framework will
automatically bind a query string to the parameters of an action method if the name is
matches. Please make sure that parameter name matches with the query string.
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
IList<Student> studentList = new List<Student>() {
new Student(){ StudentId=1, StudentName="John", Age =
18 },
new Student(){ StudentId=2, StudentName="Steve", Age
= 21 },
new Student(){ StudentId=3, StudentName="Bill", Age =
25 },
new Student(){ StudentId=4, StudentName="Ram", Age =
20 },
new Student(){ StudentId=5, StudentName="Ron", Age =
31 },
new Student(){ StudentId=6, StudentName="Chris", Age
= 17 },
new Student(){ StudentId=7, StudentName="Rob", Age =
19 }
};
return View(std);
}
}
}
As you can see in the above Edit method, we have used a LINQ query to get the Student
from the sample studentList collection whose StudentId matches with supplied StudentId,
and then we inject that Student object into View. In a real life application, you can get the
student from the database instead of sample collection.
Now, if you click on the Edit link from Index view then you will get following error.
The above error occurred because we have not created an Edit view yet. By default, MVC
framework will look for Edit.cshtml or Edit.vbhtml or Edit.aspx or Edit.ascx file in View -
> Student or Shared folder.
Step 3:
To create Edit view, right click inside Edit action method and click on Add View.. It will
open Add View dialogue.
In the Add View dialogue, keep the view name as Edit. (You can change as per your
requirement.)
Edit View
Select Edit in the Template dropdown and also select Student for Model class as shown
below.
Edit View
Now, click Add to generate Edit.cshtml view under View/Student folder as shown below.
Edit.cshtml:
@model MVC_BasicTutorials.Models.Student
@{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Student</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.StudentId)
<div class="form-group">
@Html.LabelFor(model => model.StudentName, htmlAttributes:
new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.StudentName, new
{ htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.StudentName,
"", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Age, htmlAttributes: new
{ @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Age, new { htmlAttributes
= new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Age, "", new
{ @class = "text-danger"< })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default"
/>
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
Please notice that Edit.cshtml includes HtmlHelper method @using (Html.BeginForm())
to create a html form element. Html.BeginForm sends a HttpPost request by default.
Now, click on the Edit link of any student in the Index view. Edit view will be display
student information whose Edit link clicked, as shown below.
Edit View
You can edit the Name or Age of Student and click on Save. Save method should send a
HttpPOST request because the POST request sends form data as a part of the request, not in
the querystring. So write a POST method as fourth step.
Step 4:
Now, write POST Edit action method to save the edited student as shown below.
return RedirectToAction("Index");
}
As you can see in the above code, the Edit() method requires a Student object as an input
parameter. The Edit() view will automatically binds form's data collection to the student
model parameter. Please visit Model Binding section for more information. Here, you can
update the information to the database and redirect it to Index action. (we have not written
code to update database here for demo purpose)
Now, clicking on the Save button in the Edit view will save the updated information and
redirect it to the Index() action method.
In this way, you can provide edit functionality using a default scaffolding Edit template.
However, you can also create an Edit view without using an Edit scaffolding template.
The following example demonstrates the StudentController class with all the action
methods.
Example: Controller in C#
using MVC_BasicTutorials.Models;
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
IList<Student> studentList = new List<Student>() {
new Student(){ StudentId=1, StudentName="John", Age =
18 },
new Student(){ StudentId=2, StudentName="Steve", Age
= 21 },
new Student(){ StudentId=3, StudentName="Bill", Age =
25 },
new Student(){ StudentId=4, StudentName="Ram", Age =
20 },
new Student(){ StudentId=5, StudentName="Ron", Age =
31 },
new Student(){ StudentId=6, StudentName="Chris", Age
= 17 },
new Student(){ StudentId=7, StudentName="Rob", Age =
19 }
};
// GET: Student
public ActionResult Index()
{
return View(studentList);
}
return View(std);
}
[HttpPost]
public ActionResult Edit(Student std)
{
//write code to update student
return RedirectToAction("Index");
}
}
}
Learn how to implement validations in the razor view in the next section.
We have created an Edit view for Student in the previous section. Now, we will implement
data validation in the Edit view, which will display validation messages on the click of
Save button, as shown below if Student Name or Age is blank.
Validation
DataAnnotations
Attribute Description
RegularExpression Specifies that the field value must match with specified Regular Expression
Specifies that the field is a phone number using regular expression for phone
Phone
numbers
Step 1: First of all, apply DataAnnotation attribute on the properties of Student model
class. We want to validate that StudentName and Age is not blank. Also, Age should be
between 5 and 50. Visit Model section if you don't know how to create a model class.
[Required]
public string StudentName { get; set; }
[Range(5,50)]
public int Age { get; set; }
}
You can also apply multiple DataAnnotations validation attributes to a single property
if required.
In the above example, we have applied a Required attribute to the StudentName property.
So now, the MVC framework will automatically display the default error message, if the
user tries to save the Edit form without entering the Student Name. In the same way, the
Range attribute is applied with a min and max value to the Age property. This will validate
and display an error message if the user has either not entered Age or entered an age less
than 5 or more than 50.
Step 2: Create the GET and POST Edit Action method in the same as previous section. The
GET action method will render Edit view to edit the selected student and the POST Edit
method will save edited student as shown below.
namespace MVC_BasicTutorials.Controllers
{
public class StudentController : Controller
{
public ActionResult Edit(int id)
{
var std = studentList.Where(s => s.StudentId == StudentId)
.FirstOrDefault();
return View(std);
}
[HttpPost]
public ActionResult Edit(Student std)
{
if (ModelState.IsValid) {
return RedirectToAction("Index");
}
return View(std);
}
}
}
As you can see in the POST Edit method, we first check if the ModelState is valid or not. If
ModelState is valid then update the student into database, if not then return Edit view again
with the same student data.
To create an Edit view, right click inside Edit action method -> click Add View..
Create Edit View
In the Add View dialogue, keep the view name as Edit. (You can change as per your
requirement.)
Select the Edit template in the Template dropdown and also select Student Model class as
shown below.
Edit.cshtml:
@model MVC_BasicTutorials.Models.Student
@{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Student</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
@Html.HiddenFor(model => model.StudentId)
<div class="form-group">
@Html.LabelFor(model => model.StudentName, htmlAttributes:
new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.StudentName, new
{ htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.StudentName,
"", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Age, htmlAttributes: new
{ @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Age, new { htmlAttributes
= new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Age, "", new
{ @class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default"
/>
</div>
</div>
</div>
}
<div>
@Html.ActionLink("Back to List", "Index")
</div>
As you can see in the above Edit.cshtml, it calls Html Helper method
ValidationMessageFor for every field and ValidationSummary method at the top.
ValidationMessageFor is responsible to display error message for the specified field.
ValidationSummary displays a list of all the error messages at once.
So now, it will display default validation message when you submit an Edit form without
entering a Name or Age.
Validation
Thus, you can implement validations by applying various DataAnnotation attributes to the
model class and using ValidationMessage() or ValidationMessageFor() method in the view.
Points to Remember :
1. ASP.NET MVC uses DataAnnotations attributes for validation.
2. DataAnnotations attributes can be applied to the properties of the model class to indicate
the kind of value the property will hold.
3. The following validation attributes available by default
1. Required
2. StringLength
3. Range
4. RegularExpression
5. CreditCard
6. CustomValidation
7. EmailAddress
8. FileExtension
9. MaxLength
10. MinLength
11. Phone
4. Use ValidationSummary to display all the error messages in the view.
5. Use ValidationMessageFor or ValidationMessage helper method to display field level
error messages in the view.
6. Check whether the model is valid before updating in the action method using
ModelState.IsValid.
7. Enable client side validation to display error messages without postback effect in the
browser.
ValidationMessage() Signature
Example: ValidationMessage
@model Student
In the above example, the first parameter in the ValidationMessage method is a property
name for which we want to show the error message e.g. StudentName. The second
parameter is for custom error message and the third parameter is for html attributes like css,
style etc.
The ValidationMessage() method will only display an error, if you have configured the
DataAnnotations attribute to the specifed property in the model class. The following is a
Student model class where the DataAnnotations attribute "Required" is applied to the
StudentName property.
Html Result:
<input id="StudentName"
name="StudentName"
type="text"
value="" />
Now, when the user submits a form without entering a StudentName, then ASP.NET MVC
uses a data- attribute of Html5 for the validation and a default validation message will be
injected, when the validation error occurs, as shown below.
You can display your own error message instead of the default error message as shown
above. You can provide a custom error message either in the DataAnnotations attribute or
ValidationMessage() method.
Use the parameter of the DataAnnotation attributes to provide your own custom error
message as shown below.
Also, you can specify a message as a second parameter in the ValidationMessage() method
as shown below.
ValidationMessageFor() Signature
Example: ValidationMessageFor
@model Student
The ValidationMessageFor() method will only display an error if you have configured
DataAnnotations attribute to the specifed property in the model class. The following
example is a Student model class where the DataAnnotations attribute "Required" is
applied to the StudentName property.
Html Result:
<input id="StudentName"
name="StudentName"
type="text"
value="" />
Now, when the user submits a form without entering the StudentName then ASP.NET
MVC uses the data- attribute of Html5 for the validation and the default validation message
will be injected when validation error occurs, as shown below.
Output of
ValidationMessageFor() method
You can display your own error message instead of the default error message as above. You
can provide a custom error message either in the DataAnnotations attribute or the
ValidationMessageFor() method.
Use the ErrorMessage parameter of the DataAnnotation attributes to provide your own
custom error message as shown below.
Also, you can specify a message as a second parameter in the ValidationMessage() method
as shown below.
The ValidationSummary can be used to display all the error messages for all the fields. It
can also be used to display custom error messages. The following figure shows how
ValidationSummary displays the error messages.
Va
lidationSummary
ValidationSummary() Signature
By default, ValidationSummary filters out field level error messages. If you want to display
field level error messages as a summary then specify excludePropertyErrors = false.
Err
or Message using ValidationSummary
You can also display a custom error message using ValidationSummary. For example, we
want to display a message if Student Name already exists in the database.
To display a custom error message, first of all, you need to add custom errors into the
ModelState in the appropriate action method.
if(nameAlreadyExists)
{
ModelState.AddModelError(string.Empty, "Student Name already
exists.");
return View(std);
}
}
As you can see in the above code, we have added custom error messages using the
ModelState.AddModelError method. The ValidationSummary method will automatically
display all the error messages added into ModelState.
Dis
play error message using ValidationSymmary
Thus, you can use the ValidationSummary helper method to display error messages.
Layout View
In this section, you will learn about the layout view in ASP.NET MVC.
An application may contain common parts in the UI which remains the same throughout the
application such as the logo, header, left navigation bar, right bar or footer section.
ASP.NET MVC introduced a Layout view which contains these common UI parts, so that
we don't have to write the same code in every page. The layout view is same as the master
page of the ASP.NET webform application.
For example, an application UI may contain Header, Left menu bar, right bar and footer
section that remains same in every page and only the centre section changes dynamically as
shown below.
Sample Application UI
Parts
The layout view allows you to define a common site template, which can be inherited in
multiple views to provide a consistent look and feel in multiple pages of an application. The
layout view eliminates duplicate coding and enhances development speed and easy
maintenance. The layout view for the above sample UI would contain a Header, Left Menu,
Right bar and Footer sections. It contains a placeholder for the center section that changes
dynamically as shown below.
Layout View
The razor layout view has same extension as other views, .cshtml or .vbhtml. Layout views
are shared with multiple views, so it must be stored in the Shared folder. For example,
when we created our first MVC application in the previous section, it also created
_Layout.cshtml in the Shared folder as shown below.
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
As you can see, the layout view contains html Doctype, head and body as normal html, the
only difference is call to RenderBody() and RenderSection() methods. RenderBody acts
like a placeholder for other views. For example, Index.cshtml in the home folder will be
injected and rendered in the layout view, where the RenderBody() method is being called.
You will learn about these rendering methods later in this section.
Use Layout View
You must be wondering that how would the View know which layout view to use?
You can set the layout view in multiple ways, by using _ViewStart.cshtml or setting up
path of the layout page using Layout property in the individual view or specifying layout
view name in the action method.
_ViewStart.cshtml
_ViewStart.cshtml is included in the Views folder by default. It sets up the default layout
page for all the views in the folder and its subfolders using the Layout property. You can
assign a valid path of any Layout page to the Layout property.
For example, the following _ViewStart.cshtml in the Views folder, sets the Layout property
to "~/Views/Shared/_Layout.cshtml". So now, _layout.cshtml would be layout view of all
the views included in Views and its subfolders. So by default, all the views derived default
layout page from _ViewStart.cshtml of Views folder.
_ViewStart.cshtml
_ViewStart.cshtml can also be included in sub folder of View folder to set the default
layout page for all the views included in that particular subfolder only.
For example, the following _ViewStart.cshtml in Home folder, sets Layout property to
_myLayoutPage.cshtml. So this _ViewStart.cshtml will influence all the views included in
the Home folder only. So now, Index, About and Contact views will be rendered in
_myLayoutPage.cshtml instead of default _Layout.cshml.
Layout View
You can also override default layout page set by _ViewStart.cshtml by setting Layout
property in each individual .cshtml view. For example, the following Index view use
_myLayoutPage.cshtml even if _ViewStart.cshtml set _Layout.cshtml.
Index View:
@{
ViewBag.Title = "Home Page";
Layout = "~/Views/Shared/_myLayoutPage.cshtml";
}
<div class="jumbotron">
<h1>ASP.NET</h1>
<p class="lead">ASP.NET is a free web framework for building great
Web sites and Web applications using HTML, CSS and JavaScript.</p>
<p><a href="http://asp.net" class="btn btn-primary btn-lg">Learn more
»</a></p>
</div>
<div class="row">
<div class="col-md-4">
<h2>Getting started</h2>
<p>
ASP.NET MVC gives you a powerful, patterns-based way to build
dynamic websites that
enables a clean separation of concerns and gives you full
control over markup
for enjoyable, agile development.
</p>
<p><a class="btn btn-default"
href="http://go.microsoft.com/fwlink/?LinkId=301865">Learn more
»</a></p>
</div>
<div class="col-md-4">
<h2>Get more libraries</h2>
<p>NuGet is a free Visual Studio extension that makes it easy to
add, remove, and update libraries and tools in Visual Studio
projects.</p>
<p><a class="btn btn-default"
href="http://go.microsoft.com/fwlink/?LinkId=301866">Learn more
»</a></p>
</div>
<div class="col-md-4">
<h2>Web Hosting</h2>
<p>You can easily find a web hosting company that offers the
right mix of features and price for your applications.</p>
<p><a class="btn btn-default"
href="http://go.microsoft.com/fwlink/?LinkId=301867">Learn more
»</a></p>
</div>
</div>
You can also specify which layout page to use in while rendering view from action method
using View() method.
The following example, View() method renders Index view using _myLayoutPage.cshtml.
ASP.NET MVC layout view renders child views using the following methods.
Method Description
Renders the portion of the child view that is not within a named section.
RenderBody()
Layout view must include RenderBody() method.
RenderSection(string Renders a content of named section and specifies whether the section is
name) required. RenderSection() is optional in Layout view.
The following figure illustrates the use of RenderBody and RenderSection methods.
Rendering Methods
As you can see in the above figure, _Layout.cshtml includes RenderBody() method and
RenderSection() method. RenderSection methods specify name of a section such as
LeftSection, MiddleSection and RightSection in the above figure. Index.cshtml defines
named section using @section where name of each section matches with the name specified
in RenderSection method of _Layout.cshtml, such as @Section RightSection etc. At run
time, the named sections of Index.cshtml such as LeftSection, RightSection and
MiddleSection will be rendered at appropriate place where RenderSection method is called.
Rest of the part of Index view, which is not in any of the named section will render where
RenderBody() method is being called.
Let's create a new layout view to understand the above render methods in the next section.
Points to Remember :
1. The Layout view contains common parts of a UI. It is same like masterpage of ASP.NET
webforms.
2. _ViewStart.cshtml file can be used to specify path of layout page, which in turn will be
applicable to all the views of the folder and its subfolder.
3. You can set the Layout property in the individual view also, to override default layout page
setting of _ViewStart.cshtml
4. Layout view uses two rendering methods: RenderBody() and RenderSection().
5. RenderBody can be used only once in the layout view, whereas the RenderSection method
can be called multiple time with different name.
6. RenderBody method renders all the content of view which is not wrapped in named
section.
7. RenderSection method renders the content of a view which is wrapped in named section.
8. RenderSection can be configured as required or optional. If required, then all the child
views must included that named section.
In the Add New Item dialogue box, select MVC 5 Layout Page (Razor) and give the layout
page name as "_myLayoutPage.cshtml" and click Add.
Rendering Methods
_myLayoutPage.cshtml:
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>@ViewBag.Title</title>
</head>
<body>
<div>
@RenderBody()
</div>
</body>
</html>
Now, add the <footer> tag with the RenderSection("footer",true) method alongwith
some styling as shown below. Please notice that we made this section as required. This
means any view that uses _myLayoutPage as its layout view must include a footer section.
Now, let's use this _myLayoutPage.cshtml with the Index view of HomeController.
You can add an empty Index view by right clicking on Index action method of
HomeController and select Add View. Select Empty as a scaffolding template and
_myLayoutPage.cshtml as layout view and click Add.
Index view:
@{
ViewBag.Title = "Home Page";
Layout = "~/Views/Shared/_myLayoutPage.cshtml";
}
<h2>Index</h2>
So now, we have created Index view that uses our _myLayoutPage.cshtml as a layout view.
We will now add footer section along with some styling because _myLayoutPage requires
footer section.
Index view:
@{
ViewBag.Title = "Home Page";
Layout = "~/Views/Shared/_myLayoutPage.cshtml";
}
<div class="jumbotron">
<h2>Index</h2>
</div>
<div class="row">
<div class="col-md-4">
<p>This is body.</p>
</div>
@section footer{
<p class="lead">
This is footer section.
</p>
}
</div>
Now, run the application and you will see Index view will contain body and footer part as
shown below.
Index View
Thus, you can create new layout view with different rendering methods.
Partial View
In this section you will learn about partial views in ASP.NET MVC.
Partial view is a reusable view, which can be used as a child view in multiple other views.
It eliminates duplicate coding by reusing same partial view in multiple places. You can use
the partial view in the layout view, as well as other content views.
To start with, let's create a simple partial view for the following navigation bar for demo
purposes. We will create a partial view for it, so that we can use the same navigation bar in
multiple layout views without rewriting the same code everywhere.
Partial View
The following figure shows the html code for the above navigation bar. We will cut and
paste this code in a seperate partial view for demo purposes.
Partial Views
To create a partial view, right click on Shared folder -> select Add -> click on View..
Note:
If a partial view will be shared with multiple views of different controller folder then create it in
the Shared folder, otherwise you can create the partial view in the same folder where it is going to
be used.
In the Add View dialogue, enter View name and select "Create as a partial view" checkbox
and click Add.
Partial Views
We are not going to use any model for this partial view, so keep the Template dropdown as
Empty (without model) and click Add. This will create an empty partial view in Shared
folder.
Now, you can cut the above code for navigation bar and paste it in _HeaderNavBar.cshtml
as shown below:
Thus, you can create a new partial view. Let's see how to render partial view.
Render Partial View
You can render the partial view in the parent view using html helper methods: Partial() or
RenderPartial() or RenderAction(). Each method serves different purposes. Let's have an
overview of each method and then see how to render partial view using these methods.
Html.Partial()
@Html.Partial() helper method renders the specified partial view. It accept partial view
name as a string parameter and returns MvcHtmlString. It returns html string so you have a
chance of modifing the html before rendering.
Html.RenderPartial()
The RenderPartial helper method is same as the Partial method except that it returns void
and writes resulted html of a specified partial view into a http response stream directly.
RenderPartial(String
Renders the specified partial view
partialViewName)
RenderPartial(String Renders the specified partial view and set the specified
partialViewName, Object model) model object
Html.RenderAction()
The RenderAction helper method invokes a specified controller and action and renders the
result as a partial view. The specified Action method should return PartialViewResult using
the Partial() method.
Name Description
RenderAction(String actionName, String Invokes the specified child action method using the
controllerName, RouteValueDictionary specified parameters and controller name and
routeValues) renders the result inline in the parent view.
So now, we can use any of the above rending methods to render the _HeaderNavBar partial
view into _Layout.cshtml. The following layout view renders partial view using the
RenderPartial() method.
Example: Html.RenderPartial()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@{
Html.RenderPartial("_HeaderNavBar");
}
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
Note:
RenderPartial returns void, so a semicolon is required at the end and so it must be enclosed in the
braces.
The following layout view uses the Partial method to render partial
view_HeaderNavBar.cshtml.
Example: Html.Partial()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,
initial-scale=1.0">
<title>@ViewBag.Title - My ASP.NET Application</title>
@Styles.Render("~/Content/css")
@Scripts.Render("~/bundles/modernizr")
</head>
<body>
@Html.Partial("_HeaderNavBar")
<div class="container body-content">
@RenderBody()
<hr />
<footer>
<p>© @DateTime.Now.Year - My ASP.NET Application</p>
</footer>
</div>
@Scripts.Render("~/bundles/jquery")
@Scripts.Render("~/bundles/bootstrap")
@RenderSection("scripts", required: false)
</body>
</html>
Note:
@Html.Partial() method doesn't need to be in code block because it returns a html string.
You will see following UI in browser when you run the application.
Index.cshtml
So in this way, you can use partial view without any differences in the UI.
Points to Remember :
1. Partial view is a reusable view, which can be used as a child view in multiple other views.
2. Partial view can be rendered using Html.Partial(), Html.RenderPartial() or
Html.RenderAction() method.
ASP.NET MVC - ViewBag
We have learned in the previous section that the model object is used to send data in a razor
view. However, there may be some scenario where you want to send a small amount of
temporary data to the view. So for this reason, MVC framework includes ViewBag.
ViewBag can be useful when you want to transfer temporary data (which is not included in
model) from the controller to the view. The viewBag is a dynamic type property of
ControllerBase class which is the base class of all the controllers.
ViewBag
In the above figure, it attaches Name property to ViewBag with the dot notation and assigns
a string value "Bill" to it in the controller. This can be accessed in the view like
@ViewBag.Name. (@ is razor syntax to access the server side variable.)
You can assign any number of properties and values to ViewBag. If you assign the same
property name multiple times to ViewBag, then it will only consider last value assigned to
the property.
Note:
ViewBag only transfers data from controller to view, not visa-versa. ViewBag values will
be null if redirection occurs.
The following example demonstrates how to transfer data from controller to view using
ViewBag.
return View();
}
}
}
In the above example, we want to display the total number of students in a view for the
demo. So, we have attached the TotalStudents property to the ViewBag and assigned the
student count using studentList.Count().
Now, in the Index.cshtml view, you can access ViewBag.TotalStudents property and
display all the student info as shown below.
Points to Remember :
1. ViewBag transfers data from the controller to the view, ideally temporary data
which in not included in a model.
2. ViewBag is a dynamic property that takes advantage of the new dynamic features in
C# 4.0
3. You can assign any number of propertes and values to ViewBag
4. The ViewBag's life only lasts during the current http request. ViewBag values will
be null if redirection occurs.
5. ViewBag is actually a wrapper around ViewData.
ASP.NET MVC - ViewData
ViewData is similar to ViewBag. It is useful in transferring data from Controller to View.
ViewData is a dictionary which can contain key-value pairs where each key must be string.
ViewData
Note:
ViewData only transfers data from controller to view, not vice-versa. It is valid only during
the current request.
The following example demonstrates how to transfer data from controller to view using
ViewData.
ViewData["students"] = studentList;
return View();
}
In the above example, we have added a student list with the key "students" in the ViewData
dictionary. So now, the student list can be accessed in a view as shown below.
return View();
}
ViewData and ViewBag both use the same dictionary internally. So you cannot have
ViewData Key matches with the property name of ViewBag, otherwise it will throw a
runtime exception.
return View();
}
Points to Remember :
You can add a key-value pair in TempData as shown in the below example.
Example: TempData
public class HomeController : Controller
{
// GET: Student
public HomeController()
{
}
public ActionResult Index()
{
TempData["name"] = "Test data";
TempData["age"] = 30;
return View();
}
if(TempData.ContainsKey("name"))
userName = TempData["name"].ToString();
if(TempData.ContainsKey("age"))
userAge = int.Parse(TempData["age"].ToString());
return View();
}
}
In the above example, we have added data into TempData and accessed the same data using
a key inside another action method. Please notice that we have converted values into the
appropriate type.
TempData internally uses session to store the data. So the data must be serialized
if you decide you to switch away from the default Session-State Mode, and use State Server
Mode or SQL Server Mode.
As you can see in the above example, we add test data in TempData in the first request and
in the second subsequent request we access test data from TempData which we stored in
the first request. However, you can't get the same data in the third request because
TempData will be cleared out after second request.
Example: TempData.Keep()
public class HomeController : Controller
{
public HomeController()
{
if(TempData["myData"] != null)
data = TempData["myData"] as string;
TempData.Keep();
return View();
}
if(TempData["myData"] != null)
data = TempData["myData"] as string;
return View();
}
}
Points to Remember :
1. TempData can be used to store data between two consecutive requests. TempData
values will be retained during redirection.
2. TemData is a TempDataDictionary type.
3. TempData internaly use Session to store the data. So think of it as a short lived
session.
4. TempData value must be type cast before use. Check for null values to avoid
runtime error.
5. TempData can be used to store only one time messages like error messages,
validation messages.
6. Call TempData.Keep() to keep all the values of TempData in a third request.
ASP.NET MVC Filter is a custom class where you can write custom logic to execute before
or after an action method executes. Filters can be applied to an action method or controller
in a declarative or programmatic way. Declarative means by applying a filter attribute to an
action method or controller class and programmatic means by implementing a
corresponding interface.
MVC provides different types of filters. The following table list filter types, built-in filters
for the type and interface which must be implemented to create a custom filter class.
Filter Type Description Built-in Filter Interface
To understand the filter in detail, let's take an example of built-in Exception filter.
Error.cshtml
return View();
}
Every attribute class must end with Attribute e.g. HanderErrorAttribute. Attribute must
be applied without Attribute suffix inside square brackets [ ] like [HandelError].
Filters applied to the controller will automatically be applicable to all the action methods of
a controller.
Now, if you run the application. You would get following error page because we throw
exception in Index action method for the demo purpose.
HandleError Demo
Thus, HandleError attribute will display common error page for any unhandled exception
occurred in HomeController.
Register Filters
1. Global Level
You can apply filters at global level in the Application_Start event of Global.asax.cs file by
using default FilterConfig.RegisterGlobalFilters() mehtod. Global filters will be applied to
all the controller and action methods of an application.
The [HandleError] filter is applied globaly in MVC Application by default in every MVC
application created using Visual Studio as shown below.
2. Controller level
Filters can also be applied to the controller class. So, filters will be applicable to all the
action method of Controller class if it is applied to a controller class.
[HandleError]
public class HomeController : Controller
{
public ActionResult Index()
{
return View();
}
You can apply filters to an individual action method also. So, filter will be applicable to
that particular action method only.
The same way, you can apply multiple built-in or custom filters globally or at controller or
action method level for different purpose such as [Authorize],[RequireHttps],
[ChildActionOnly],[OutputCache],[HandleError].
Filter Order
As mentioned above, MVC includes different types of filters and multiple filters can be
applied to a single controller class or action method. So, filters run in the following order.
1. Authorization filters
2. Action filters
3. Response filters
4. Exception filters
You can create custom filter attributes by implementing an appropriate filter interface for
which you want to create a custom filter and also derive a FilterAttribute class so that you
can use that class as an attribute.
base.OnException(filterContext);
}
}
}
Alternatively, you can also derive a built-in filter class and override an appropriate method
to extend the functionality of built-in filters.
Let's create custom exception filter to log every unhandled exception by deriving built-in
HandleErrorAttribute class and overriding OnException method as shown below.
base.OnException(filterContext);
}
}
}
Now, you can apply MyErrorHandler attribute at global level or controller or action method
level, the same way we applied the HandleError attribute.
}
Points to Remember :
1. MVC Filters are used to execute custom logic before or after executing action method.
2. MVC Filter types:
1. Authorization filters
2. Action filters
3. Result filters
4. Exception filters
3. Filters can be applied globally in FilterConfig class, at controller level or action method
level.
4. Custom filter class can be created by implementing FilterAttribute class and corresponding
interface.
Action filter executes before and after an action method executes. Action filter attributes
can be applied to an individual action method or to a controller. When action filter applied
to controller then it will be applied to all the action methods in that controller.
OutputCache is a built-in action filter attribute that can be apply to an action method for
which we want to cache the output. For example, output of the following action method
will be cached for 100 seconds.
Example: ActionFilter
[OutputCache(Duration=100)]
public ActionResult Index()
{
return View();
}
You can create custom action filter for your application. Let's see how to create custom
action filters.
You can create custom action filter by two ways. First, by implementing IActionFilter
interface and FilterAttribute class. Second, by deriving ActionFilterAttribute abstract class.
As you can see that ActionFilterAttribute class has four methods to overload. It includes
OnResultExecuted and OnResultExecuting methods, which can be used to execute custom
logic before or after result executes. Action filters are generally used to apply cross-cutting
concerns such as logging, caching, authorization etc.
controllerName,
actionName);
Debug.WriteLine(message);
}
}
As you can see, Log class derived ActionFilterAttribute class. It logs before and after action
method or result executes. You can apply Log attribute to any Controller or action methods
where you want to log the action. For example, by applying Log attribute to Controller, it
will log each action methods of that controller.
The above example will show following output in the output window of Visual Studio on
http://localhost/student request.
Output:
OnActionExecuting- controller:Home action:Index
OnActionExecuted- controller:Home action:Index
OnResultExecuting - controller:Home action:Index
OnResultExecuted- controller:Home action:Index
Points to Remember :
1. Action filters allow pre and post processing logic to be applied to an action method.
2. Action filters are generally used to apply cross-cutting concerns such as logging, caching,
authorization etc.
3. Action filter can be registered as other filters at global, controller or action method level.
4. Custom action filter attribute can be created by deriving ActionFilterAttribute class or
implementing IActionFilter interface and FilterAttribute abstract class.
5. Every action filter must override OnActionExecuted, OnActionExecuting,
OnResultExecuted, OnResultExecuting methods.
Bundling
Bundling and minification techniques were introduced in MVC 4 to improve request load
time. Bundling allow us to load the bunch of static files from the server into one http
request.
Load
script files in separate requests
In the above figure, browser sends two separate requests to load two different JavaScript
file MyJavaScriptFile-1.js and MyJavaScriptFile-2.js.
Bundling technique in MVC 4 allows us to load more than one JavaScript file,
MyJavaScriptFile-1.js and MyJavaScriptFile-2.js in one request as shown below.
Minification
Minification technique optimizes script or css file size by removing unnecessary white
space and comments and shortening variable names to one character.
Example: JavaScript
sayHello = function(name){
//this is comment
var msg = "Hello" + name;
alert(msg);
}
The above JavaScript will be optimized and minimized into following script.
As you can see above, it has removed unnecessary white space, comments and also
shortening variable names to reduce the characters which in turn will reduce the size of
JavaScript file.
Bundling and minification impacts on the loading of the page, it loads page faster by
minimizing size of the file and number of requests.
Bundle Types
Points to Remember :
1. Bundling and Minification minimize static script or css files loading time therby minimize
page loading time.
2. MVC framework provides ScriptBundle, StyleBundle and DynamicFolderBundle classes.
3. ScriptBundle does minification of JavaScript files.
4. StyleBundle does minification of CSS files.
ASP.NET MVC API includes ScriptBundle class that does JavaScript minification and
bundling.
Example: BundleConfig.RegisterBundle()
using System.Web;
using System.Web.Optimization;
//use Include() method to add all the script files with their
paths
scriptBndl.Include(
"~/Scripts/bootstrap.js",
"~/Scripts/respond.js"
);
BundleTable.EnableOptimizations = true;
}
}
In the above example, we have created a bundle of two JavaScript files, bootstrap.js and
respond.js using ScriptBundle for demo purposes.
1. First of all create an instance of ScriptBundle class by specifing the bundle name as a
constructor parameter. This bundle name is a virtual path starting with ~/. You can give
anything in virtual path but it's recommended to give a path that will be easy to identify as
a bundle. Here, we have given "~/bundles/bootstrap" path, so that we can easily identify
that this bundle includes bootstrap related files.
2. Use Include method to add one or more JS files into a bundle with its relative path after
root path using ~ sign.
3. Final, add the bundle into BundleCollection instance, which is specified as a parameter in
RegisterBundle() method.
4. Last, BundleTable.EnableOptimizations = true enables bundling and minification
in debug mode. If you set it to false then it will not do bundling and minification.
You can also use IncludeDirectory method of bundle class to add all the files under
particular directory as shown below.
ScriptBundle Example:
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new
ScriptBundle("~/bundles/scripts").IncludeDirectory("~/Scripts/","*.js",tr
ue));
}
Thus, you can create a bundle of JavaScript files using ScriptBundle. MVC framework
invokes BundleConfig.RegisterBundle() method from the Application_Start event in
Global.asax.cs file, so that it can add all the bundles into BundleCollection at the starting of
an application.
Sometime third party script files includes versions in a name of script file. So it is not
advisable to changes the code whenever you upgrade the version of script file. With the use
of wildcards, you don't have to specify a version of a script file. It automatically includes
files with the version available.
For example, Jquery files includes the version in a name. So you can use {version}
wildcard to pickup a version based on available version.
Example: Wildcard with bundle
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/bundles/jquery")
.Include( "~/Scripts/jquery-{version}.js"));
}
}
Now, it will pick up jquery file added in a project. If you have included jquery-1.7.1.js then
it will render this file and when you upgrade jquery file to jquery-1.10.2.js then it will
automatically render 1.10 version file without changing or compiling code.
Using CDN
You can also use Content Delivery Network to load script files. For example, you can load
jquery library from CDN as shown below.
In the above code, jquery will be requested from the CDN while in release mode and in the
debug mode, jquery library will be loaded from a local source. Please note that you should
have a fallback mechanism to deal with a CDN request failure.
Now, let's see how to use the bundle into a razor view.
We have create a script bundle above. Now, we will learn how to include bundle into razor
view.
The script bundles can be included using static Scripts class. Use Scripts.Render() method
to include specified script bundle at runtime.
Example: Scripts.Render()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
<title>@ViewBag.Title</title>
@Scripts.Render("~/bundles/bootstrap")
</head>
<body>
@*html code removed for clarity *@
</body>
</html>
Now, if you run the above example then you will find two script files is combined, minified
and loaded in a single request. Please make sure that you have set debug = false in
web.config <compilation debug="false" targetFramework="4.5"/>
As you can see in the above figure that bootstrap bundle is loaded in a single request. It has
also combined and minified two JS files for bootstrap.
Points to Remember :
1. Bundling and Minification minimize static script or css files loading time therby minimize
page loading time.
2. ScriptBundle does minification of JavaScript files.
3. Create script or css bundles in BundleConfig class included in App_Start folder.
4. Use wildcard {version} to render available version files at runtime.
5. Use Scripts.Render("bundle name") method to include script bundle in a razor view.
StyleBundle
You have learned how to create a bundle of JavaScript files in the previous section. Here,
you will learn how to create a bundle of style sheet files (CSS).
ASP.NET MVC API includes StyleBundle class that does CSS minification and bundling.
StyleBundle is also derived from a Bundle class so it supports same methods as
ScriptBundle.
As mentioned in the previous section, you should create bundles of script and css files in
the RegisterBundles() method of BundleConfig class contained in App_Start ->
BundleConfig.cs file.
Use ScriptsInclude or IncludeDerictory method to add css files into bundle as shown
below:
Example: StyleBundle
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new StyleBundle("~/bundles/css").Include(
"~/Content/bootstrap.css",
"~/Content/site.css"
));
// add ScriptBundle here..
}
}
As you can see in the above example, we have created StyleBundle instance with bundle
name as virtual path. The bundle name (virtual path) must start with ~/. Use Include() or
IncludeDirectory() method with css file names as a string.
You can use wildcard and CDN path the same way as ScriptBundle as shown in the
previous section.
You can use StyleBundle in a layout view and render bunch of css files in a single request
using static Styles class. Styles is a helper class to render css bundles.
As shown in the above example, use Styles.Render() method to include specified css
bundle at runtime. Open developer tool of the browser and check that it has minified and
loaded css files as shown below.
Points to Remember :
1. Bundling and Minification minimize static script or css files loading time therby minimize
page loading time.
2. MVC framework provides ScriptBundle, StyleBundle and DynamicFolderBundle classes.
3. StyleBundle does minification of CSS files.
4. Create script or css bundles in the BundleConfig class included in App_Start folder.
5. Use wildcard {version} to render available version files at runtime.
6. Use Styles.Render("bundle name") method to include style bundles in a razor view.
Area
You have already learned that ASP.NET MVC framework includes separate folders for
Model, View and Controller. However, large application can include a large number of
controller, views and model classes. So to maintain a large number of views, models and
controllers with the default ASP.NET MVC project structure can become unmanageable
ASP.NET MVC 2 introduced Area. Area allows us to partition large application into
smaller units where each unit contains separate MVC folder structure, same as default
MVC folder structure. For example, large enterprise application may have different
modules like admin, finance, HR, marketing etc. So an Area can contain separate MVC
folder structure for all these modules as shown below.
Area
Create Area
You can create an Area using ASP.NET MVC 5 and Visual Studio 2013 for web by right
clicking on the project in the solution explorer -> Add -> Area..
Area
Enter Area name in Add Area dialogue box and click Add.
Area
This will add 'admin' folder under Area folder as shown below.
Area
As you can see, each area includes AreaRegistration class in {area name} +
AreaRegistration.cs file.
Area Registration:
public class adminAreaRegistration : AreaRegistration
{
public override string AreaName
{
get
{
return "admin";
}
}
AreaRegistration class overrides RegisterArea method to map the routes for the area. In the
above example, any URL that starts with admin will be handled by the controllers included
in the admin folder structure under Area folder. For example, http://localhost/admin/profile
will be handled by profile controller included in Areas/admin/controller/ProfileController
folder.
These tutorials will help you understand these terms to achieve loose coupled design step
by step. These tutorials are broken down into chapters, where each chapter contains a
number of related topics that are packed with easy to understand explanations and real-
world examples.
These tutorials are designed for beginners and professionals who want to learn IoC, DIP, DI
and IoC Container step by step.
Prerequisites
IoC Test
Test your IoC knowledge with a quick test. It includes 20 questions and each question
includes 4 options. Select an appropriate answer out of 4 options. There is no time limit for
this test.
IoC Introduction
The terms Inversion of Control (IoC), Dependency Injection Principle (DIP), Dependency
Injection (DI), and IoC containers may be familiar. But are you clear about what each term
means?
Here, you are going to learn about each term, with simple and real-world examples to clear
your confusion. Before you go further, it is important to understand the difference between
principle and pattern.
Now, let's understand the above buzz words. The following figure clears the confusion
whether on they are principles or patterns.
As illustrated in the above figure, IoC and DIP are high level design principles which
should be used while designing application classes. These are principles, so they only
recommend certain best practices but do not provide any specific implementation details.
Dependency Injection (DI) is a pattern and IoC container is a framework.
Inversion of Control
DIP principle also helps in achieving loose coupling between the classes. It is highly
recommended to use DIP and IoC together in order to achieve loose coupling.
DIP suggests that high-level modules should not depend on low level modules. Both should
depend on abstraction.
DIP principle is invented by Robert Martin (a.k.a. Uncle Bob). He is a founder of SOLID
principles. Learn about DIP in the DIP chapter.
Dependency Injection
Dependency Injection (DI) is a design pattern which implements IoC principle to invert the
creation of dependent objects. We will learn about it in the DI chapter.
IoC Container
We cannot achieve loosely couplde classes by only using IoC. Along with IoC we also need
to use DIP, DI and IoC container. The following figure illustrates how we are going to
achieve loosely coupled design step by step in the next few chapters.
Let's learn about each of the above steps, starting with IoC as the first step in the next
chapter.
Inversion of Control
In this chapter, we will learn about IoC and how to implement it. This would be the first
step towards achieving loose coupled design as illustrated by the following figure.
IoC is all about inverting the control. To explain in layman's term, suppose you drive a car
to your work place, it means you control the car. IoC principle suggests to invert the
control, meaning instead of driving the car yourself, you hire a cab where another person
will drive the car. Thus it is called inversion of the control from you to the cab driver. You
don't have to drive a car yourself and let the driver do the driving so that you can focus on
your main work.
IoC principle helps in designing loosely coupled classes which make them testable,
maintainable and extensible.
In a typical console application in C#, execution starts from the Main() function. The
Main() function controls the flow of a program or in other words sequence of user
interaction. Consider the following simple console program.
Example: Program Flow
namespace FlowControlDemo
{
class Program
{
static void Main(string[] args)
{
bool continueExecution = true;
do
{
Console.Write("Enter First Name:");
var firstName = Console.ReadLine();
if (wantToSave.ToUpper() == "Y")
SaveToDB(firstName, lastName);
if (wantToExit.ToUpper() == "Y")
continueExecution = false;
}while (continueExecution);
In the above example, the Main() function of the program class controls the flow of a
program. It takes user's input for the first Name and last name. It saves the data, continues
or exits the console depending upon the user's input. So here, flow of the control through
the Main() function.
IoC can be applied to the above program by creating a GUI based application such as the
following windows based application wherein the framework will handle the flow of a
program using events.
This is a simple example of implementing IoC on the flow of a program.
IoC can also be applied in the way we create objects of dependent class. First of all, let's
understand what we mean by dependency here.
public class A
{
B b;
public A()
{
b = new B();
}
public class B {
In object oriented design approach, classes need to interact with each other in order to
complete one or more functionalities of an application such as in the above classes A and
B. Class A creates and manages the life time of an object of class B. Essentially it controls
the creation and life time of objects of dependency class.
IoC principle suggests to invert the control, means separate the controlling stuff to another
class. In other words, invert the dependency creation control from the class A to another
class as shown below.
public class A
{
B b;
public A()
{
b = Factory.GetObjectOfB ();
}
As you can see above, class A uses Factory class to get an object of class B. Thus, we have
inverted the dependent object creation from class A to Factory. The class A no longer
creates an object of class B instead it uses Factory class to get the object of class B.
In an object oriented design, classes should be designed in loosely coupled way. Loosely
coupled means changes in one class should not force other classes to change, so the whole
application can become maintainable and extensible. Let's understand this by using typical
n-tier architecture as depicted by the following figure.
In the typical n-tier architecture, the User Interface (UI) uses Service layer to retrieve or
save the data. The service layer uses the BusinessLogic class to apply business rules on
the data. The BusinessLogic class depends on the DataAccess class which retrieves or
saves the data to the underlying database. This is simple n-tier architecture design. Let's
focus on the BusinessLogic and DataAccess class to understand IoC.
public CustomerBusinessLogic()
{
_dataAccess = new DataAccess();
}
As you can see in the above example, the CustomerBusinessLogic class depends on
DataAccess class. It creates an object of the DataAccess class to get customer data.
So, to solve the above problems and get a loosely coupled design, we can use IoC and DIP
principles together. Remember, IoC is a principle not a pattern. It just gives high level
design guidelines but does not give implementation details. You are free to implement IoC
principle the way you want.
Let's use Factory pattern to implement IoC in the above example as the first step towards
attaining loosely coupled classes.
First, create a simple Factory class which returns an object of DataAccess class as shown
below.
public CustomerBusinessLogic()
{
}
return _dataAccess.GetCustomerName(id);
}
}
This is a simple implementation of IoC and the first step towards achieving fully loose
coupled design. As mentioned in the previous chapter, we will not achieve complete
loosely coupled classes by only using IoC. Along with IoC we also need to use DIP,
Strategy pattern, and DI (Dependency Injection).
Let's move to the second step to understand DIP and how it helps in achieving loose
coupled design in the next chapter.
DIP is one of the SOLID object oriented principle invented by Robert Martin (a.k.a. Uncle
Bob)
DIP Definition
1. High-level modules should not depend on low-level modules. Both should depend on
abstraction.
2. Abstractions should not depend on details. Details should depend on abstractions.
To understand DIP, let's take an example from the previous chapter as shown below.
return _dataAccess.GetCustomerName(id);
}
}
Let's use DIP on the CustomerBusinessLogic and DataAccess classes and make them
more loosely coupled.
As per DIP definition, a high-level module should not depend on low-level modules. Both
should depend on abstraction. So, first, decide which is the high-level module (class) and
low-level module. High-level module is a module which depends on other modules. In our
example, CustomerBusinessLogic depends on DataAccess class, so
CustomerBusinessLogic is high-level module and DataAccess is low-level module. So,
as per first rule of DIP, CustomerBusinessLogic should not depends on concrete
DataAccess class, instead both classes depends on abstraction.
The second rule in DIP is "Abstractions should not depend on details. Details should
depend on abstractions".
What is Abstraction?
Now, what should be in interface (or in abstract class)? As you can see,
CustomerBusinessLogic uses GetCustomerName() method of DataAccess class. (In real
life, there will be many customer related methods in DataAccess class). So, let's declare
GetCustomerName(int id) method in the interface as shown below.
Now, we need to change our factory class which returns ICustomerDataAccess instead of
concrete DataAccess class as shown below.
public CustomerBusinessLogic()
{
_custDataAccess = DataAccessFactory.GetCustomerDataAccessObj();
}
public CustomerBusinessLogic()
{
_custDataAccess = DataAccessFactory.GetCustomerDataAccessObj();
}
Still, we have not achieved fully loosely coupled classes because CustomerBusinessLogic
class includes Factory class to get the reference of ICustomerDataAccess. This is where
Dependency Injection pattern helps us. In the next chapter, we will learn how to use DI and
Strategy pattern using the above example.
Dependency Injection
In the previous chapter of DIP, we created and used abstraction to make the classes loosely
coupled. Here, we are going to implement Dependency Injection and strategy pattern
together to move the dependency object creation completely out of the class. This is our
third step in making the classes completely loose coupled.
Dependency Injection (DI) is a design pattern used to implement IoC where it allows
creation of dependent objects outside of a class and provides those objects to a class
through different ways. Using DI, we move the creation and binding of the dependent
objects outside of the class that depends on it.
1. Client Class: The client class (dependent class) is a class which depends on the service class
2. Service Class: The service class (dependency) is a class that provides service to the client
class.
3. Injector Class: The injector class injects service class object into the client class.
As you can see, injector class creates an object of service class, and injects that object to a
client object. This way DI pattern separates the responsibility of creating an object of
service class out of client class.
As you have learned above, the injector class injects the service (dependency) to the client
(dependent). The injector class injects dependencies broadly in three ways: through
constructor, through property, or through method.
Method Injection: In this type of injection, client class implements an interface which
declares method(s) to supply dependency and the injector uses this interface to supply
dependency to the client class.
Let's take an example from the previous chapter to maintain the continuity. In the previous
section of DIP, we used Factory class inside CustomerBusinessLogic class to get an
object of CustomerDataAccess object as shown below.
public CustomerBusinessLogic()
{
_custDataAccess = DataAccessFactory.GetCustomerDataAccessObj();
}
The problem with the above example is that we used DataAccessFactory inside
CustomerBusinessLogic class. So, suppose there is another implementation of
ICustomerDataAccess for some reason and we want to use that new class inside
CustomerBusinessLogic. Then, we need to change the source code of
CustomerBusinessLogic class also. Dependency injection pattern solves this problem by
injecting dependent objects via constructor, property, or interface.
The following figure illustrates the DI pattern implementation for the above example.
Dependency Injection
As you see, CustomerService class becomes injector class which sets an object of service
class (CustomerDataAccess) to the client class (CustomerBusinessLogic) either through
constructor, property, or method to achieve loose coupling. Let's explore each of these
options.
Constructor Injection
As mentioned before, when we provide dependency through the constructor then it's
constructor injection.
public CustomerBusinessLogic()
{
_dataAccess = new CustomerDataAccess();
}
public CustomerService()
{
_customerBL = new CustomerBusinessLogic(new
CustomerDataAccess());
}
As you can see in the above example, CustomerService class creates and injects
CustomerDataAccess object into CustomerBusinessLogic class. Thus,
CustomerBusinessLogic class need not create an object of CustomerDataAccess using
new keyword or using factory class. The calling class (CustomerService) creates and sets
appropriate DataAccess class to the CustomerBusinessLogic class. This way
CustomerBusinessLogic and CustomerDataAccess class become more loosely coupled
classes.
Property Injection
In the property injection, dependency is provided through public property. Consider the
following example.
public CustomerService()
{
_customerBL = new CustomerBusinessLogic();
_customerBL.DataAccess = new CustomerDataAccess();
}
public string GetCustomerName(int id) {
return _customerBL.GetCustomerName(id);
}
}
As you can see above, the CustomerBusinessLogic class includes public property named
DataAccess where you set an instance of a class that has implanted
ICustomerDataAccess. So, CustomerService class creates and sets
CustomerDataAccess class using this public property.
Method Injection
In the method injection, dependencies are provided through methods. This method can be a
class method or interface method.
The following example demonstrates method injection using interface based method.
public CustomerBusinessLogic()
{
}
public CustomerService()
{
_customerBL = new CustomerBusinessLogic();
((IDataAccessDependency)_customerBL).SetDependency(new
CustomerDataAccess());
}
public string GetCustomerName(int id) {
return _customerBL.GetCustomerName(id);
}
}
Thus, you can use DI and strategy pattern to create loose coupled classes.
So far, we have used couple of principles and patterns to achieve loosely coupled classes.
In professional projects, there would be many dependent classes and implementing these
patterns would be time consuming. Here IoC Container (aka DI container) helps us. Learn
about IoC Container in the next chapter.
IoC Container
In the previous chapter, we learned how to implement Dependency Injection pattern to
achieve loose coupled classes. IoC Container (a.k.a. DI Container) is a framework for
implementing automatic dependency injection. It manages object creating and its life time
and also injects dependencies to the class.
IoC container creates an object of the specified class and also injects all the dependency
objects through constructor, property or method at run time and disposes it at the
appropriate time. This is done so that we don't have to create and manage objects manually.
All the containers must provide easy support for the following DI lifecycle.
Unity
StructureMap
Castle Windsor
Ninject
Autofac
DryIoc
Simple Injector
Light Inject
Unity Container
Unity container is an open source IoC container for .NET applications supported by
Microsoft. It is a lightweight and extensible IoC container.
Before we start working with Unity container, let's learn how to install it, in the next
chapter.
Enter Name of the project and location as per your choice and click OK. This will create
new console application project.
Now, we need to install Unity in this project because we want to dependency injection in
our project. So, right click on the project node in the solution explorer and select Manage
NuGet Packages as shown below.
Now, we can search for unity from the browse tab of NuGet. Enter "unity" in the search
box and it will list all the libraries or plugins which contains "unity" word as shown below.
Now, click on Install button in the right pane as shown below.
This will add all the references of unity into your project as shown below.
So now, we are ready to use Unity to implement automatic dependency injection in our
project.
As we learned in the IoC container chapter that every container must provide a way to
register and resolve dependencies. Unity container provides RegisterType() and Resolve()
methods for this.
We are going to use the following sample classes to demo registration and resolution of
dependencies throughout this chapter.
}
public class Driver
{
private ICar _car = null;
As you can see sample classes, Driver class depends on ICar interface. So, when we
instantiate the Driver class object then we will have to pass an instance of a class which
implement ICar interface such as BMW, Audi or Ford class as shown below.
driver.RunCar();
Output:
Running BMW - 1 mile
In the above example, we created and passed an object of BMW while creating an object of
Driver class. Thus, we injected dependency of Driver class manually. Now, use unity
container and understand different ways to register and resolve dependencies.
Using UnityContainer.
In order to use unity container, we first need to create an object of it. You can use any class
which implements IUnityContainer interface. Unity container includes UnityContainer
class in Microsoft.Practices.Unity namespace that implements IUnityContainer
interface. If you need to extend the container then you can create your own custom class
and implement IUnityContainer interface as per your need.
Register
Before unity resolve dependencies, we first need to register the type-mapping with the
container, so that it can create the correct object for the given type. Use RegisterType()
method to register a type mapping. Basically, it configures which class to instantiate, for
which interface or base class. For example, if we want unity container to create and supply
an object of BMW class whenever it needs to supply dependency of ICar interface, then you
first need to register it as below.
container.RegisterType<ICar, BMW>();
The RegisterType method includes many overloads. Learn about all the overloads of
RegisterType on MSDN.
Unity creates an object of the specified class and automatically injects dependencies using
resolve() method. We have registered BMW with ICar above. Now, we can instantiate the
Driver class using unity container without using new keyword as shown below.
Example: Resolve
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();// Map ICar with BMW
In the above example, unity container creates an object of a class Driver using
container.Resolve<driver>() method. The Driver class is a dependent on ICar. So,
container.Resolve<Driver>() returns an object of Driver class by automatically
creating and injecting BMW object in it. All this is behind the scene. It creates and injects BMW
object because we register BMW type with ICar.
Unity container will create new object and inject it every time whenever we resolve the
same type.
In the above example, container injects BMW object whenever it resolves Driver class e.g.
driver1 and driver2 both has a reference of separate BMW objects.
Thus, you can create an object of the specified type using unity container. Learn about all
the overloads of Resolve method on MSDN.
Multiple Registration
Unity container will inject last registered type if you register multiple mappings of the same
type.
IUnityContainer container = new UnityContainer();
container.RegisterType<ICar, BMW>();
container.RegisterType<ICar, Audi>();
In the above example, ICar is mapped to both BMW and Audi. But, unity will inject Audi
every time because it has been registered last.
You can register a type-mapping with a name which you can use with Resolve method.
As you can see above, we have mapped ICar with both BMW and Audi class. However, we
have given a name "LuxuryCar" to ICar-Audi mapping. So now, Resolve() method will
return an object of Audi if we specify the mapping name.
Register Instance
Let understand how we can perform property injection using unity container. Consider the
following example classes.
}
public class Driver
{
public Driver()
{
}
[Dependency]
public ICar Car { get; set; }
As you can see in the above sample classes, the Driver class is dependent on a property of
type ICar. So, we need to set an object of a class that implements ICar to the Car property
using unity container.
[Dependency] Attribute
For the property injection, we first tell the unity container which property to inject. So, we
need to decorate the dependent properties with the [Dependency] attribute as shown in the
following Driver class.
public Driver()
{
}
[Dependency]
public ICar Car { get; set; }
Named Mapping
We can specify a name in the [Dependency("name")] attribute, which can then be used to
set property value.
[Dependency("LuxuryCar")]
public ICar Car { get; set; }
Run-time Configuration
//run-time configuration
container.RegisterType<Driver>(new InjectionProperty("Car", new BMW()));
nityContainer();
ICar audi = new Audi();
container.RegisterInstance<ICar>(audi);
Thus, we can register and resolve different types using Unity container. Learn how Unity
container performs constructor injection in the next chapter.
Unity Container: Constructor Injection
In the previous chapter, we learned about registering and resolving types using unity. Here,
you will learn how unity container performs constructor injection.
}
public class Driver
{
private ICar _car = null;
public Driver(ICar car)
{
_car = car;
}
As you can see above, the Driver class accepts an object of type ICar in the constructor.
So, the unity container will inject dependencies via constructor as shown below.
Thus, the Resolve() method by default performs constructor injection while resolving types.
Multiple Parameters
You can also inject multiple parameters in the constructor. Consider the following example.
}
public class FordKey : ICarKey
{
So now, you can register ICar and ICarKey with unity and inject both the parameters as
shown below.
container.RegisterType<ICar, Audi>();
container.RegisterType<ICarKey, AudiKey>();
Multiple Constructors
[InjectionConstructor]
public Driver(ICar car)
{
_car = car;
}
public Driver(string name)
{
}
As you can see, Driver class includes two constructors. So, we have used
[InjectionConstructor] attribute to indicate which constructor to call when resolving the
Driver class.
You can configure the same thing as above at run time instead of applying
[InjectionConstructor] attribute by passing InjectionConstructor in the RegisterType()
method as shown below.
//or
container.RegisterType<ICar, Ford>();
container.RegisterType<Driver>(new
InjectionConstructor(container.Resolve<ICar>()));
Primitive Type Parameter
Unity also injects primitive type parameter in the constructor. Consider the following
Driver class with primitive type parameter in the constructor.
In the method injection, dependencies are provided through method parameters. Visit
Dependency Injection chapter to learn more about method injection.
Let's understand how we can perform method injection using unity container. Consider the
following example classes.
}
public class Driver
{
private ICar _car = null;
public Driver()
{
}
As you can see in the above sample classes, the Driver class includes method UseCar() to
set the object of type ICar. Here, we have taken a simple method example. However, you
can also use interface based method injection explained in Dependency Injection chapter.
[InjectionMethod] Attribute
For the method injection, we need to tell the unity container which method should be used
for dependency injection. So, we need to decorate a method with the [InjectionMethod]
attribute as shown in the following Driver class.
public Driver()
{
}
[InjectionMethod]
public void UseCar(ICar car) {
_car = car;
}
Run-time Configuration
//run-time configuration
container.RegisterType<Driver>(new InjectionMethod("UseCar", new
Audi()));
}
public class Driver
{
private ICar _car = null;
Example: ParameterOverride
var container = new UnityContainer()
.RegisterType<ICar, BMW>();
In the above example, unity container injects BMW in driver1 which is default mapping.
However, we override default mapping and specify a different mapping for driver2 by
passing new ParameterOverride("car", new Ford()) into Resolve() method. The first
parameter is the name of the constructor parameter and second is the value of a parameter.
So, driver2 includes an object of Ford class instead of BMW class.
If a constructor includes multiple parameters then we can override them by passing an array
of ResolverOverride as shown below.
We learned about Property Injection in the previous chapter. Here, we will learn how to
override the registered value of the specified property using PropertyOverride.
You can override registered property injection and provide different property value when
you resolve it.
Example: PropertyOverride
var container = new UnityContainer();
driver2.RunCar();
Output:
BMW - 1 mile
Audi - 1 mile
DependencyOverride
The DependencyOverride class can be used to override the type of dependency and its
value, irrespective of whether dependencies are provided through constructor, property or a
method.
You can override registered method injection and provide different parameter value when
you resolve it. Consider the following example.
Example: DependencyOverride
var container = new UnityContainer()
.RegisterType<ICar, BMW>();
//Override dependency
var driver2 = container.Resolve<Driver>(new DependencyOverride<ICar>(new
Audi())
driver2.RunCar();
Output:
Running BMW - 1 mile
Running Audi - 1 mile
Unity container includes different lifetime managers for different purposes. You can
specify lifetime manager in RegisterType() method at the time of registering type-mapping.
For example, the following code snippet shows registering a type-mapping with
TransientLifetimeManager.
TransientLifetimeManager Creates a new object of requested type every time you call
Lifetime Manager Description
Let's understand each lifetime manager using the following example classes.
In the above example, unity container will create two new instances of BMW class and injects
into driver1 and driver2 object. This is because the default lifetime manager is
TransientLifetimeManager which creates new dependent object every time you call
Resolve or ResolveAll method. You can specify the lifetime manager at the time of
registering type using RegisterType() method.
The following example will display same output as above example because
TransientLifetimeManager is the default manager if not specified.
ContainerControlledLifetimeManager
HierarchicalLifetimeManager
As you can see, container and childContainer have their own singleton instance of BMW.
C# Tutorials
C# is a simple & powerful object-oriented programming language developed by Microsoft.
C# can be used to create various types of applications, such as web, windows, console
applications or other types of applications using Visual studio.
These C# tutorials will help you learn the essentials of C#, from the basic to advance level
topics. These tutorials are broken down into sections, where each section contains a number
of related topics that are packed with easy to understand explanations, real-world examples,
useful tips, informative notes and a "points to remember" section.
These tutorials are designed for beginners and professionals who want to learn C# step-by-
step.
C# Version History
C# is a simple & powerful object-oriented programming language developed by Microsoft.
C# has evolved much since its first release in 2002. C# was introduced with .NET
Framework 1.0 and the current version of C# is 6.0.
The following table lists important features introduced in each version of C#:
Generics
Partial types
Anonymous methods
Iterators
Nullable types
Private setters (properties)
C# 2.0 .NET Framework 2.0 Visual Studio 2005
Method group conversions
(delegates)
Covariance and Contra-
variance
Static classes
Async features
Visual Studio
C# 5.0 .NET Framework 4.5 Caller information
2012/2013
Expression Bodied Methods
Auto-property initializer
nameof Expression
Visual Studio Primary constructor
C# 6.0 .NET Framework 4.6
2013/2015 Await in catch block
Exception Filter
String Interpolation
The .NET Framework is a platform where you can write different types of web and desktop
based applications. You can use C#, Visual Basic, F# and Jscript to write these
applications. If you have the Windows operating system, the .NET framework might
already be installed in your PC. Check MSDN to learn about .NET Framework
dependencies.
An IDE is a tool that helps you write your programs. Visual Studio is an IDE provided by
Microsoft to write the code in languages such as C#, F#, VisualBasic, etc. Use latest
version of Visual Studio (2017) to learn C#.
You can write C# code with notepad also. Build your C# program using command line
tool csc.exe. Visit MSDN for more information.
Visual Studio Community edition is a free for individual developer for personal or
commercial use. However, you can purchase a license for Visual Studio Professional or
Enterprise edition. Download and install Visual Studio Community from visualstudio.com
for free.
Open Visual Studio 2017 installed on your local machine. Click on File -> New Project...
from the top menu as shown below.
Create a New Project in Visual Studio 2017
From the New Project popup as shown below, select Visual C# in the left side panel and
select Console App in the right side panel.
Select Visual C# Console App Template
In the name section, give any appropriate project name, location where you want to create
all the project files and solution name.
Click OK to create the console project. Program.cs will be created as default a C# file in
Visual Studio where you can write your C# code in Program class as shown below. (The .cs
is a file extension for C# file.)
C# Console Program
Thus, you can create a C# console application in Visual Studio. Now, you can write C#
code in program.cs file to play with C#.
First C# Program
In the previous section, we have created a console project. Now, let's write simple C# code
to understand important building blocks.
Every console application starts from the Main() method of Program class. The following
example code displays "Hello World!!" on the console.
namespace CSharpTutorials
{
class Program
{
static void Main(string[] args)
{
string message = "Hello World!!";
Console.WriteLine(message);
}
}
}
The following image illustrates the important parts of the above example.
C# Code Structure
1. Every .NET application takes the reference of the necessary .NET framework namespaces
that it is planning to use with the "using" keyword e.g. using System.Text
2. Declare the namespace for the current class using the "namespace" keyword e.g.
namespace CSharpTutorials.FirstProgram
3. We then declared a class using the "class" keyword: class Program
4. The Main() is a method of Program class which is the entry point of the console
application.
5. String is a data type.
6. 'message' is a variable, that holds a value of a specified data type.
7. "Hello World!!" is the value of the message variable.
8. Console is a .NET framework class. WriteLine() is a method which you can use to display
messages to the console.
Note:
Every line or statement in C# must end with a semicolon (;).
In order to see the output of the above C# program, we have to compile it and run it by
pressing Ctrl + F5, or clicking Run button or by clicking the "Debug" menu and clicking
"Start Without Debugging". You will see following output in the console:
Output:
Hello World!!
So this is the basic code items that you will probably use in every C# code. Let's learn
about C# Class in the next section.
C# Class
A class is like a blueprint of specific object. In the real world, every object has some color,
shape and functionalities. For example, the luxury car Ferrari. Ferrari is an object of the
luxury car type. The luxury car is a class that specify certain characteristic like speed, color,
shape, interior etc. So any company that makes a car that meet those requirements is an
object of the luxury car type. For example, every single car of BMW, lamborghini, cadillac
are an object of the class called 'Luxury Car'. Here, 'Luxury Car' is a class and every single
physical car is an object of the luxury car class.
Likewise, in object oriented programming, a class defines certain properties, fields, events,
method etc. A class defines the kinds of data and the functionality their objects will have.
A class enables you to create your own custom types by grouping together variables of
other types, methods and events.
Example: C# Class
public class MyClass
{
public string myField = string.Empty;
public MyClass()
{
}
C# Class
C# Access Modifiers
Access modifiers are applied on the declaration of the class, method, properties, fields and
other members. They define the accessibility of the class and its members. Public, private,
protected and internal are access modifiers in C#. We will learn about it in the keyword
section.
C# Field
Field is a class level variable that can holds a value. Generally field members should have a
private access modifier and used with a property.
C# Constructor
A class can have parameterized or parameter less constructors. The constructor will be
called when you create an instance of a class. Constructors can be defined by using an
access modifier and class name: <access modifiers> <class name>(){ }
Example: Constructor in C#
class MyClass
{
public MyClass()
{
}
}
C# Method
Example: Method in C#
public void MyMethod(int parameter1, string parameter2)
{
// write your method code here..
}
Property
Example: Property in C#
private int _myPropertyVar;
Property encapsulates a private field. It provides getters (get{}) to retrieve the value of the
underlying field and setters (set{}) to set the value of the underlying field. In the above
example, _myPropertyVar is a private field which cannot be accessed directly. It will only
be accessed via MyProperty. Thus, MyProperty encapsulates _myPropertyVar.
You can also apply some addition logic in get and set, as in the below example.
Example: Property in C#
private int _myPropertyVar;
set {
if (value > 100)
_myPropertyVar = 100;
else
_myPropertyVar = value; ;
}
}
Auto-implemented Property
From C# 3.0 onwards, property declaration has been made easy if you don't want to apply
some logic in get or set.
Notice that there is no private backing field in the above property example. The backing
field will be created automatically by the compiler. You can work with an automated
property as you would with a normal property of the class. Automated-implemented
property is just for easy declaration of the property when no additional logic is required in
the property accessors.
Namespace
Namespace is a container for a set of related classes and namespaces. Namespace is also
used to give unique names to classes within the namespace name. Namespace and classes
are represented using a dot (.).
Example: Namespace
namespace CSharpTutorials
{
class MyClass
{
}
}
In the above example, the fully qualified class name of MyClass is
CSharpTutorials.MyClass.
A namespace can contain other namespaces. Inner namespaces can be separated using (.).
Example: Namespace
namespace CSharpTutorials.Examples
{
class MyClassExample
{
}
}
C# Variable
In the first C# program chapter, we declared a variable called "message" as shown below.
Example: C# Variable
namespace CSharpTutorials
{
class Program
{
static void Main(string[] args)
{
string message = "Hello World!!";
Console.WriteLine(message);
}
}
}
The variable in C# is nothing but a name given to a data value. In the above example,
message is the name of the variable that stores the string data value "Hello World!!". As the
name suggests, the contents of a variable can vary, i.e., you can change the value of a
variable at any time.
In C#, a variable is always defined with a data type. The following is the syntax variable
declaration and initialization.
Variable Syntax:
<data type> <variable name>;
A variable can be declared and initialized later or it can be declared and initialized at the
same time. In the following example, the first statement declares a variable called
"message" without assigning any value to it. In the second statement, a value is assigned to
the "message" variable.
In the following example, variable is declared and initialized (a value is assigned to it) at
the same time.
Multiple variables of the same data type can be declared and initialized in a single line
separated by commas.
When declaring multiple variables of the same data type, you can put them in multiple lines
for the sake of readability; even if split across multiple lines, the compiler will consider it to
be one statement, until it encounters a semicolon (;).
The value of a variable can be assigned to another variable of the same data type. However,
a value must be assigned to a variable before using it.
The following example would give a compile time error because string value cannot be
assinged to a int type variable.
Example: Invalid Variable Assignment
string message = "Hello World!!";
You must assign a value to a variable before using it otherwise the compiler will give an
error. For example, in the following code, we have declared a variable called i without
assigning any value to it. If we then try to display the value of the variable on the console,
we will get a compile time error.
Points to Remember :
C# Data Types
In the previous section, we have seen that a variable must be declared with the data type
because C# is a strongly-typed language. For example,
Above, string is a data type, message is a variable, and "Hello World!!" is a string
value assigned to a variable message.
The data type tells the C# compiler what kind of value a variable can hold. C# includes
many in-built data types for different kinds of data, e.g. String, number, float, decimal, etc.
Example: Data types
class Program
{
static void Main(string[] args)
{
string stringVar = "Hello World!!";
int intVar = 100;
float floatVar = 10.2f;
char charVar = 'A';
bool boolVar = true;
}
}
Each data types includes specific range of values. For example, a variable of int data type
can have any value between -2,147,483,648 to 2,147,483,647. The same way, bool data
type can have only two value - true or false. The following table lists the data types
available in C# along with the range of values possible for each data type:
.NET Size
Alias Type Range (values)
Type (bits)
-9,223,372,036,854,775,808 to
long Int64 Signed integer 64
9,223,372,036,854,775,807
As you can see in the above table that each data types (except string and object) includes
value range. Compiler will give an error if value goes out of datatype's permitted range. For
example, int data type's range is -2,147,483,648 to 2,147,483,647. So if you assign value
which is not in this range then compiler would give error.
In the above table of data types, first column is for data type alias and second column is
actual .Net type name. For example, int is an alias (or short name) for Int32. Int32 is a
structure defined in System namespace. The same way, string represent String class.
Data types are further classified as value type or reference type, depending on whether a
variable of a particular type stores its own data or a pointer to the data in the memory.
Learn about variables in value type and reference type in the next section.
1. Value type
2. Reference type
Value Type:
A data type is a value type if it holds a data value within its own memory space. It means
variables of these data types directly contain their values.
All the value types derive from System.ValueType, which in-turn, derives from
System.Object.
The system stores 100 in the memory space allocated for the variable 'i'. The following
image illustrates how 100 is stored at some hypothetical location in the memory
(0x239110) for 'i':
Memory allocation for Value Type
bool
byte
char
decimal
double
enum
float
int
long
sbyte
short
struct
uint
ulong
ushort
Passing by Value:
When you pass a value type variable from one method to another method, the system
creates a separate copy of a variable in another method, so that if value got changed in the
one method won't affect on the variable in another method.
Console.WriteLine(x);
}
Console.WriteLine(i);
ChangeValue(i);
Console.WriteLine(i);
}
Output:
100
200
100
In the above example, variable i in Main() method remains unchanged even after we pass it
to the ChangeValue() method and change it's value there.
Reference Type
Unlike value types, a reference type doesn't store its value directly. Instead, it stores the
address where the value is being stored. In other words, a reference type contains a pointer
to another memory location that holds the data.
The following image shows how the system allocates the memory for the above string
variable.
Memory allocation
for Reference type
As you can see in the above image, the system selects a random location in memory
(0x803200) for the variable 's'. The value of a variable s is 0x600000 which is the memory
address of the actual data value. Thus, reference type stores the address of the location
where the actual value is stored instead of value itself.
String
All arrays, even if their elements are value types
Class
Delegates
Pass by Reference
When you pass a reference type variable from one method to another, it doesn't create a
new copy; instead, it passes the address of the variable. If we now change the value of the
variable in a method, it will also be reflected in the calling method.
ChangeReferenceType(std1);
Console.WriteLine(std1.StudentName);
}
Output:
Steve
In the above example, since Student is an object, when we send the Student object std1 to
the ChangeReferenceType() method, what is actually sent is the memory address of std1.
Thus, when the ChangeReferenceType() method changes StudentName, it is actually
changing StudentName of std1, because std1 and std2 are both pointing to the same address
in memory. Therefore, the output is Steve.
Null
Reference types have null value by default, when they are not initialized. For example, a
string variable (or any other variable of reference type datatype) without a value assigned to
it. In this case, it has a null value, meaning it doesn't point to any other memory location,
because it has no value yet.
Null Reference
type
A value type variable cannot be null because it holds a value not a memory address.
However, value type variables must be assigned some value before use. The compiler will
give an error if you try to use a local value type variable without assigning a value to it.
Console.WriteLine(i);
}
C# 2.0 introduced nullable types for value types so that you can assign null to a value
type variable or declare a value type variable without assigning a value to it.
However, value type field in a class can be declared without initialization (field not a local
variable in the function) . It will have a default value if not assigned any value, e.g., int will
have 0, boolean will have false and so on.
Console.WriteLine(mcls.i);
Output:
0
Points to Remember :
1. Value type stores the value in its memory space, whereas reference type stores the
address of the value where it is stored.
2. Primitive data types and struct are of the 'Value' type. Class objects, string, array,
delegates are reference types.
3. Value type passes byval by default. Reference type passes byref by default.
4. Value types and reference types stored in Stack and Heap in the memory depends on the
scope of the variable.
Further Reading
Read Eric Lippert's blog part 1 and part 2 for more details about value type and reference
type.
Visit MSDN to know default values of value types.
C# Keywords
C# contains reserved words, that have special meaning for the compiler. These reserved
words are called "keywords". Keywords cannot be used as a name (identifier) of a variable,
class, interface, etc.
Modifier Keywords
Modifier keywords are certain keywords that indicate who can modify types and type
members. Modifiers allow or prevent certain parts of programs from being modified by
other parts.
Modifier keywords
abstract
async
const
event
extern
new
override
partial
readonly
sealed
static
unsafe
virtual
volatile
Modifier keywords
Access modifiers are applied on the declaration of the class, method, properties, fields and
other members. They define the accessibility of the class and its members.
Access
Usage
Modifiers
The Public modifier allows any part of the program in the same assembly or another
public
assembly to access the type and its members.
The Private modifier restricts other parts of the program from accessing the type
private
and its members. Only code in the same class or struct can access it.
The Internal modifier allows other program code in the same assembly to access the
internal
type or its members. This is default access modifiers if no modifier is specified.
The Protected modifier allows codes in the same class or a class that derives from
protected
that class to access the type or its members.
Statement Keywords
Statement Keywords
if
else
switch
case
do
for
foreach
in
while
break
Statement Keywords
continue
default
goto
return
yield
throw
try
catch
finally
checked
unchecked
fixed
lock
params
ref
out
Namespace Keywords
Namespace Keywords
using
. operator
:: operator
Namespace Keywords
extern alias
Operator Keywords
Operator Keywords
as
await
is
new
sizeof
typeof
stackalloc
checked
unchecked
Access Keywords
Access keywords are used to access the containing class or the base class of an object or
class.
Access keywords
base
this
Literal Keywords
Literal Keywords
null
false
true
Literal Keywords
value
void
Type Keywords
Type keywords
bool
byte
char
class
decimal
double
enum
float
int
long
sbyte
short
string
struct
uint
ulong
ushort
Contextual Keywords
Contextual keywords are considered as keywords, only if used in certain contexts. They are
not reserved and so can be used as names or identifiers.
Contextual Keywords
add
var
dynamic
global
set
value
Contextual keywords are not converted into blue color (default color for keywords in visual
studio) when used as an identifier in Visual Studio. For example, var in the below figure is
not in blue color whereas color of this is blue color. So var is a contextual keyword.
C# Keywords
Query Keywords
Query Keywords
from
where
select
group
into
orderby
join
let
Query Keywords
in
on
equals
by
ascending
descending
@class.MyProperty = 100;
Points to Remember :
C# Interface:
An interface in C# contains only the declaration of the methods, properties, and events, but
not the implementation. It is left to the class that implements the interface by providing
implementation for all the members of the interface. Interface makes it easy to maintain a
program.
In C#, an interface can be defined using the interface keyword. For example, the following
is a simple interface for a logging string message:
Interface Declaration:
interface ILog
{
void Log(string msgToLog);
}
Now, different classes can implement ILog by providing an implementation of the Log()
method, for example, the ConsoleLog class logs the string on the console whereas FileLog
logs the string into a text file.
Implement Interface
class ConsoleLog: ILog
{
public void Log(string msgToPrint)
{
Console.WriteLine(msgToPrint);
}
}
Now, you can instantiate an object of either the ConsoleLog or FileLog class:
Instantiate Object
ILog log = new ConsoleLog();
//Or
You can implement interface explicitly by prefixing interface name with method name, as
below:
Points to Remember :
C# Operators
Operator in C# is a special symbol that specifies which operations to perform on operands.
For example, in mathematics the plus symbol (+) signifies the sum of the left and right
numbers. In the same way, C# has many operators that have different meanings based on
the data types of the operands. C# operators usually have one or two operands. Operators
that have one operand are called Unary operators.
Primary x.y
Unary +x
Multiplicative x*y
Additive x+y
Shift x << y
Equality x == y
Logical OR x|y
Conditional OR x || y
Null-coalescing x ?? y
Conditional ?:
As mentioned before, certain operators have different meanings based on the datatype of
the operand. For example, if the + operator is used with numbers, it will add the numbers
but if it is used with strings, it will concatenate the two strings.
When an operator does different things based on the datatype of the operands, it is called
operator over loading.
The following C# code shows the use of the + sign operator on different datatypes:
Example: + Operator
static void Main(string[] args)
{
string message1 = "Hello";
Console.WriteLine(message2);
int sum = i + j;
Output:
Hello World!!
10 + 20 = 30.
This tutorial doesn't cover detail of each operators. Visit MSDN to learn all the operators in
detail.
if Statement
C# provides many decision making statements that help the flow of the C# program based
on certain logical conditions. C# includes the following decision making statements.
1. if statement
2. if-else statement
3. switch statement
4. Ternary operator :?
Syntax:
if(boolean expression)
{
// execute this code block if expression evalutes to true
}
The if statement contains boolean expression inside brackets followed by a single or multi
line code block. At runtime, if a boolean expression is evalutes to true then the code block
will be executed.
Consider the following example where the if condition contains true as an expression.
Example: if condition
if(true)
{
Console.WriteLine("This will be displayed.");
}
if(false)
{
Console.WriteLine("This will not be displayed.");
}
Example: if condition
int i = 10, j = 20;
if (i > j)
{
Console.WriteLine("i is greater than j");
}
if (i < j)
{
Console.WriteLine("i is less than j");
}
if (i == j)
{
Console.WriteLine("i is equal to j");
}
Output:
i is less than j
In the above example, the boolen expression i < j in the second 'if' statement evalutes to
be true, only the second 'if' statement's code block will be executed. The first and third 'if'
condition evalutes to false, so their code blocks will not be executed.
if-else Statement
C# also provides for a second part to the if statement, that is else. The else statement must
follow if or else if statement. Also, else statement can appear only one time in a if-else
statement chain.
Syntax:
if(boolean expression)
{
// execute this code block if expression evalutes to true
}
else
{
// always execute this code block when above if expression is false
}
As you can see in the above syntax, the else stament cannot contain any expression. The
code block that follows else statement will always be executed, when the 'if' condition
evalutes to be false.
Example: if else
int i = 10, j = 20;
if (i > j)
{
Console.WriteLine("i is greater than j");
}
else
{
Console.WriteLine("i is either equal to or less than j");
}
Output:
i is either equal to or less than j
else if Statement
The 'if' statement can also follow an 'else' statement, if you want to check for another
condition in the else part.
Example: else if
static void Main(string[] args)
{
int i = 10, j = 20;
if (i > j)
{
Console.WriteLine("i is greater than j");
}
else if (i < j)
{
Console.WriteLine("i is less than j");
}
else
{
Console.WriteLine("i is equal to j");
}
}
Output:
i is less than j
You can use multiple else-if statements in a single 'if' statment chain. Also, you can remove
the curly brackets, when the 'if' block has only one line to execute:
if (i > j)
Console.WriteLine("i is greater than j");
else if (i < j)
Console.WriteLine("i is less than j");
else if (i == j)
Console.WriteLine("i is equal to j");
Output:
i is less than j
Nested if Statements
C# alows nested if else statements. The nested 'if' statement makes the code more readable.
if (i > 0)
{
if (i <= 100)
{
Console.WriteLine("i is positive number less than 100");
}
else
{
Console.WriteLine("i is positive number greater than
100");
}
}
Output:
i is positive number less than 100
The if-else statement can be replaced by ternary operator. Learn about ternary operator in
the next section.
Points to Remember :
1. if-else statement controls the flow of program based on the evaluation of the boolean
expression.
2. It should start from the if statement followed by else or else-if statements.
3. Only one else statement is allowed in the if-else chain.
4. Multiple else-if statements are allowed in a single if-else chain.
5. Nested if-else statement is allowed.
C# - Ternary operator ?:
C# includes a special type of decision making operator '?:' called the ternary operator.
Variable Syntax:
Boolean Expression ? First Statement : Second Statement
As you can see in the above syntax, ternary operator includes three parts. First part
(before ?) includes conditional expression that returns boolean value true or false. Second
part (after ? and before :) contains a statement which will be returned if the conditional
expression in the first part evalutes to true. The third part includes another statement which
will be returned if the conditional expression returns false.
Note:
Ternary operator returns a value or expression included in the second or third part of it. It does
not execute the statements.
Consider the following example where conditional expression x > y returns false, so it the
returns the first statement after ?.
var result = x > y ? "x is greater than y" : "x is less than or equal to
y";
Console.WriteLine(result);
output:
x is greater than y
The ternary operator can return a value of any data type. So it is advisable to store it in
implicitly typed variable - var.
Console.WriteLine(result);
output:
20
Ternary operator can also be used instead of if-else statement. The above example can be
written using if-else statement as shown below.
if (x > y)
result = x;
else if (x < y)
result = y;
Console.WriteLine(result);
output:
20
Nested ternary operators are possible by including conditional expression as a second (after
?) or third part (after :) of the ternary operator..Consider the following example.
Points to Remember :
C# - switch
C# includes another decision making statement called switch. The switch statement
executes the code block depending upon the resulted value of an expression.
Syntax:
switch(expression)
{
case <value1>
// code block
break;
case <value2>
// code block
break;
case <valueN>
// code block
break;
default
// code block
break;
}
As per the syntax above, switch statement contains an expression into brackets. It also
includes multiple case labels, where each case represents a particular literal value. The
switch cases are seperated by a break keyword which stops the execution of a particular
case. Also, the switch can include a default case to execute if no case value satisfies the
expression.
Note:
Case label in switch must be unique. It can be bool, char, string, integer, enum, or corresponding
nullable type.
Example: switch
int x = 10;
switch (x)
{
case 5:
Console.WriteLine("Value of x is 5");
break;
case 10:
Console.WriteLine("Value of x is 10");
break;
case 15:
Console.WriteLine("Value of x is 15");
break;
default:
Console.WriteLine("Unknown value");
break;
}
Output:
Value of x is 10
The switch statement can include expression or variable of any data type such as string,
bool, int, enum, char etc.
switch (statementType)
{
case "if.else":
Console.WriteLine("if...else statement");
break;
case "ternary":
Console.WriteLine("Ternary operator");
break;
case "switch":
Console.WriteLine("switch statement");
break;
}
Output:
switch statement
Goto in switch:
The switch case can use goto to jump over a different case.
switch (statementType)
{
case "DecisionMaking":
Console.Write("if-else is a decision making statement.");
break;
case "if.else":
Console.Write("if-else");
break;
case "ternary":
Console.Write("Ternary operator");
break;
case "switch":
Console.Write("switch statement");
goto case "DecisionMaking";
}
Output:
switch statement is a decision making statement.
Nested switch:
Nested switch statments are allowed in C# by writing inner switch statement inside a outer
switch case.
switch (j)
{
case 5:
Console.WriteLine(5);
switch (j - 1)
{
case 4:
Console.WriteLine(4);
switch (j - 2)
{
case 3:
Console.WriteLine(3);
break;
}
break;
}
break;
case 10:
Console.WriteLine(10);
break;
case 15:
Console.WriteLine(15);
break;
default:
Console.WriteLine(100);
break;
}
Output:
5
4
3
Points to Remember :
C# - for loop
The for keyword indicates a loop in C#. The for loop executes a block of statements
repeatedly until the specified condition returns false.
Syntax:
for (variable initialization; condition; steps)
{
//execute this code block as long as condition is satisfied
}
As per the syntax above, the for loop contains three parts: initialization, conditional
expression and steps, which are separated by a semicolon.
1. variable initialization: Declare & initialize a variable here which will be used in conditional
expression and steps part.
2. condition: The condition is a boolean expression which will return either true or false.
3. steps: The steps defines the incremental or decremental part
for loop
execution steps
As you can see in the above example, first step is to declare & initialize an int type variable.
The second step is to check the condition. The third step is to execute the code block if the
'if' condition returns true. The fourth step is to increment the int variable and last step is to
eveluate the condition again and repeat the steps.
It is not necessary to put the initialization, condition and steps into brackets. You can
initialize a variable before the 'for' loop, and the condition and steps can be defined inside
the for loop.
for(;;)
{
if (i < 10)
{
Console.WriteLine("Value of i: {0}", i);
i++;
}
else
break;
}
Output:
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Value of i: 6
Value of i: 7
Value of i: 8
Value of i: 9
Be careful with infinite loop. It will be an infinite loop if for loop does not contain
initialization, condition or steps part. Also, make sure that conditional expression will
return false at some point of time to stop the looping.
The control variable for the for loop can be of any numeric data type, such as double,
decimal, etc.
The steps part in a for loop can either increase or decrease the value of a variable.
You can also exit from a for loop by using the break keyword.
Points to Remember :
C# - while loop:
C# includes the while loop to execute a block of code repeatedly.
Syntax:
While(boolean expression)
{
//execute code as long as condition returns true
As per the while loop syntax, the while loop includes a boolean expression as a condition
which will return true or false. It executes the code block, as long as the specified
conditional expression returns true. Here, the initialization should be done before the loop
starts and increment or decrement steps should be inside the loop.
i++;
}
Output:
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Value of i: 6
Value of i: 7
Value of i: 8
Value of i: 9
In the above example, while loop inclues an expression i < 10. Inside while loop, value of
i increased to 1 (using i++). So, the above while loop will be executed till the value of i will
be 10.
Use the break keyword to exit from a while loop as shown below.
while (true)
{
Console.WriteLine("Value of i: {0}", i);
i++;
if (i > 10)
break;
}
Output:
Value of i: 0
while (i < 2)
{
Console.WriteLine("Value of i: {0}", i);
int j = 1;
i++;
while (j < 2)
{
Console.WriteLine("Value of j: {0}", j);
j++;
}
}
Output:
Value of i: 0
Value of j: 1
Value of i: 1
Value of j: 1
Note:
Please make sure that conditional expression evaluates to false at some point to avoid infinite
loop.
Points to Remember :
1. The while loop executes the block of code repeatedly.
2. The while loop includes condition expression. Increment/decrement step should be inside
the loop.
3. Use break keyword to stop the execution and exit from while loop.
4. An nested while loop is allowed.
C# - do while
The do-while loop is the same as a 'while' loop except that the block of code will be
executed at least once, because it first executes the block of code and then it checks the
condition.
Syntax:
do
{
//execute code block
} while(boolean expression);
As per the syntax above, do-while loop starts with the 'do' keyword followed by a code
block and boolean expression with 'while'.
do
{
Console.WriteLine("Value of i: {0}", i);
i++;
Output:
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Value of i: 6
Value of i: 7
Value of i: 8
Value of i: 9
Just as in the case of the for and while loops, you can break out of the do-while loop using
the break keyword.
do
{
Console.WriteLine("Value of i: {0}", i);
i++;
if (i > 5)
break;
} while (true);
Output:
Value of i: 0
Value of i: 1
Value of i: 2
Value of i: 3
Value of i: 4
Value of i: 5
Nested do-while
do
{
Console.WriteLine("Value of i: {0}", i);
int j = i;
i++;
do
{
Console.WriteLine("Value of j: {0}", j);
j++;
Output:
Value of i: 0
Value of j: 0
Value of j: 1
Value of i: 1
Value of j: 1
Points to Remember :
C# - struct
We have learned class in the previous section. Class is a reference type. C# includes a value
type entity, which is called Structure. A structure is a value type that can contain
constructors, constants, fields, methods, properties, indexers, operators, events and nested
types. A structure can be defined using the struct keyword.
Example: Structure
public struct Discounts
{
public int Cloths { get; set; }
public int HomeDecor { get; set; }
public int Grocery { get; set; }
}
A struct can be initialized with or without the new keyword same as primitive variable or
an object. You can then assign values to the members of the structure as shown below.
saleDiscounts.Cloths = 10;
saleDiscounts.HomeDecor = 5;
saleDiscounts.Grocery = 2;
A struct is a value type so it is faster than a class object. Use struct whenever you want to
just store the data. Generally structs are good for game programming. However, it is easier
to transfer a class object than a struct. So do not use struct when you are passing data across
the wire or to other classes.
Example: Structure
struct Point
{
private int _x, _y;
public int x, y;
set
{
_x = value;
PointChanged(_x);
}
}
The above structure consists of different types of properties and events for the demo
purpose. It includes private fields _x, _y, public fields x and y, static fields X and Y, public
properties XPoint and YPoint, and PointChanged event. It also includes static and non-
static methods. Notice that we raise the PointChanged event whenever XPoint or YPoint
changes.
In the following code, we initialize the above Point struct with the new keyword as we
initialize the class and also handle the PointChanged event:
p.PointChanged += StructEventHandler;
p.XPoint = 123;
p.PrintPoints();
}
}
Output:
Inside Static Method
Point changed to 123
X: 123, y: 0
Please note that if you want to use properties, methods or events, you MUST initialize the
struct with the new keyword. The following will give a compile time error:
Example: structure
Point pto;
Points to Remember :
Further Reading
C# - enum
In C#, enum is a value type data type. The enum is used to declare a list of named integer
constants. It can be defined using the enum keyword directly inside a namespace, class, or
structure. The enum is used to give a name to each constant so that the constant integer can
be referred using its name.
Example: enum
enum WeekDays
{
Monday = 0,
Tuesday =1,
Wednesday = 2,
Thursday = 3,
Friday = 4,
Saturday =5,
Sunday = 6
}
Console.WriteLine(WeekDays.Friday);
Console.WriteLine((int)WeekDays.Friday);
Output:
Friday
4
By default, the first member of an enum has the value 0 and the value of each successive
enum member is increased by 1. For example, in the following enumeration, Monday is 0,
Tuesday is 1, Wednesday is 2 and so forth.
Example: enum
enum WeekDays
{
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
Console.WriteLine((int)WeekDays.Monday);
Console.WriteLine((int)WeekDays.Friday);
Output:
0
4
An explicit cast is necessary to convert from enum type to an integral type. For example, to
get the int value from an enum:
Example: enum
int dayNum = (int)WeekDays.Friday;
Console.WriteLine(dayNum);
Output:
4
A change in the value of the first enum member will automatically assign incremental
values to the other members sequentially. For example, changing the value of Monday to
10, will assign 11 to Tuesday, 12 to Wednesday, and so on:
Example: enum
enum WeekDays
{
Monday = 10,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
Sunday
}
Console.WriteLine((int)WeekDays.Monday);
Console.WriteLine((int)WeekDays.Friday);
Output:
10
14
The enum can includes named constants of numeric data type e.g. byte, sbyte, short, ushort,
int, uint, long, or ulong.
Enum is mainly used to make code more readable by giving related constants a meaningful
name. It also improves maintainability.
Enum methods:
Enum is an abstract class that includes static helper methods to work with enums.
Console.WriteLine(Enum.GetName(typeof(WeekDays), 4));
Console.WriteLine("Enum.TryParse():");
WeekDays wdEnum;
Enum.TryParse<WeekDays>("1", out wdEnum);
Console.WriteLine(wdEnum);
Output:
Friday
WeekDays constant names:
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Enum.TryParse():
Tuesday
Points to Remember :
C# - StringBuilder
A String is immutable, meaning String cannot be changed once created. For example, new
string "Hello World!!" will occupy a memory space on the heap. Now, by changing the
initial string "Hello World!!" to "Hello World!! from Tutorials Teacher" will create a new
string object on the memory heap instead of modifying the initial string at the same
memory address. This behaviour will hinder the performance if the same string changes
multiple times by replacing, appending, removing or inserting new strings in the initial
string.
Example: StringBuilder
StringBuilder sb = new StringBuilder();
//or
You can give an initial capacity of characters by passing an int value in the constructor. For
example, the following will allocate memory of 50 characters sequentially on the memory
heap. The memory allocation automatically expands once it reaches the capacity.
Example: StringBuilder
StringBuilder sb = new StringBuilder(50);
//or
StringBuilder.Replace(oldValue,
Replaces characters with new characters.
newValue)
Append()/AppendLine()
Example: Append()
StringBuilder sb = new StringBuilder("Hello ",50);
sb.Append("World!!");
sb.AppendLine("Hello C#!");
sb.AppendLine("This is new line.");
Console.WriteLine(sb);
Output:
Hello World!! Hello C#!.
This is new line.
Note : StringBuilder performs faster than string when concatenating multiple strings. Use
StringBuilder if you want to append more than three-four string. Appending two or three string is
more efficient than using StringBuilder.
AppendFormat()
Use AppendFormat method to format input string into specified format and then append it.
Example: AppendFormat()
StringBuilder amountMsg = new StringBuilder("Your total amount is ");
amountMsg.AppendFormat("{0:C} ", 25);
Console.WriteLine(amountMsg);
Output:
Your total amount is $ 25.00
Insert()
Example: Insert()
StringBuilder sb = new StringBuilder("Hello World!!",50);
sb.Insert(5," C#");
Console.WriteLine(sb);
Output:
Hello C# World!!
Remove()
The Remove() method removes the string at specified index with specified length.
Example: Remove()
StringBuilder sb = new StringBuilder("Hello World!!",50);
sb.Remove(6, 7);
Console.WriteLine(sb);
Output:
Hello
Replace()
The Replace() method replaces all occurance of a specified string with a specified
replacement string.
Example: Replace()
StringBuilder sb = new StringBuilder("Hello World!!",50);
sb.Replace("World", "C#");
Console.WriteLine(sb);
Output:
Hello C#!!
Indexer
You can use indexer with StringBuilder to get or set a character at specified index. The
following example uses indexer to get all the characters of StringBuilder using for loop.
ToString()
Example: ToString()
StringBuilder sb = new StringBuilder("Hello World!!");
Points to Remember :
1. StringBuilder is mutable.
2. StringBuilder performs faster than string when appending multiple string values.
3. Initialize StringBuilder as class e.g. StringBuilder sb = new StringBuilder()
4. Use StringBuilder when you need to append more than three or four strings.
5. Use Append() method to add or append strings with StringBuilder.
6. Use ToString() method to get the string from StringBuilder.
C# - Array
We have learned that a variable can hold only one literal value, for example int x = 1;.
Only one literal value can be assigned to a variable x. Suppose, you want to store 100
different values then it will be cumbersome to create 100 different variables. To overcome
this problem, C# introduced an array.
An array is a special type of data type which can store fixed number of values sequentially
using special syntax.
Array
Representation
As you can see in the above figure, index is a number starting from 0, which stores the
value. You can store a fixed number of values in an array. Array index will be increased by
1 sequentially till the maximum specified array size.
Array Declaration
An array can be declare using a type name followed by square brackets [].
An array can be declared and initialized at the same time using the new keyword. The
following example shows the way of initializing an array.
// defining array with size 5 and adding values at the same time
int[] intArray2 = new int[5]{1, 2, 3, 4, 5};
In the above example, the first statement declares & initializes int type array that can store
five int values. The size of the array is specified in square brackets. The second statement,
does the same thing, but it also assignes values to each indexes in curley brackets { }. The
third statement directly initializes an int array with the values without giving any size. Here,
size of an array will automatically be number of values.
Initialization without giving size is NOT valid. For example, the following example would
give compile time error.
Arrays can be initialized after declaration. It is not necessary to declare and initialize at the
same time using new keyword. Consider the following example.
As shown above, values can be assigned to an array at the time of initialization. However,
value can also be assigned to individual index randomly as shown below.
intArray[0] = 10;
intArray[1] = 20;
intArray[2] = 30;
intArray[3] = 40;
intArray[4] = 50;
In the same way, you can retrieve values at a particular index, as below:
intArray[0]; //returns 10
intArray[2]; //returns 30
Use a for loop to access the values from all the indexes of an array by using length property
of an array.
GetLowerBound(int
Returns the lowest index of the specified dimension.
dimension)
GetUpperBound(int
Returns the highest index of the specified dimension.
dimension)
Property Description
.NET provides an abstract class, Array, as a base class for all arrays. It provides static
methods for creating, manipulating, searching, and sorting arrays.
Array.Sort(intArr);
Array.Reverse(intArr);
You can create an instance of an Array that starts with index 1 (not default starting index 0)
using Array class as shown below:
array.SetValue(1, 1);
array.SetValue(2, 2);
array.SetValue(3, 3);
array.SetValue(4, 4);
array.SetValue(5, 5);
Points to Remember :
C# - Multi-dimensional Array
We have learned about single dimensional arrays in the previous section. C# also supports
multi-dimensional arrays. A multi-dimensional array is a two dimensional series like rows
and columns.
// or
int[,] intArray = { {1, 1}, {1, 2}, {1, 3} };
As you can see in the above example, multi dimensional array is initialized by giving size
of rows and columns. [3,2] specifies that array can include 3 rows and 2 columns.
The following figure shows a multi-dimensional array divided into rows and columns:
Multi-dimensional Array
The values of a multi-dimensional array can be accessed using two indexes. The first index
is for the row and the second index is for the column. Both the indexes start from zero.
intArray[0,0]; //Output: 1
intArray[0,1]; // 2
intArray[1,0]; // 3
intArray[1,1]; // 4
intArray[2,0]; // 5
intArray[2,1]; // 6
In the above example, intArray[2,1] returns 6. Here, 2 means the third row and 1 means the
second column (rows and columns starts with zero index).
C# - Jagged Array
A jagged array is an array of an array. Jagged arrays store arrays instead of any other data
type value directly.
A jagged array is initialized with two square brackets [][]. The first bracket specifies the
size of an array and the second bracket specifies the dimension of the array which is going
to be stored as values. (Remember, jagged array always store an array.)
The following jagged array stores a two single dimensional array as a value:
Console.WriteLine(intJaggedArray[0][0]); // 1
Console.WriteLine(intJaggedArray[0][2]); // 3
Console.WriteLine(intJaggedArray[1][1]); // 5
The following jagged array stores a multi-dimensional array as a value. Second bracket [,]
indicates multi-dimension.
Console.WriteLine(intJaggedArray[0][1,1]); // 4
Console.WriteLine(intJaggedArray[1][1,0]); // 5
Console.WriteLine(intJaggedArray[1][1,1]); // 6
Note:
Be careful while working with jagged arrays. It will throw an IndexOutOfRange exception if the
index does not exist.
C# Collection:
We have learned about an array in the previous section. C# also includes specialized classes
that hold many values or objects in a specific series, that are called 'collection'.
There are two types of collections available in C#: non-generic collections and generic
collections. We will learn about non-generic collections in this section.
Every collection class implements the IEnumerable interface so values from the collection
can be accessed using a foreach loop.
ArrayList stores objects of any type like an array. However, there is no need to
ArrayList
specify the size of the ArrayList like with an array as it grows automatically.
Stack stores the values in LIFO style (Last In First Out). It provides a Push() method
Stack to add a value and Pop() & Peek() methods to retrieve values. C# includes both,
generic and non-generic Stack.
Queue stores the values in FIFO style (First In First Out). It keeps the order in which
the values were added. It provides an Enqueue() method to add values and a
Queue
Dequeue() method to retrieve values from the collection. C# includes generic and
non-generic Queue.
Hashtable stores key and value pairs. It retrieves the values by comparing the hash
Hashtable
value of the keys.
C# - ArrayList
ArrayList is a non-generic type of collection in C#. It can contain elements of any data
types. It is similar to an array, except that it grows automatically as you add items in it.
Unlike an array, you don't need to specify the size of ArrayList.
Capacity Gets or sets the number of elements that the ArrayList can contain.
IsFixedSize Gets a value indicating whether the ArrayList has a fixed size.
Method Description
The AddRange() method can take any type of collection that implements the
ICollection interface e.g. List, ArrayList, SortedList, Queue, Stack, HashSet, Hashtable, etc.
Use the Add()method to add a single element or the AddRange() method to add multiple
elements from the other collections into an ArrayList. Here, the element means the literal
value of a primitive or non-primitive type.
You can also add items when you initialize it using object initializer syntax.
ArrayList elements can be accessed using indexer, in the same way as an array. However,
you need to cast it to the appropriate type or use the implicit type var keyword while
accessing it.
//Or
for(int i = 0 ; i< myArryList.Count; i++)
Console.WriteLine(myArryList[i]);
Output:
1
Two
3
4.5
Note:
Use the Insert() method to insert a single item at the specified index.
Example: Insert()
ArrayList myArryList = new ArrayList();
myArryList.Add(1);
myArryList.Add("Two");
myArryList.Add(3);
myArryList.Add(4.5);
Use the InsertRange() method to insert all the values from another collection into ArrayList
at the specfied index.
Example: InsertRange()
ArrayList arryList1 = new ArrayList();
arryList1.Add(100);
arryList1.Add(200);
arryList2.InsertRange(2, arryList1);
Example: Remove()
ArrayList arryList1 = new ArrayList();
arryList1.Add(100);
arryList1.Add(200);
arryList1.Add(300);
Use the RemoveAt() method to remove an element from the specified index location.
Example: RemoveAt()
ArrayList arryList1 = new ArrayList();
arryList1.Add(100);
arryList1.Add(200);
arryList1.Add(300);
Use the RemoveRange() method to remove multiple elements from the specified index till
the specified number of elements in the ArrayList.
Example: RemoveRange()
ArrayList arryList1 = new ArrayList();
arryList1.Add(100);
arryList1.Add(200);
arryList1.Add(300);
ArrayList Sorting
ArrayList includes Sort() and Reverse() method. Sort() method arranges elements in
ascending order. However, all the elements should have same data type so that it can
compare with default comparer otherwise it will throw runtime exception.
Reverse() method arranges elements in reverse order. Last element at zero index and so on.
Example: Sort(), Reverse()
ArrayList arryList1 = new ArrayList();
arryList1.Add(300);
arryList1.Add(200);
arryList1.Add(100);
arryList1.Add(500);
arryList1.Add(400);
Console.WriteLine("Original Order:");
arryList1.Reverse();
Console.WriteLine("Reverse Order:");
arryList1.Sort();
Console.WriteLine("Ascending Order:");
Example: Contains()
ArrayList myArryList = new ArrayList();
myArryList.Add(100);
myArryList.Add("Hello World");
myArryList.Add(300);
Console.WriteLine(myArryList.Contains(100));
Output:
True
Further Reading
Points to Remember :
C# - SortedList
The SortedList collection stores key-value pairs in the ascending order of key by default.
SortedList class implements IDictionary & ICollection interfaces, so elements can be
accessed both by key and index.
C# includes two types of SortedList, generic SortedList and non-generic SortedList. Here,
we will learn about non-generic SortedList.
Capacity Gets or sets the number of elements that the SortedList instance can store.
IsFixedSize Gets a value indicating whether the SortedList has a fixed size.
Item Gets or sets the element at the specified key in the SortedList.
Method Description
Key cannot be null but value can be null. Also, datatype of all keys must be same, so that it
can compare otherwise it will throw runtime exception.
SortedList collection sorts the elements everytime you add the elements. So if you debug
the above example, you will find keys in ascending order even if they are added randomly,
as below:
Please notice that sortedList2 sorts the key in alphabetical order for string key in the above
image.
SortedList key can be of any data type, but you cannot add keys of different data types in
the same SortedList. The following example will throw run time exception because we are
trying to add the second item with a string key:
sortedList.Add(3, "Three");
sortedList.Add("Four", "Four"); // Throw exception:
InvalidOperationException
sortedList.Add(1, "One");
sortedList.Add(8, "Five");
sortedList.Add(2, "Two");
Access SortedList
SortedList can be accessed by index or key. Unlike other collection, SortedList requires key
instead of index to access a value for that key.
Console.WriteLine(i);
Console.WriteLine(j);
Console.WriteLine(str);
Output:
1
2
Four
Note : Non-generic SortedList collection can contain key and value of any data type. So values
must be cast to the appropriate data type otherwise it will give compile-time error.
The foreach statement in C# can be use to access the SortedList collection. SortedList
element includes both key and value. so, type of element would be DictionaryEntry rather
than type of key or value.
The Contains() & ContainsKey() methods determine whether the specified key exists in the
SortedList collection or not.
The ContainsValue() method determines whether the specified value exists in the
SortedList or not.
Example: Contains
SortedList sortedList = new SortedList();
sortedList.Add(3, "Three");
sortedList.Add(2, "Two");
sortedList.Add(4, "Four");
sortedList.Add(1, "One");
sortedList.Add(8, "Five");
Visit MSDN for more information on the properties and methods of SortedList.
Points to Remember :
Stack allows null value and also duplicate values. It provides a Push() method to add a
value and Pop() or Peek() methods to retrieve values.
C# Stack Representation
Method Usage
Pop Removes and returns items from the top of the stack.
The Push() method adds values into the Stack. It allows value of any datatype.
Example: Push()
Stack myStack = new Stack();
myStack.Push("Hello!!");
myStack.Push(null);
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);
myStack.Push(5);
Accessing Stack Elements
You can retrieve stack elements by various ways. Use a foreach statement to iterate the
Stack collection and get all the elements in LIFO style.
Hello!!
Peek()
The Peek() method returns the last (top-most) value from the stack. Calling Peek() method
on empty stack will throw InvalidOperationException. So always check for elements in the
stack before retrieving elements using the Peek() method.
Example: Stack.Peek()
Stack myStack = new Stack();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);
myStack.Push(5);
Console.WriteLine(myStack.Peek());
Console.WriteLine(myStack.Peek());
Console.WriteLine(myStack.Peek());
Output:
5
5
5
Pop()
You can also retrieve the value using the Pop() method. The Pop() method removes and
returns the value that was added last to the Stack. The Pop() method call on an empty stack
will raise an InvalidOperationException. So always check for number of elements in stack
must be greater than 0 before calling Pop() method.
Contains()
The Contains() method checks whether the specified item exists in a Stack collection or
not. It returns true if it exists; otherwise it returns false.
The Clear() method removes all the values from the stack.
Example: Stack.Contains()
Stack myStack = new Stack();
myStack.Push(1);
myStack.Push(2);
myStack.Push(3);
myStack.Push(4);
myStack.Push(5);
Points to Remember :
1. Stack stores the values in LIFO (Last in First out) style. The element which is added last will
be the element to come out first.
2. Use the Push() method to add elements into Stack.
3. The Pop() method returns and removes elements from the top of the Stack. Calling the
Pop() method on the empty Stack will throw an exception.
4. The Peek() method always returns top most element in the Stack.
Visit MSDN for more information on Stack member properties and methods.
C# - Queue
C# includes a Queue collection class in the System.Collection namespace. Queue stores the
elements in FIFO style (First In First Out), exactly opposite of the Stack collection. It
contains the elements in the order they were added.
Queue collection allows multiple null and duplicate values. Use the Enqueue() method to
add values and the Dequeue() method to retrieve the values from the Queue.
Method Usage
Dequeue Removes and returns an item from the beginning of the queue.
Queue is a non-generic collection. So you can add elements of any datatype into a queue
using the Enqueue() method.
Example: Enqueue()
Queue queue = new Queue();
queue.Enqueue(3);
queue.Enqueue(2);
queue.Enqueue(1);
queue.Enqueue("Four");
Access Queue
Dequeue() method is used to retrieve the top most element in a queue collection. Dequeue()
removes and returns a first element from a queue because the queue stores elements in
FIFO order. Calling Dequeue() method on empty queue will throw InvalidOperation
exception. So always check that the total count of a queue is greater than zero before
calling the Dequeue() method on a queue.
Example: Dequeue()
Queue queue = new Queue();
queue.Enqueue(3);
queue.Enqueue(2);
queue.Enqueue(1);
queue.Enqueue("Four");
Peek()
The Peek() method always returns the first item from a queue collection without removing
it from the queue. Calling Peek() and Dequeue() methods on an empty queue collection will
throw a run time exception "InvalidOperationException".
Example: Peek()
Queue queue = new Queue();
queue.Enqueue(3);
queue.Enqueue(2);
queue.Enqueue(1);
queue.Enqueue("Four");
Console.WriteLine(queue.Peek());
Console.WriteLine(queue.Peek());
Console.WriteLine(queue.Peek());
Contains()
The Contains() method checks whether an item exists in a queue. It returns true if the
specified item exists; otherwise it returns false.
queue.Contains(2); // true
queue.Contains(100); //false
Clear()
Example: Clear()
Queue queue = new Queue();
queue.Enqueue(3);
queue.Enqueue(2);
queue.Enqueue(1);
queue.Enqueue("Four");
queue.Clear();
Points to Remember :
1. The Queue stores the values in FIFO (First in First out) style. The element which is added
first will come out First.
2. Use the Enqueue() method to add elements into Queue
3. The Dequeue() method returns and removes elements from the beginning of the Queue.
Calling the Dequeue() method on an empty queue will throw an exception.
4. The Peek() method always returns top most element.
C# - Hashtable
C# includes Hashtable collection in System.Collections namespace, which is similar to
generic Dictionary collection. The Hashtable collection stores key-value pairs. It optimizes
lookups by computing the hash code of each key and stores it in a different bucket
internally and then matches the hash code of the specified key at the time of accessing
values.
Item Gets or sets the value associated with the specified key.
Methods Usage
Add Adds an item with a key and value into the hashtable.
Remove Removes the item with the specified key from the hashtable.
The Add() method adds an item with a key and value into the Hashtable. Key and value can
be of any data type. Key cannot be null whereas value can be null.
Example: Add()
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
ht.Add(4, "Four");
ht.Add(5, null);
ht.Add("Fv", "Five");
ht.Add(8.5F, 8.5);
You can also assign key and value at the time of initialization using object initializer
syntax:
Example: Add()
Hashtable ht = new Hashtable()
{
{ 1, "One" },
{ 2, "Two" },
{ 3, "Three" },
{ 4, "Four" },
{ 5, null },
{ "Fv", "Five" },
{ 8.5F, 8.5 }
};
Example: Add()
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "one");
dict.Add(2, "two");
dict.Add(3, "three");
Note : Add() will throw an exception if you try to add a key that already exists in the Hashtable. So
always check the key using the Contains() or ContainsKey() method before adding a key-value pair
into the Hashtable.
Access Hashtable
You can retrive the value of an existing key from the Hashtable using indexer. Please note
that the hashtable indexer requires a key.
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
ht.Add(4, "Four");
ht.Add("Fv", "Five");
ht.Add(8.5F, 8.5F);
Console.WriteLine(strValue1);
Console.WriteLine(strValue2);
Console.WriteLine(fValue);
Output:
Two
Five
8.5
Note:
Hashtable is a non-generic collection so it can contains a key and a value of any data type. So
values must be cast to an appropriate data type otherwise it will give compile-time error.
Hashtable elements are key-value pairs stored in DictionaryEntry. So you cast each element
in Hashtable to DictionaryEntry. Use the foreach statement to iterate the Hashtable, as
shown below:
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
ht.Add(4, "Four");
ht.Add("Fv", "Five");
ht.Add(8.5F, 8.5);
Hashtable has a Keys and a Values property that contain all the keys and values
respectively. You can use these properties to get the keys and values.
Console.WriteLine("***All Values***");
The Remove() method removes the item with the specified key from the hashtable.
Example: Remove()
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
ht.Add(4, "Four");
ht.Add("Fv", "Five");
ht.Add(8.5F, 8.5);
Contains() and ContainsKey() check whether the specified key exists in the Hashtable
collection. ContainsValue() checks whether the specified value exists in the Hashtable.
Example: Clear()
Hashtable ht = new Hashtable();
ht.Add(1, "One");
ht.Add(2, "Two");
ht.Add(3, "Three");
ht.Add(4, "Four");
ht.Add("Fv", "Five");
ht.Add(8.5F, 8.5);
Points to Remember :
1. Hashtable stores key-value pairs of any datatype where the Key must be unique.
2. The Hashtable key cannot be null whereas the value can be null.
3. Hashtable retrieves an item by comparing the hashcode of keys. So it is slower in
performance than Dictionary collection.
4. Hashtable uses the default hashcode provider which is object.GetHashCode(). You can also
use a custom hashcode provider.
5. Use DictionaryEntry with foreach statement to iterate Hashtable.
Further Reading
Syntax:
Public <return type> this[<parameter type> index]
{
Get{
// return the value from the specified index
}
Set{
// set values at the specified index
}
}
The following example shows how to use indexer in the custom class.
Example: Indexer
class StringDataStore
{
return strArr[index];
}
set
{
if (index < 0 && index >= strArr.Length)
throw new IndexOutOfRangeException("Cannot store more
than 10 objects");
strArr[index] = value;
}
}
}
class Program
{
static void Main(string[] args)
{
StringDataStore strStore = new StringDataStore();
strStore[0] = "One";
strStore[1] = "Two";
strStore[2] = "Three";
strStore[3] = "Four";
The array operator [] is nothing but an indexer implemented in all the data type in C#.
For example, string[] is an indexer in the String class.
In the above example, StringDataStore class implements an indexer for its internal string
array. So now, object of StringDataStore can be used like an array to add or retrive string
data. We have used string array in the above example, you can also you any collection type
as per your requirement.
Override Indexer
You can override an indexer by having different index types. The following example shows
how an indexer can be of int type as well as string type.
Example: Indexer
class StringDataStore
{
public StringDataStore()
{
set
{
if (index < 0 && index >= strArr.Length)
throw new IndexOutOfRangeException("Cannot store more than 10
objects");
strArr[index] = value;
}
}
return null;
}
}
}
class Program
{
static void Main(string[] args)
{
StringDataStore strStore = new StringDataStore();
strStore[0] = "One";
strStore[1] = "Two";
strStore[2] = "Three";
strStore[3] = "Four";
Console.WriteLine(strStore["one"]);
Console.WriteLine(strStore["two"]);
Console.WriteLine(strStore["Three"]);
Console.WriteLine(strStore["FOUR"]);
}
}
Output:
One
Two
Three
Four
Insert Indexer Code snippet in VisualStudio
Vsual studio provides shortcut way to insert a code snippet for an indexer so that you don't
have to write entire syntax manually. To insert a snippet for an indexer in Visual Studio,
write idexer and press tab or do right click (or Ctrl + K,S) -> select "Insert Snippet.." ->
select "Visual C#.." -> select "indexer".
Indexer
snippet in Visual Studio
Points to Remember :
1. An indexer is same as property except that it defined with this keyword with square
bracket that takes paramter.
2. Indexer can be override by having different types of parameters.
3. Ref and out parameter with the indexer is not supported.
4. Indexer can be included as an interface member.
5. Use code snippet to insert indexer syntax automatically in the visual studio.
C# - Stream
C# includes following standard IO (Input/Output) classes to read/write from different
sources like a file, memory, network, isolated storage, etc.
The following classes inherits Stream class to provide functionality to Read/Write bytes
from a particular source:
FileStream reads or writes bytes from/to a physical file whether it is a .txt, .exe, .jpg or any
other file. FileStream is derived from the Stream class.
BinaryReader: BinaryReader is a helper class for reading primitive datatype from bytes.
The above image shows that FileStream reads bytes from a physical file and then
StreamReader reads strings by converting those bytes to strings. In the same way,
StreamWriter takes a string and converts it into bytes and writes to FileStream and then
FileStream writes the bytes to a physical file. So FileStream deals with bytes where as
StreamReader & StreamWriter deals with strings.
Points to Remember :
1. Stream is an abstract class for transfering bytes from different sources. It is base class for
all other class that reads\writes bytes to different sources.
2. FileStream class provides reading and writing functionality of bytes to physical file.
3. Reader & writer classes provides functionality to read bytes from Stream classes
(FileStream, MemoryStream etc) and converts bytes into appropriate encoding.
4. StreamReader provides a helper method to read string from FileStream by converting
bytes into strings. StreamWriter provides a helper method to write string to FileStream by
converting strings into bytes.
File is a static class that provides different functionalities like copy, create, move,
File delete, open for reading or /writing, encrypt or decrypt, check if a file exists, append
lines or text to a file’s content, get last access time, etc.
The FileInfo class provides the same functionality as a static File class. You have
FileInfo more control on how you do read/write operations on a file by writing code
manually for reading or writing bytes from a file.
Class Name Usage
Directory is a static class that provides functionality for creating, moving, deleting
Directory
and accessing subdirectories.
Path is a static class that provides functionality such as retrieving the extension of a
Path file, changing the extension of a file, retrieving the absolute physical path, and other
path related functionalities.
File
C# includes static File class to perform I/O operation on physical file system. The static
File class includes various utility method to interact with physical file of any type e.g.
binary, text etc.
Use this static File class to perform some quick operation on physical file. It is not
recommended to use File class for multiple operations on multiple files at the same time
due to performance reasons. Use FileInfo class in that scenario.
Appends lines to a file, and then closes the file. If the specified file does not
AppendAllLines exist, this method creates a file, writes the specified lines to the file, and then
closes the file.
Opens a file, appends the specified string to the file, and then closes the file. If
AppendAllText the file does not exist, this method creates a file, writes the specified string to
the file, then closes the file.
Copies an existing file to a new file. Overwriting a file of the same name is not
Copy
allowed.
Decrypts a file that was encrypted by the current account using the Encrypt
Decrypt
method.
Encrypt Encrypts a file so that only the account used to encrypt the file can decrypt it.
Method Usage
Gets a FileSecurity object that encapsulates the access control list (ACL) entries
GetAccessControl
for a specified file.
Moves a specified file to a new location, providing the option to specify a new
Move
file name.
Opens a binary file, reads the contents of the file into a byte array, and then
ReadAllBytes
closes the file.
ReadAllLines Opens a text file, reads all lines of the file, and then closes the file.
ReadAllText Opens a text file, reads all lines of the file, and then closes the file.
Replaces the contents of a specified file with the contents of another file,
Replace
deleting the original file, and creating a backup of the replaced file.
Creates a new file, writes the specified byte array to the file, and then closes
WriteAllBytes
the file. If the target file already exists, it is overwritten.
Creates a new file, writes a collection of strings to the file, and then closes the
WriteAllLines
file.
Creates a new file, writes the specified string to the file, and then closes the file.
WriteAllText
If the target file already exists, it is overwritten.
Use AppendAllLines() method to append multiple text lines to the specified file as shown
below.
//Opens DummyFile.txt and append lines. If file is not exists then create
and open.
File.AppendAllLines(@"C:\DummyFile.txt",
dummyLines.Split(Environment.NewLine.ToCharArray()).ToList<string>());
Append String
Use File.AppendAllText() method to append string to a file in single line of code as shown
below.
Use File.WriteAllText() method to write texts to the file. Please note that it will not append
text but overwrite existing texts.
The following example shows how to perform different operations using static File class.
//Open file and returns FileStream for reading bytes from the file
FileStream fs = File.Open(@"D:\DummyFile.txt", FileMode.OpenOrCreate);
//Open file and return StreamReader for reading string from the file
StreamReader sr = File.OpenText(@"D:\DummyFile.txt");
//Delete file
File.Delete(@"C:\DummyFile.txt");
Thus, it is easy to work with physical file using static File class. However, if you want more
flexibility then use FileInfo class. The same way, use static Directory class to work with
physical directories.
Visit MSDN to know all the methods of the static File class.
Points to Remember :
1. File is a static class to read\write from physical file with less coding.
2. Static File class provides functionalities such as create, read\write, copy, move, delete and
others for physical files.
3. Static Directory class provides functionalities such as create, copy, move, delete etc for
physical directories with less coding.
4. FileInfo and DirectoryInfo class provides same functionality as static File and Directory
class.
C# - FileInfo
You have learned how to perform different tasks on physical files using static File class in
the previous section. Here, we will use FileInfo class to perform read/write operation on
physical files.
The FileInfo class provides the same functionality as the static File class but you have more
control on read/write operations on files by writing code manually for reading or writing
bytes from a file.
Extension Gets the string representing the extension part of the file.
IsReadOnly Gets or sets a value that determines if the current file is read only.
LastAccessTime Gets or sets the time the current file or directory was last accessed
LastWriteTime Gets or sets the time when the current file or directory was last written to
Method Usage
Property Usage
Encrypts a file so that only the account used to encrypt the file
Encrypt
can decrypt it.
The following example shows how to read bytes from a file manually and then convert
them to a string using UTF8 encoding:
//define counter to check how much butes to read. Decrease the counter as
you read each byte
int numBytesToRead = (int)fileBytes.Length;
if (n == 0)
break;
numBytesRead += n;
numBytesToRead -= n;
}
//Once you read all the bytes from FileStream, you can convert it into
string using UTF8 encoding
string filestring = Encoding.UTF8.GetString(fileBytes);
As you have seen in the above code, you have to write lot of code for reading/writing a
string from a FileSream. The same read/write operation can be done easily using
StreamReader and StreamWriter.
The following example shows how StreamReader makes it easy to read strings from a file:
The following example shows how StreamWriter makes it easy to write strings to a File:
Read and Write operations are not possible on the same FileStream object simultaneously.
If you are already reading from a file, create a separate FileStream object to write to the
same file, as shown below:
Further Reading
Exception in C#
An application may encounter an error during the execution. When an error occurs, either
CLR or program code throws an exception which contains necessary information about the
error. There are two types of exceptions in .Net, exceptions generated by the executing
program and exceptions generated by the CLR.
C# includes built-in classes for every possible exception. All the exception classes are
directly or indirectly derived from the Exception class. There are two main classes for
exceptions - SystemException and ApplicationException. SystemException is a base class
for all CLR generated errors whereas ApplicationException serves as a base class for all
application related exceptions, which you want to raise on business rule violation.
As you can see in the above figure, SystemException class is a base class for all the
exception that can occurs during execution of the program. No other class derives
ApplicationException class by default, because you as a programmer need to derive this
class to create your own exeception classes as per the business rules.
The following figure shows how NullReferenceException is thrown in Visual Studio debug
mode, when it accesses a property of a null object at runtime:
NullReferenceException
Important Exception Classes:
Exception Description
Every exception class in .Net is derived from the base Exception class. It includes the
following important properties using which you can use to get information about the
exception when you handle the exception.
Property Description
InnerException Provides information about the series of exceptions that might have occurred.
HelpLink This property can hold the help URL for a particular exception.
TargetSite Provides the name of the method where this exception was thrown.
When an error occurs, either application code or the default handler handles the exception.
Learn how to handle the excetion in the next section.
Points to Remember :
Exception Handling in C#
We have seen in the previous section that an exception is thrown by the CLR or program
code if there is an error in the program. These exceptions need to be handle to prevent
crashing of program. C# provides built-in support to handle the exception using try, catch
& finally block.
Syntax:
try
{
// code that may raise exceptions
}
catch(Exception ex)
{
// handle exception
}
finally
{
// final cleanup code
}
As per the above syntax, put the code in the try block that may raise an exception followed
by a catch or finally block. Keep variable declarations out of the try block so that they can
be accessed in the catch and finally blocks.
Let's see how to use try & catch block to handle the exception. Consider the following code
which can raise an exception.
IList<String> studentList =
FindAllStudentFromDatabase(studentName);
Console.ReadKey();
}
return studentList;
}
}
In the above example, it display total number of students with the same name. Assume that
FindAllStudentFromDatabase() method gets student list with the same name from the
database.
The above example will work fine if at least one student exists for the specified name,
otherwise it will raise NullReferenceException. We don't want to show exception message
to the user and stop the execution. So, we need to handle exception using try catch block as
shown below.
try
{
IList<String> studentList =
FindAllStudentFromDatabase(studentName);
Console.ReadKey();
}
return studentList;
}
}
As you can see in the above example, studentList.Count() can raise an exception if
studentList is null. So wrap this code into try block. The try block simple tells the
compiler to monitor the code for an exception. Exception raised within try block must be
handled using catch block.
Note:
try block must be followed by catch or finally or both blocks. The try block without a catch or
finally block will give a compile time error.
Catch block:
Exception raised within try block can be handled using the catch block as shown in the
above example. Code in the catch block will only execute when an exception occurs.
A multiple catch block can also be specified with a different exception type is called
exception filters. A multiple catch block is useful when you want to handle different
exceptions in different ways.
try
{
int num1 = int.Parse(Console.ReadLine());
int num2 = int.Parse(Console.ReadLine());
Console.ReadKey();
}
In the above example, we have specified a multiple catch block with different exception
types, so that we can display the appropriate message to the user, depending upon the error
and so the user does not repeat the same mistake again.
Note:
A multiple catch block with the same exception type is not allowed. It will give a compile time
error.
Parameterless catch block and a catch block with an Exception parameter are not allowed in
the same try-catch statements, because they both do the same thing.
Also, parameterless catch block catch{ } or general catch block catch(Exception ex)
{ } must be the last block. The compiler will give an error if you have other catch blocks
after a catch{ } or catch(Exception ex) block.
The finally block must come after a try or catch block. The finally block will always be
executed whether or not an exception is thrown. The finally block is generally used for
cleaning-up code e.g. for disposing an unmanaged objects etc.
try
{
int result = 5/zero; // this will throw an exception
}
catch(Exception ex)
{
Console.WriteLine("Inside catch block. Exception: {0}",
ex.Message );
}
finally
{
Console.WriteLine("Inside finally block.");
}
}
Output:
Inside catch block. Exception: Attempted to divide by zero.
Inside finally
Note:
Multiple finally blocks are not allowed. Also, the finally block cannot have the return, continue, or
break keywords. It doesn't allow control to leave the finally block.
Nested try-catch
C# allows nested try catch blocks. In the nested try catch block, an exception will be caught
in the catch block that follows the try block where an exception occurred.
try
{
try
{
std.StudentName = "";
}
catch
{
Console.WriteLine("Inner catch");
}
}
catch
{
Console.WriteLine("Outer catch");
}
}
Output:
Inner catch
If there isn't any inner catch block with appropriate exception type, then exception will flow
to the outer catch block until it finds the appropriate exception filter. Consider the
following example.
try
{
try
{
// following throws NullReferenceException
std.StudentName = "";
}
catch (InvalidOperationException innerEx)
{
Console.WriteLine("Inner catch");
}
}
catch
{
Console.WriteLine("Outer catch");
}
}
Output:
Outer catch
Points to Remember :
1. Use the try, catch and finally blocks to handle exceptions in C#.
2. The try block must be followed by a catch or finally block or both.
3. A multiple catch block is allowed with different exception filters. General catch{..} block
must come last.
4. catch{..} and catch(Exception ex){ } both cannot be used.
5. The finally block must come after the try or catch block.
6. The finally block will always execute irrespective of whether an exception occured or not.
7. The finally block is appropriate place for disposing objects.
8. The finally block cannot have a return or break because it isn't allow to leave the control.
9. Nested try-catch blocks are allowed in C#.
10. An Exception will be catched in the inner catch block if appropriate filter found, otherwise
will be catched by outer catch block.
C# - throw keyword
We have seen in the previous section how to handle exceptions which are automatically
raised by CLR. Here, we will see how to raise an exception manually.
An exception can be raised manually by using the throw keyword. Any type of exceptions
which is derived from Exception class can be raised using the throw keyword.
try
{
PrintStudentName(std);
}
catch(Exception ex)
{
Console.WriteLine(ex.Message );
}
Console.ReadKey();
}
Console.WriteLine(std.StudentName);
}
Output:
Student object is null.
Please notice that throw creates an object of any valid exception type using the new
keyword. The throw keyword cannot be used with any other type which does not derive
from the Exception class.
The .Net framework includes ApplicationException class since .Net v1.0. It was designed
to use as a base class for the custom exception class. However, Microsoft now recommends
Exception class to create a custom exception class.
Example: ApplicationException
class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
}
[Serializable]
class InvalidStudentNameException : Exception
{
public InvalidStudentNameException()
{
Now, you can raise InvalidStudentNameException in your program whenever the name
contains special characters or numbers. Use the throw keyword to raise an exception.
try
{
newStudent = new Student();
newStudent.StudentName = "James007";
ValidateStudent(newStudent);
}
catch(InvalidStudentNameException ex)
{
Console.WriteLine(ex.Message );
}
Console.ReadKey();
}
if (!regex.IsMatch(std.StudentName))
throw new InvalidStudentNameException(std.StudentName);
}
}
Output:
Invalid Student Name: James000
Thus, you can create custom exception classes to differentiate from system exceptions.
C# - Delegate
A function can have one or more parameters of different data types, but what if you want to
pass a function itself as a parameter? How does C# handle the callback functions or event
handler? The answer is - delegate.
A delegate is like a pointer to a function. It is a reference type data type and it holds the
reference of a method. All the delegates are implicitly derived from System.Delegate
class.
Delegate Syntax:
<access modifier> delegate <return type> <delegate_name>(<parameters>)
Example: C# delegate
class Program
{
// declare delegate
public delegate void Print(int value);
printDel(100000);
printDel(200);
printDel(10000);
printDel(200);
}
In the above example, we have declared Print delegate that accepts int type parameter and
returns void. In the Main() method, a variable of Print type is declared and assigned a
PrintNumber method name. Now, invoking Print delegate will in-turn invoke PrintNumber
method. In the same way, if the Print delegate variable is assigned to the PrintMoney
method, then it will invoke the PrintMoney method.
Invoking Delegate
The delegate can be invoked like a method because it is a reference to a method. Invoking a
delegate will in-turn invoke a method which id refered to. The delegate can be invoked by
two ways: using () operator or using the Invoke() method of delegate as shown below.
//or
printDel (10000);
Number: 200
Number: 200
A method can have a parameter of a delegate type and can invoke the delegate parameter.
The following example shows how to use PrintHelper method that includes delegate type
parameter.
Multicast Delegate
The delegate can points to multiple methods. A delegate that points multiple methods is
called a multicast delegate. The "+" operator adds a function to the delegate object and the
"-" operator removes an existing function from a delegate object.
As you can see in the above example, Print delegates becomes a multicast delegate because
it points to three methods - PrintNumber, PrintMoney & PrintHexadecimal. So invoking
printDel will invoke all the methods sequentially.
Delegate is also used with Event, Anonymous method, Func delegate, Action delegate.
Points to Remember :
C# - Event
In general terms, an event is something special that is going to happen. For example,
Microsoft launches events for developers, to make them aware about the features of new or
existing products. Microsoft notifies the developers about the event by email or other
advertisement options. So in this case, Microsoft is a publisher who launches (raises) an
event and notifies the developers about it and developers are the subscribers of the event
and attend (handle) the event.
Events in C# follow a similar concept. An event has a publisher, subscriber, notification
and a handler. Generally, UI controls use events extensively. For example, the button
control in a Windows form has multiple events such as click, mouseover, etc. A custom
class can also have an event to notify other subscriber classes about something that has
happened or is going to happen. Let's see how you can define an event and notify other
classes that have event handlers.
Example: Delegate
public delegate void someEvent();
Now, to declare an event, use the event keyword before declaring a variable of delegate
type, as below:
Now, let's see a practical example of an event. Consider the following PrintHelper class
that prints integers in different formats like number, money, decimal, temperature and
hexadecimal. It includes a beforePrintEvent to notify the subscriber of the BeforePrint
event before it going to print the number.
Example: Event
public class PrintHelper
{
// declare delegate
public delegate void BeforePrint();
public PrintHelper()
{
The delegate can also be invoked using the Invoke() method, e.g.,
beforePrintEvent.Invoke().
PrintHelper is a publisher class that publishes the beforePrint event. Notice that in each
print method, it first checks to see if beforePrintEvent is not null and then it calls
beforePrintEvent(). beforePrintEvent is an object of type BeforPrint delegate, so it would
be null if no class is subscribed to the event and that is why it is necessary to check for null
before calling a delegate.
Now, let's create a subscriber. Consider the following simple Number class for example.
All the subscribers must provided a handler function, which is going to be called when a
publisher raises an event. In the above example, the Number class creates an instance of
PrintHelper and subscribes to the beforePrintEvent with the "+=" operator and gives the
name of the function which will handle the event (it will be get called when publish fires an
event). printHelper_beforePrintEvent is the event handler that has the same signature as the
BeforePrint delegate in the PrintHelper class.
Example: Event
Number myNumber = new Number(100000);
myNumber.PrintMoney();
myNumber.PrintNumber();
Output:
BeforePrintEventHandler: PrintHelper is going to print value
Money: $ 1,00,000.00
BeforePrintEventHandler: PrintHelper is going to print value
Number: 1,00,000
Event
publisher-Subscriber
Event Arguments
Events can also pass data as an argument to their subscribed handler. An event passes
arguments to the handler as per the delegate signature. In the following example,
PrintHelper declares the BeforePrint delegate that accepts a string argument. So now, you
can pass a string when you raise an event from PrintNumber or any other Print method.
Now, the subscriber class should have an event handler that has a string parameter.
Example: Event
class Number
{
private PrintHelper _printHelper;
}
Output:
BeforePrintEvent fires from PrintMoney.
Money: $ 1,00,000.00
BeforePrintEvent fires from PrintNumber.
Number: 1,00,000
Further Reading
Points to Remember :
Generics in C#
Generics introduced in C# 2.0. Generics allow you to define a class with placeholders for
the type of its fields, methods, parameters, etc. Generics replace these placeholders with
some specific type at compile time.
A generic class can be defined using angle brackets <>. For example, the following is a
simple generic class with a generic member variable, generic method and property.
return genericMemberVariable;
}
As you can see in the above code, MyGenericClass is defined with <T>. <> indicates that
MyGenericClass is generic and the underlying type would be defined later, for now
consider it as T. You can take any character or word instead of T.
Now, the compiler assigns the type based on the type passed by the caller when
instantiating a class. For example, the following code uses the int data type:
The following figure illustrates how the compiler will replace T with int in
MyGenericClass.
C# Generic Class
return genericMemberVariable;
}
When deriving from a generic base class, you must provide a type argument instead of the
base-class's generic type parameter as shown below.
Example: Generic
class MyDerivedClass : MyGenericClass<string>
{
//implementation
}
If you want the derived class to be generic then no need to specify type for the generic base
class.
If the generic base class has constraints, the derived class must use the same constraints.
Example: Constraints
class MyGenericClass<T> where T: class
{
// Implementation
}
As you have already learned in the previous section, the delegate defines the signature of
the method which it can invoke. A generic delegate can be defined the same way as
delegate but with generic type.
For example, consider the following generic delegate that takes two generic parameters.
Console.WriteLine(sum(10, 20));
Console.WriteLine(conct("Hello","World!!"));
}
In the above example, add delegate is generic. In the Main() method, it has defined add
delegate of int type variable sum. So it can point to the AddNumber() method which has int
type parameters. Another variable of add delegate uses string type, so it can point to the
Concate method. In this way, you can use generic delegates for different methods of
different types of parameters.
Note:
A generic delegate can point to methods with different parameter types. However, the number of
parameters should be the same.
Advantages of Generics
Further Reading
Points to Remember :
return genericMemberVariable;
}
In the above example, the generic class MyGenericClass defines a placeholder for the type,
but the placeholder is like a black box, because MyGenericClass doesn't know anything
about the placeholder type, whether it is primitive or non-primitive type, or an interface or
custom class etc.
C# includes Constraints to specify which type of placeholder type with the generic class is
allowed. It will give a compile time error if you try to instantiate a generic class using a
placeholder type that is not allowed by a constraints. For example, if the generic constraints
specifies that only reference type can be used with the generic class then you cannot use
value type to create an object of generic type.
Constraints can be applied using the where keyword. In the following example,
MyGenericClass specifies the constraints that only a reference type can be used with
MyGenericClass. This means that only a class can be a placeholder type not the primitive
types, struct etc.
return genericMemberVariable;
}
public T genericProperty { get; set; }
}
So now, you cannot use int as a placeholder type. The following would give a compile time
error.
Constraint Description
Type supplied for T must be or derive from the argument supplied for
where T: U
U.
Multiple constraints:
Multiple constraints:
class MyGenericClass<T, U> where T: class where U:struct
{
...
}
Constraint on Generic Methods
Method constraint:
class MyGenericClass<T> where T: class
{
public T genericMethod<U>(T genericParameter, U anotherGenericType)
where U: struct
{
Console.WriteLine("Generic Parameter of type {0}, value {1}",
typeof(T).ToString(),genericParameter);
Console.WriteLine("Return value of type {0}, value {1}",
typeof(T).ToString(), genericMemberVariable);
return genericMemberVariable;
}
}
Points to Remember :
C# - Generic Collection
You have learned about the collection in the previous section, e.g. ArrayList, BitArray,
SortedList, Queue, Stack and Hashtable. These types of collections can store any type of
items. For example, ArrayList can store items of different data types:
arList.Add(1);
arList.Add("Two");
arList.Add(true);
arList.Add(100.45);
arList.Add(DateTime.Now);
The limitation of these collections is that while retrieving items, you need to cast into the
appropriate data type, otherwise the program will throw a runtime exception. It also affects
on performance, because of boxing and unboxing.
SortedList stores key and value pairs. It automatically adds the elements
SortedList<TKey,TValue>
in ascending order of key by default.
Queue<T> stores the values in FIFO style (First In First Out). It keeps the
order in which the values were added. It provides an Enqueue() method
Queue<T>
to add values and a Dequeue() method to retrieve values from the
collection.
Stack<T> stores the values as LIFO (Last In First Out). It provides a Push()
Stack<T>
method to add a value and Pop() & Peek() methods to retrieve values.
A generic collection gets all the benefit of generics. It doesn't need to do boxing and
unboxing while storing or retrieving items and so performance is improved.
C# - Generic List<T>
You have already learned about ArrayList in the previous section. An ArrayList resizes
automatically as it grows. The List<T> collection is the same as an ArrayList except that
List<T> is a generic collection whereas ArrayList is a non-generic collection.
//Or
In the above example, the first statement uses List type variable, whereas the second
statement uses IList type variable to initialize List. List<T> is a concreate implementation
of IList<T> interface. In the object-oriented programming, it is advisable to program to
interface rather than concreate class. So use IList<T> type variable to create an object of
List<T>.
List<T> includes more helper methods than IList<T> interface. The table shown below
lists important properties and methods of List<T>, which are initialized using a List<T>:
Property Usage
Method Usage
Find Finds the first element based on the specified predicate function.
Removes all the elements that match with the supplied predicate
RemoveRange
function.
Use the Add() method to add an element into a List collection. The following example adds
int value into a List<T> of int type.
You can also add elements at the time of initialization using object initializer syntax as
below:
//Or
AddRange()
The AddRange() method adds all the elements from another collection.
Example: AddRange
IList<int> intList1 = new List<int>();
intList1.Add(10);
intList1.Add(20);
intList1.Add(30);
intList1.Add(40);
intList2.AddRange(intList1);
Note : The AddRange() method will only be applicable if you initialized with a List<T> variable.
IList<T> doesn't include the AddRange() method.
Accessing List
If you have initialized the List<T> with an IList<T> interface then use seperate foreach
statement with implicitly typed variable:
Access individual items by using an indexer (i.e., passing an index in square brackets):
Use the Count property to get the total number of elements in the List.
The Insert() method inserts an element into a List<T> collection at the specified index.
The Remove() and RemoveAt() methods remove items from a List<T> collection.
TrueForAll() is a method of the List<T> class. It returns true if the specified condition turns
out to be true, otherwise false. Here, the condition can be specified as a predicate type
deligate or lambda expression.
Example: TrueForAll()
List<int> intList = new List<int>(){ 10, 20, 30, 40 };
Example: TrueForAll()
static bool isPositiveInt(int i)
{
return i > 0;
}
Visit MSDN to for more information on the methods & properties of IList<T> or List<T>.
Points to Remember :
C# - Generic SortedList
A generic SortedList SortedList<TKey,TValue> represents a collection of key-value pairs
that are sorted by key based on associated IComparer<T> A SortedList collection stores
key and value pairs in ascending order of key by default. Generic SortedList implements
IDictionary<TKey,TValue> & ICollection<KeyValuePair<TKey,TValue>> interfaces
so elements can be access by key and index both.
C# includes two type of SortedList, generic SortedList and non-generic SortedList. Generic
SortedList denotes with angel bracket: SortedList<TKey,TValue> where TKey is for type
of key and TValue is for type of value. Non-generic type do not specify the type of key and
values.
Internally, SortedList maintains a two object[] array, one for keys and another for values.
So when you add key-value pair, it does binary search using key to find an appropriate
index to store a key and value in respective arrays. It also re-arranges the elements when
you remove the elements from it.
You can initialize generic SortedList by specifying type for key and value as shown below.
In the above example, mySortedList will store key of int type and value (element) of string
type.
Capacity Gets or sets the number of elements that the SortedList<TKey,TValue> can store.
Item Gets or sets the element with the specified key in the SortedList<TKey,TValue>.
Method Description
Returns true and assigns the value with specified key, if key does not exists then
TryGetValue
return false.
Use the Add() method to add key value pairs into a SortedList. The key cannot be null, but
the value can be null. Also, the datatype of key and value must be same as specified,
otherwise it will give compile time error.
The following example shows how to add key-value pair in the generic SortedList
collection.
As you can see in the above image, sortedList1 stores key-value pairs in ascending order of
key and sortedList2 stores items in alphabetical order of key even if they are not added in
that ordered. sortedList3 includes nullable int so that it includes null as a value.
The SortedList can be accessed by the index or key. Unlike other collection types, Indexer
of SortedList requires key and returns value for that key. However, please make sure that
key exists in the SortedList, otherwise it will throw KeyNotFoundException.
Console.WriteLine(sortedList2["one"]);
Console.WriteLine(sortedList2["two"]);
Console.WriteLine(sortedList2["three"]);
Keys and Values indexers can use the access key and value of SortedList using for loop as
shown below:
The foreach statement in C# can be used to access the SortedList collection. SortedList
element includes both key and value pair. so, the type of element would be KeyValuePair
structure rather than type of key or value.
Accessing key
If you are not sure that particular key exists or not than use TryGetValue method to retrieve
the value of specified key. If key doesn't exists than it will return false instead of throwing
exception.
Example: TryGetValue
SortedList<string,int> sortedList2 = new SortedList<string,int>();
sortedList2.Add("one", 1);
sortedList2.Add("two", 2);
sortedList2.Add("three", 3);
sortedList2.Add("four", 4);
int val;
if (sortedList2.TryGetValue("ten",out val))
Console.WriteLine("value: {0}", val);
else
Console.WriteLine("Key is not valid.");
if (sortedList2.TryGetValue("one",out val))
Console.WriteLine("value: {0}", val);
Output:
Key is not valid.
value: 1
Use the Remove(key) and RemoveAt(index) methods to remove values from a SortedList.
The ContainsKey() checks whether the specified key exists in the SortedList or not.
The ContainsValue() method determines whether the specified value exists in the
SortedList or not.
Example: Contain()
SortedList<string,int> sortedList = new SortedList<string,int>();
sortedList.Add("one", 1);
sortedList.Add("two", 2);
sortedList.Add("three", 3);
sortedList.Add("four", 4);
sortedList.Add("five", 5);
You can use LINQ query syntax or method syntax to access SortedList collection using
different criterias.
Points to Remember :
Further Reading
C# - Dictionary
Dictionary in C# is same as English dictionary. English dictionary is a collection of words
and their definitions, often listed alphabetically in one or more specific languages. In the
same way, the Dictionary in C# is a collection of Keys and Values, where key is like word
and value is like definition.
Dictionary Initialization
//or
In the above example, we have specified types of key and value while declaring a
dictionary object. An int is a type of key and string is a type of value that will be stored into
a dictionary object named dict. You can use any valid C# data type for keys and values.
It is recommended to program to the interface rather than to the class. So, use
IDictionary<TKey, TValue> type variable to initialize a dictionary object.
Note:
Dictionary cannot include duplicate or null keys, where as values can be duplicated or set as null.
Keys must be unique otherwise it will throw a runtime exception.
Item Gets or sets the element with the specified key in the Dictionary<TKey,TValue>.
Method Description
Remove Removes the first occurance of specified item from the Dictionary<TKey, TValue>.
Returns true and assigns the value with specified key, if key does not exists then
TryGetValue
return false.
Check whether a dictionary already stores specified key before adding a key-value pair.
The IDictionary type instance has one more overload for the Add() method. It accepts a
KeyValuePair<TKey, TValue> struct as a parameter.
It can also be initialized using collecton initializer syntax with keys and values as shown
below.
Dictionary elements can be accessed by many ways e.g. foreach, for loop or indexer.
Use foreach or for loop to iterate access all the elements of dictionary. The dictionary stores
key-value pairs. So you can use a KeyValuePair<TKey, TValue> type or an implicitly
typed variable var in foreach loop as shown below.
Use for loop to access all the elements. Use Count property of dictionary to get the total
number of elements in the dictionary.
dict[ dict.Keys.ElementAt(i)]);
}
Output:
Key: 1, Value: One
Key: 2, Value: Two
Key: 3, Value: Three
Dictionary can be used like an array to access its individual elements. Specify key (not
index) to get a value from a dictionary using indexer like an array.
Note:
Indexer takes the key as a parameter. If the specified key does not exist then a
KeyNotFoundException will be thrown.
If you are not sure about the key then use the TryGetValue() method. The TryGetValue()
method will return false if it could not found keys instead of throwing an exception.
Example: TryGetValue()
Dictionary<int, string> dict = new Dictionary<int, string>()
{
{1,"One"},
{2, "Two"},
{3,"Three"}
};
string result;
Use the Contains() method to check whether a specified Key and Value pair exists in the
dictionary or not.
class StudentDictionaryComparer :
IEqualityComparer<KeyValuePair<int,Student>>
{
public bool Equals(KeyValuePair<int, Student> x, KeyValuePair<int,
Student> y)
{
if (x.Key == y.Key && (x.Value.StudentID == y.Value.StudentID) &&
(x.Value.StudentName == y.Value.StudentName))
return true;
return false;
}
class Program
{
static void Main(string[] args)
{
IDictionary<int, Student> studentDict = new Dictionary<int,
Student>()
{
{ 1, new Student(){ StudentID =1, StudentName =
"Bill"}},
{ 2, new Student(){ StudentID =2, StudentName =
"Steve"}},
{ 3, new Student(){ StudentID =3, StudentName =
"Ram"}}
};
Console.WriteLine(result);
}
}
Output:
true
Use the Remove() method to remove an existing item from the dictionary. Remove() has
two overloads, one overload method accepts a key and the other overload method accepts a
KeyValuePair<> as a parameter.
Remove() signature:
Both Key and Value must match to remove an item. The item will not be removed if both
are not matched. For example, the following example will not remove any item:
Points to Remember :
C# - Partial Class
Each class in C# resides in a separate physical file with a .cs extension. C# provides the
ability to have a single class implementation in multiple .cs files using the partial modifier
keyword. The partial modifier can be applied to a class, method, interface or structure.
For example, the following MyPartialClass splits into two files, PartialClassFile1.cs and
PartialClassFile2.cs:
Example: PartialClassFile1.cs
public partial class MyPartialClass
{
public MyPartialClass()
{
}
All the partial class definitions must be in the same assembly and namespace.
All the parts must have the same accessibility like public or private, etc.
If any part is declared abstract, sealed or base type then the whole class is declared of the
same type.
Different parts can have different base types and so the final class will inherit all the base
types.
The Partial modifier can only appear immediately before the keywords class, struct,
or interface.
Nested partial types are allowed.
Multiple developers can work simultaneously with a single class in separate files.
When working with automatically generated source, code can be added to the class
without having to recreate the source file. For example, Visual Studio separates HTML
code for the UI and server side code into two separate files: .aspx and .cs files.
Partial Methods
A partial class or struct may contain partial methods. A partial method must be declared in
one of the partial classes. A partial method may or may not have an implementation. If the
partial method doesn't have an implementation in any part then the compiler will not
generate that method in the final class. For example, consider the following partial method
with a partial keyword:
Example: PartialClassFile1.cs:
public partial class MyPartialClass
{
partial void PartialMethod(int val);
public MyPartialClass()
{
The partial method declaration must began with the partial modifier.
The partial method can have a ref but not an out parameter.
Partial methods are implicitly private methods.
Partial methods can be static methods.
Partial methods can be generic.
Partial Method
The compiler combines the two partial classes into a single final class:
Partial
Class
Points to Remember :
1. Use the partial keyword to split interface, class, method or structure into multiple .cs files.
2. The partial method must be declared before implementation.
3. All the partial class, method , interface or structs must have the same access modifiers.
C# - Static
C# includes static keyword just like other programming languages such as C++, Java,
etc. The static keyword can be applied on classes, variables, methods, properties,
operators, events and constructors. However, it cannot be used with indexers, destructors or
types other than classes.
The static modifier makes an item non-instantiable, it means the static item cannot be
instantiated. If the static modifier is applied to a class then that class cannot be instantiated
using the new keyword. If the static modifier is applied to a variable, method or property of
class then they can be accessed without creating an object of the class, just use
className.propertyName, className.methodName.
class Program
{
static void Main(string[] args)
{
Console.WriteLine(MyStaticClass.myStaticVariable);
MyStaticClass.MyStaticMethod();
MyStaticClass.MyStaticProperty = 100;
Console.WriteLine(MyStaticClass.MyStaticProperty);
}
}
Output:
0
This is a static method.
100
In the above example, MyStaticClass is a static class with static variable, method and
property. All the static members can be access using className without creating an object
of a class e.g. MyStaticClass.MyStaticMethod().
It is also possible to have static members in non-static classes just like a normal class. You
can instantiate non static classes using the new keyword as usual. However, the instance
variable can only access the non-static methods and variables, it cannot access the static
methods and variables.
For example, consider the following myNonStaticClass with mix of static and non-static
methods:
In the above example, MyNonStaticClass can be instantiated and access the non-static
members. However, you cannot access static members. The following figure shows the
debug view.
Non-Static method
C# Static Constructor
A static or non-static class can have a static constructor without any access modifiers like
public, private, protected, etc.
A static constructor in a non-static class runs only once when the class is instantiated for the
first time.
A static constructor in a static class runs only once when any of its static members accessed
for the first time.
class Program
{
MyStaticClass.myStaticVariable = 100;
MyStaticClass.MyStaticProperty = 200;
MyStaticClass.myStaticVariable = 300;
MyStaticClass.MyStaticProperty = 400;
}
}
Output:
Inside static constructor.
In the above example, the static members was accessed multiple times. However, static
constructor got called only once when any of its static members was accessed for the first
time.
class Program
{
static void Main(string[] args)
{
MyNonStaticClass mnsObj1 = new MyNonStaticClass();
MyNonStaticClass mnsObj2 = new MyNonStaticClass();
MyNonStaticClass mnsObj3 = new MyNonStaticClass();
}
}
Output:
Inside static constructor
In the above example, we instantiate MyNonStaticClass three times but the static
constructor got called only once when it instantiated for the first time.
As you know, the main parts of an application's memory are stack and heap. Static
members are stored in a special area inside the heap called High Frequency Heap. Static
members of non-static classes are also stored in the heap and shared across all the instances
of the class. So the changes done by one instance will be reflected in all the other instances.
As mentioned earlier, a static member can only contain or access other static members,
because static members are invoked without creating an instance and so they cannot access
non-static members.
The following image illustrates how static members are stored in memory:
Points to Remember :
C# - Anonymous Method
As the name suggests, an anonymous method is a method without a name. Anonymous
methods in C# can be defined using the delegate keyword and can be assigned to a variable
of delegate type.
print(100);
}
Output:
Inside Anonymous method. Value: 100
Anonymous methods can also be passed to a method that accepts the delegate as a
parameter.
In the following example, PrintHelperMethod() takes the first parameters of the Print
delegate:
class Program
{
public static void PrintHelperMethod(Print printDel,int
val)
{
val += 10;
printDel(val);
}
C# 3.0 introduced the lambda expression which also works like an anonymous method.
Points to Remember :
Nullable Type in C#
As you know, a value type cannot be assigned a null value. For example, int i = null will
give you a compile time error.
C# 2.0 introduced nullable types that allow you to assign null to value type variables. You
can declare nullable types using Nullable<t> where T is a type.
A nullable type can represent the correct range of values for its underlying value type, plus
an additional null value. For example, Nullable<int> can be assigned any value from -
2147483648 to 2147483647, or a null value.
The Nullable types are instances of System.Nullable<T> struct. Think it as something like
the following structure.
// other implementation
}
A nullable of type int is the same as an ordinary int plus a flag that says whether the int has
a value or not (is null or not). All the rest is compiler magic that treats "null" as a valid
value.
Example: HasValue
static void Main(string[] args)
{
Nullable<int> i = null;
if (i.HasValue)
Console.WriteLine(i.Value); // or Console.WriteLine(i)
else
Console.WriteLine("Null");
}
Output:
Null
The HasValue returns true if the object has been assigned a value; if it has not been
assigned any value or has been assigned a null value, it will return false.
Accessing the value using NullableType.value will throw a runtime exception if nullable
type is null or not assigned any value. For example, i.Value will throw an exception if i is
null:
In
valid use of Nullable Type
Use the GetValueOrDefault() method to get an actual value if it is not null and the default
value if it is null. For example:
Example: GetValueOrDefault()
static void Main(string[] args)
{
Nullable<int> i = null;
Console.WriteLine(i.GetValueOrDefault());
}
Shorthand Syntax for Nullable Types
You can use the '?' operator to shorthand the syntax e.g. int?, long? instead of using
Nullable<T>.
?? Operator
int j = i ?? 0;
Console.WriteLine(j);
Output:
0
In the above example, i is a nullable int and if you assign it to the non-nullable int j then it
will throw a runtime exception if i is null. So to mitigate the risk of an exception, we have
used the '??' operator to specify that if i is null then assign 0 to j.
Assignment Rules
A nullable type has the same assignment rules as a value type. It must be assigned a value
before using it if nullable types are declared in a function as local variables. If it is a field of
any class then it will have a null value by default.
For example, the following nullable of int type is declared and used without assigning any
value. The compiler will give "Use of unassigned local variable 'i'" error:
Unassigned
nullable type-error
In the following example, a nullable of int type is a field of the class, so it will not give any
error.
if(mycls.i == null)
Console.WriteLine("Null");
}
}
Output:
Null
Null is considered to be less than any value. So comparison operators won't work against
null. Consider the following example where i is neither less than j, greater than j nor equal
to j:
if (i < j)
Console.WriteLine("i < j");
else if( i > 10)
Console.WriteLine("i > j");
else if( i == 10)
Console.WriteLine("i == j");
else
Console.WriteLine("Could not compare");
}
Output:
Could not compare
Nullable static class is a helper class for Nullable types. It provides a compare method to
compare nullable types. It also has a GetUnderlyingType method that returns the
underlying type argument of nullable types.
if (Nullable.Compare<int>(i, j) < 0)
Console.WriteLine("i < j");
else if (Nullable.Compare<int>(i, j) > 0)
Console.WriteLine("i > j");
else
Console.WriteLine("i = j");
}
Output:
i < j
Points to Remember :
Consider the following class hierarchy before we learn about covariance and
contravariance:
}
class Big: Small
{
}
class Bigger : Big
{
As per the above example classes, small is a base class for big and big is a base class for
bigger. The point to remember here is that a derived class will always have something more
than a base class, so the base class is relatively smaller than the derived class.
Class initialization
As you can see above, a base class can hold a derived class but a derived class cannot hold
a base class. In other word, an instance can accept big even if it demands small, but it
cannot accept small if it demands big.
Covariance in C#
Covariance enables you to pass a derived type where a base type is expected. Co-variance
is like variance of the same kind. The base class and other derived classes are considered to
be the same kind of class that adds extra functionalities to the base type. So covariance
allows you to use a derived class where a base class is expected (rule: can accept big if
small is expected).
class Program
{
As you can see in the above example, delegate expects a return type of small (base class)
but we can still assign Method1 that returns Big (derived class) and also Method2 that has
same signature as delegate expects.
Thus, covariance allows you to assign a method to the delegate that has a less derived
return type.
C# Contravariance
Continuing with the example above, add Method3 that has a different parameter type than
delegate:
class Program
{
static Big Method1(Big bg)
{
Console.WriteLine("Method1");
return new Big();
}
static Small Method2(Big bg)
{
Console.WriteLine("Method2");
return new Small();
}
As you can see, Method3 has a parameter of Small class whereas delegate expects a
parameter of Big class. Still, you can use Method3 with the delegate.
You can also use covariance and contravariance in the same method as shown below.
class Program
{
Visit Eric Lippert's blog to know more about covariance and contravarince.
Consider the following class hierarchy before we learn about covariance and
contravariance:
}
class Big: Small
{
}
class Bigger : Big
{
As per the above example classes, small is a base class for big and big is a base class for
bigger. The point to remember here is that a derived class will always have something more
than a base class, so the base class is relatively smaller than the derived class.
Class initialization
As you can see above, a base class can hold a derived class but a derived class cannot hold
a base class. In other word, an instance can accept big even if it demands small, but it
cannot accept small if it demands big.
Covariance in C#
Covariance enables you to pass a derived type where a base type is expected. Co-variance
is like variance of the same kind. The base class and other derived classes are considered to
be the same kind of class that adds extra functionalities to the base type. So covariance
allows you to use a derived class where a base class is expected (rule: can accept big if
small is expected).
class Program
{
Thus, covariance allows you to assign a method to the delegate that has a less derived
return type.
C# Contravariance
Continuing with the example above, add Method3 that has a different parameter type than
delegate:
class Program
{
static Big Method1(Big bg)
{
Console.WriteLine("Method1");
return new Big();
}
static Small Method2(Big bg)
{
Console.WriteLine("Method2");
return new Small();
}
You can also use covariance and contravariance in the same method as shown below.
class Program
{
Further Reading
Visit Eric Lippert's blog to know more about covariance and contravarince.
C# LINQ
LINQ (Language Integrated Query) is uniform query syntax in C# and VB.Net to save and
retrieve data from different sources. It is integrated in C# or VB, thereby eliminating the
impedance mismatch between programming languages and databases, as well as providing
a single querying interface for different types of data sources.
For example, SQL is a Structured Query Language to save and retrieve data from the
database the same way LINQ is a structured query syntax built in C# and VB.Net to save
and retrieve data from different types of data sources like an Object Collection, an SQL
server database, XML, a web service etc.
C# 3.0/.Net 3.5 introduced lamda expression along with LINQ. Lambda expression is a
shorter way of representing anonymous method using some special syntax.
C# - Func
We have learned in the previous section, that a delegates can be defined as shown below.
Example: C# Delegate
public delegate int SomeOperation(int i, int j);
class Program
{
static int Sum(int x, int y)
{
return x + y;
}
Console.WriteLine(result);
}
}
Output:
20
C# 3.0 includes built-in generic delegate types Func and Action, so that you don't need to
define custom delegates as above.
Func is a generic delegate included in the System namespace. It has zero or more input
parameters and one out parameter. The last parameter is considered as an out parameter.
For example, a Func delegate that takes one input parameter and one out parameter is
defined in the System namespace as below:
Example: Func
namespace System
{
public delegate TResult Func<in T, out TResult>(T arg);
}
The last parameter in the angle brackets <> is considered as the return type and remaining
parameters are considered as input parameter types as shown in the following figure.
Func delegate
A Func delegate with two input parameters and one out parameters will be represent as
below.
Func delegate
The following Func type delegate is the same as the above SomeOperation delegate, where
it takes two input parameters of int type and returns a value of int type:
You can assign any method to the above func delegate that takes two int parameters and
returns an int value. Now, you can take Func delegate instead of someOperation delegate in
the first example.
Example: Func
class Program
{
static int Sum(int x, int y)
{
return x + y;
}
static void Main(string[] args)
{
Func<int,int, int> add = Sum;
Console.WriteLine(result);
}
}
Output:
20
A Func delegate type can include 0 to 16 input parameters of different types. However, it
must include one out parameter for result. For example, the following func delegate doesn't
have any input parameter, it includes only a out parameter.
You can assign an anonymous method to the Func delegate by using the delegate keyword.
A Func delegate can also be used with a lambda expression, as shown below:
//Or
Points to Remember :
Example: C# Delegate
public delegate void Print(int val);
You can use an Action delegate instead of defining the above Print delegate, for example:
You can initialize an Action delegate using the new keyword or by directly assigning a
method:
//Or
printActionDel(10);
}
Output:
10
printActionDel(10);
}
Thus, you can use any method that doesn't return a value with Action delegate types.
Points to Remember :
1. Action delegate is same as func delegate except that it does not return anything. Return
type must be void.
2. Action delegate can have 1 to 16 input parameters.
3. Action delegate can be used with anonymous methods or lambda expressions.
C# - Predicate Delegate
A predicate is also a delegate like Func and Action delegates. It represents a method that
contains a set of criteria and checks whether the passed parameter meets those criteria or
not. A predicate delegate methods must take one input parameter and it then returns a
boolean value - true or false.
Same as other delegate types, Predicate can also be used with any method, anonymous
method or lambda expression.
Console.WriteLine(result);
}
Output:
false
An anonymous method can also be assigned to a Predicate delegate type as shown below.
A lambda expression can also be assigned to a Predicate delegate type as shown below.
Points to Remember :
1. Predicate delegate takes one input parameter and boolean return type.
2. Predicate delegate must contains some criateria to check whether supplied
parameter meets those criateria or not.
3. Anonymous method and Lambda expression can be assigned to the predicate
delegate.
C# - Extension Method
Extension methods, as the name suggests, are additional methods. Extension methods allow
you to inject additional methods without modifying, deriving or recompiling the original
class, struct or interface. Extension methods can be added to your own custom class, .NET
framework classes, or third party classes or interfaces.
In the following example, IsGreaterThan() is an extension method for int type, which
returns true if the value of the int variable is greater than the supplied integer parameter.
The IsGreaterThan() method is not a method of int data type (Int32 struct). It is an
extension method written by the programmer for the int data type. The IsGreaterThan()
extension method will be available throughout the application by including the namespace
in which it has been defined.
The extension methods have a special symbol in intellisense of the visual studio, so that
you can easily differentiate between class methods and extension methods.
An extension method is actually a special kind of static method defined in a static class. To
define an extension method, first of all, define a static class.
}
}
Now, define a static method as an extension method where the first parameter of the
extension method specifies the type on which the extension method is applicable. We are
going to use this extension method on int type. So the first parameter must be int preceded
with the this modifier.
For example, the IsGreaterThan() method operates on int, so the first parameter would
be, this int i.
Now, you can include the ExtensionMethods namespace wherever you want to use this
extension method.
class Program
{
static void Main(string[] args)
{
int i = 10;
Console.WriteLine(result);
}
}
Output:
false
Note:
The only difference between a regular static method and an extension method is that the
first parameter of the extension method specifies the type that it is going to operator on,
preceded by the this keyword.
Points to Remember :
1. Extension methods are additional custom methods which were originally not
included with the class.
2. Extension methods can be added to custom, .NET Framework or third party classes,
structs or interfaces.
3. The first parameter of the extension method must be of the type for which the
extension method is applibable, preceded by the this keyword.
4. Extension methods can be used anywhere in the application by including the
namespace of the extension method.
C# - Anonymous Type
Anonymous type, as the name suggests, is a type that doesn't have any name. C# allows
you to create an object with the new keyword without defining its class. The implicitly
typed variable- var is used to hold the reference of anonymous types.
Notice that the compiler applies the appropriate type to each property based on the value
expression. For example, firstProperty is a string type, secondProperty is an int type and
thirdProperty is a bool.
Internally, the compiler automatically generates the new type for anonymous types. You
can check the type of an anonymous type as shown below.
Console.WriteLine(myAnonymousType.GetType().ToString());
}
Output:
<>f__AnonymousType0'3[System.String,System.Int32,System.Boolean]
As you can see in the above output, the compiler generates a type with some cryptic name
for an anonymous type. If you see the above anonymous type in reflector, it looks like
below.
Dis
assembled Anonymous Type
Notice that it is derived from the System.Object class. Also, it is a sealed class and all the
properties are created as read only properties.
An anonymous type will always be local to the method where it is defined. Usually, you
cannot pass an anonymus type to another method; however, you can pass it to a method that
accepts a parameter of dynamic type. Please note that Passing anonymous types using
dynamic is not recommended.
DoSomethig(myAnonymousType);
}
Linq Select clause creates an anonymous type as a result of a query to include various
properties which is not defined in any class. Consider the following example.
class Program
{
static void Main(string[] args)
{
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName =
"John", age = 18 } ,
new Student() { StudentID = 2, StudentName =
"Steve", age = 21 } ,
new Student() { StudentID = 3, StudentName =
"Bill", age = 18 } ,
new Student() { StudentID = 4, StudentName =
"Ram" , age = 20 } ,
new Student() { StudentID = 5, StudentName =
"Ron" , age = 21 }
};
In the above example, Student class includes various properties. In the Main() method, Linq
select clause creates an anonymous type to include only StudentId and StudentName
instead of including all the properties in a result. Thus, it is useful in saving memory and
unnecessary code. The query result collection includes only StudentID and StudentName
properties as shown in the following debug view.
Points to Remember :
1. Anonymous type can be defined using the new keyword and object initializer syntax.
2. The implicitly typed variable- var, is used to hold an anonymous type.
3. Anonymous type is a reference type and all the properties are read-only.
4. The scope of an anonymous type is local to the method where it is defined.
C# - Dynamic Type
C# 4.0 (.NET 4.5) introduced a new type that avoids compile time type checking. You have
learned about the implicitly typed variable- var in the previous section where the compiler
assigns a specific type based on the value of the expression. A dynamic type escapes type
checking at compile time; instead, it resolves type at run time.
The compiler compiles dynamic types into object types in most cases. The above statement
would be compiled as:
The actual type of dynamic would resolve at runtime. You can check the type of the
dynamic variable, as below:
Console.WriteLine(dynamicVariable.GetType().ToString());
}
Output:
System.Int32
A dynamic type changes its type at runtime based on the value of the expression to the right
of the "=" operator. The following example shows how a dynamic variable changes its type
based on its value:
Example: dynamic
static void Main(string[] args)
{
dynamic dynamicVariable = 100;
Console.WriteLine("Dynamic variable value: {0}, Type:
{1}",dynamicVariable, dynamicVariable.GetType().ToString());
dynamicVariable = true;
Console.WriteLine("Dynamic variable value: {0}, Type: {1}",
dynamicVariable, dynamicVariable.GetType().ToString());
dynamicVariable = DateTime.Now;
Console.WriteLine("Dynamic variable value: {0}, Type: {1}",
dynamicVariable, dynamicVariable.GetType().ToString());
}
Output:
Dynamic variable value: 100, Type: System.Int32
Dynamic variable value: Hello World!!, Type: System.String
Dynamic variable value: True, Type: System.Boolean
Dynamic variable value: 01-01-2014, Type: System.DateTime
If you assign class object to the dynamic type then the compiler would not check for correct
methods and properties name of a dynamic type that holds the custom class object.
Consider the following example.
Example: dynamic
public class Student
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
class Program
{
static void Main(string[] args)
{
dynamic dynamicStudent = new Student();
dynamicStudent.FakeMethod();
}
}
Intellisense in Visual Studio does not give any help for the dymanic type.
In the above example, we have assigned Student object to a dynamic variable. In the second
statement in Main() method, we call FakeMethod() method, which is not exists in the
Student class. However, the compiler will not give any error for FakeMethod() because it
skips type checking for dynamic type, instead you will get a runtime exception for it as
shown below.
Dynamic Type Fake Method Error
A method can have dynamic type parameters so that it can accept any type of parameter at
run time.
PrintValue("Hello World!!");
PrintValue(100);
PrintValue(100.50);
PrintValue(true);
PrintValue(DateTime.Now);
}
}
Output:
Hello World!!
100
100.50
True
01-01-2014 10:10:50
Points to Remember :
1. The dynamic types are resolved at runtime instead of compile time.
2. The compiler skips the type checking for dynamic type. So it doesn't give any error about
dynamic types at compile time.
3. The dynamic types do not have intellisense support in visual studio.
4. A method can have parameters of the dynamic type.
5. An exception is thrown at runtime if a method or property is not compatible.
class Program
{
static void Main(string[] args)
{
Student std = new Student() { StudentID = 1,
StudentName = "Bill",
Age = 20,
Address = "New York"
};
}
}
In the above example, Student class is defined without any constructors. In the Main()
method, we have created Student object and assigned values to all or some properties in the
curly bracket at the same time. This is called object initializer syntax.
The compiler compiles the above initializer into something like the following.
Collection can be initialized the same way as class objects using collection initializer
syntax.
You can also initialize collections and objects at the same time.
Initializer syntax makes a code more readable, easy to add elements into the collection.
Useful in multi-threading.
C# - Tuple
The Tuple<T> class was introduced in .NET Framework 4.0. A tuple is a data structure that
contains a sequence of elements of different data types. It can be used where you want to
have a data structure to hold an object with properties, but you don't want to create a
separate type for it.
In the above example, we created an instance of the Tuple which holds a record of a
person. We specified a type for each element and passed values to the constructor.
Specifying the type of each element is cumbersome. So, C# includes a static helper class
Tuple which returns an instance of the Tuple<T> without specifying the type of each
element, as shown below.
A tuple can only include maximum eight elements. It gives a compiler error when you try
to include more than eight elements.
The elements of a tuple can be accessed with Item<elementNumber> properties e.g. Item1,
Item2, Item3 and so on up to Item7 property. The Item1 property returns the first element,
Item2 returns the second element and so on. The last element (the 8th element) will be
returned using the Rest property.
Generally, the 8th position is for the nested tuple which you can access using the Rest
property.
Nested Tuples
If you want to include more than eight elements in a tuple, you can do that by nesting
another tuple object as the eighth element. The last nested tuple can be accessed using the
Rest property. To access the nested tuple's element, use the
Rest.Item1.Item<elelementNumber> property.
You can include the nested tuple object anywhere in the sequence. However, it is
recommended to place the nested tuple at the end of the sequence so that it can be accessed
using the Rest property.
1. When you want to return multiple values from a method without using ref or out
parameters.
2. When you want to pass multiple values to a method through a single parameter.
3. When you want to hold a database record or some values temporarily without creating a
separate class.
Tuple Limitations:
1. Tuple is a reference type and not a value type. It allocates on heap and could result in CPU
intensive operations.
2. Tuple is limited to include 8 elements. You need to use nested tuples if you need to store
more elements. However, this may result in ambiguity.
3. Tuple elements can be accessed using properties with a name pattern
Item<elementNumber> which does not make sense.
C# 7 includes ValueTuple to overcome the limitations of Tuple and also makes it even
easier to work with Tuple. Learn about it in the next chapter.
C# - ValueTuple
C# 7.0 (.NET Framework 4.7) introduced ValueTuple, a structure which is a value type
representation of the Tuple.
The ValueTuple is only available in .NET Framework 4.7. If you don't see ValueTuple in
your project then you need to install the ValueTuple. (.NET Framework 4.7 or higher,
or .NET Standard Library 2.0 or higher already includes ValueTuple.)
To install the ValueTuple package, right click on the project in the solution explorer and
select Manage NuGet Packages... This will open the NuGet Package Manager. Click the
Browse tab, search for ValueTuple in the search box and select the System.ValueTuple
package, as shown below.
ValueTuple Initialization
It is easy to create and initialize ValueTuple. It can be created and initialized using
parentheses () and specifying the values between them.
ValueTuple can also be initialized by specifying the type of each element, as shown below.
Please notice that we have not used var in the above tuple initialization statement; instead
we provided the type of each member values inside the brackets.
We can assign names to ValueTuple properties instead of having the default property
names Item1, Item2 and so on.
We can also assign member names at the right side with values, as below.
Please note that we can provide member names either at the left side or at the right side but
not at both side. The left side has precedence over the left side. The following will ignore
names at the right side.
We can also specify different member names for a ValueTuple returned from a method.
ValueTuple also allows "discards" in deconstruction for the members you are not going to
use.
LINQ Tutorial
Language-Integrated Query (LINQ) is a powerful query language introduced with .Net 3.5
& Visual Studio 2008. LINQ can be used with C# or Visual Basic to query different data
sources.
LINQ tutorials will help you to learn the LINQ language using topics which go from basic
to advanced. These tutorials are broken down into series of related topics, so that you start
from a topic which must be understand first, and then gradually learn other features of
LINQ sequentially. LINQ tutorials are packed with easy to understand explanations, real-
world examples, useful tips, informative notes and points to remember.
These tutorials are designed for beginners and professionals who want to learn LINQ step-
by-step.
Prerequisites
LINQ Test
Test your LINQ knowledge with a quick test. It includes 20 questions and each question
includes 4 options. Select an appropriate answer out of 4 options. There is no time limit for
this test.
What is LINQ?
LINQ (Language Integrated Query) is uniform query syntax in C# and VB.NET used to
save and retrieve data from different sources. It is integrated in C# or VB, thereby
eliminating the mismatch between programming languages and databases, as well as
providing a single querying interface for different types of data sources.
For example, SQL is a Structured Query Language used to save and retrieve data from a
database. In the same way, LINQ is a structured query syntax built in C# and VB.NET used
to save and retrieve data from different types of data sources like an Object Collection,
SQL server database, XML, web service etc.
LINQ always works with objects so you can use the same basic coding patterns to query
and transform data in XML documents, SQL databases, ADO.NET Datasets, .NET
collections, and any other format for which a LINQ provider is available.
LINQ Usage
Before C# 2.0, we had to use a 'foreach' or a 'for' loop to traverse the collection to find a
particular object. For example, we had to write the following code to find all Student
objects from an array of Students where the age is between 12 and 20 (for teenage 13 to
19):
Example: Use for loop to find elements from the collection in C# 1.0
class Student
{
public int StudentID { get; set; }
public String StudentName { get; set; }
public int Age { get; set; }
}
class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18
},
new Student() { StudentID = 2, StudentName = "Steve", Age =
21 },
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 },
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20
},
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31
},
new Student() { StudentID = 6, StudentName = "Chris", Age =
17 },
new Student() { StudentID = 7, StudentName = "Rob",Age =
19 },
};
int i = 0;
Use of for loop is cumbersome, not maintainable and readable. C# 2.0 introduced delegate,
which can be used to handle this kind of a scenario, as shown below.
class StudentExtension
{
public static Student[] where(Student[] stdArray, FindStudent del)
{
int i=0;
Student[] result = new Student[10];
foreach (Student std in stdArray)
if (del(std))
{
result[i] = std;
i++;
}
return result;
}
}
class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John", Age = 18
} ,
new Student() { StudentID = 2, StudentName = "Steve", Age =
21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20
} ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 31
} ,
new Student() { StudentID = 6, StudentName = "Chris", Age =
17 } ,
new Student() { StudentID = 7, StudentName = "Rob",Age =
19 } ,
};
The C# team felt that they still needed to make the code even more compact and readable.
So they introduced the extension method, lambda expression, expression tree, anonymous
type and query expression in C# 3.0. You can use these features of C# 3.0, which are
building blocks of LINQ to query to the different types of collection and get the resulted
element(s) in a single statement.
The example below shows how you can use LINQ query with lambda expression to find a
particular student(s) from the student collection.
Example: LINQ
class Program
{
static void Main(string[] args)
{
Student[] studentArray = {
new Student() { StudentID = 1, StudentName = "John",
age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve",
age = 21 } ,
new Student() { StudentID = 3, StudentName = "Bill",
age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" ,
age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" ,
age = 31 } ,
new Student() { StudentID = 6, StudentName = "Chris",
age = 17 } ,
new Student() { StudentID = 7, StudentName =
"Rob",age = 19 } ,
};
As you can see in the above example, we specify different criteria using LINQ operator and
lambda expression in a single statement. Thus, LINQ makes code more compact and
readable and it can also be used to query different data sources. For example, if you have a
student table in a database instead of an array of student objects as above, you can still use
the same query to find students using the Entity Framework.
Advantages of LINQ
Familiar language: Developers don’t have to learn a new query language for each type of
data source or data format.
Less coding: It reduces the amount of code to be written as compared with a more
traditional approach.
Readable code: LINQ makes the code more readable so other developers can easily
understand and maintain it.
Standardized way of querying multiple data sources: The same LINQ syntax can be used
to query multiple data sources.
Compile time safety of queries: It provides type checking of objects at compile time.
IntelliSense Support: LINQ provides IntelliSense for generic collections.
Shaping data: You can retrieve data in different shapes.
LINQ API
LINQ is nothing but the collection of extension methods for classes that implements
IEnumerable and IQueryable interface. System.Linq namespace includes the necessary
classes & interfaces for LINQ. Enumerable and Queryable are two main static classes of
LINQ API that contain extension methods.
System.Linq namespace is included by default when you add a new class in Visual Studio,
so that you can use LINQ by default.
Enumerable
Enumerable class includes extension methods for the classes that implement
IEnumerable<T> interface, this include all the collection types in
System.Collections.Generic namespaces such as List<T>, Dictionary<T>, SortedList<T>,
Queue<T>, HashSet<T>, LinkedList<T> etc.
The following figure illustrates that the extension methods included in Enumerable class
can be used with generic collection in C# or VB.Net.
Queryable
The Queryable class includes extension methods for classes that implement IQueryable<t>
interface. IQueryable<T> is used to provide querying capabilities against a specific data
source where the type of the data is known. For example, Entity Framework api implements
IQueryable<T> interface to support LINQ queries with underlaying database like SQL
Server.
Also, there are APIs available to access third party data; for example, LINQ to Amazon
provides the ability to use LINQ with Amazon web services to search for books and other
items by implementing IQueryable interface.
The following figure illustrates that the extension methods included in Queryable class can
be used with various native or third party data providers.
IQueryable extension methods in Queryable class
Visit MSDN to know all the extension methods of Enumerable and Queryable class.
Points to Remember :
Query Syntax
Query syntax is similar to SQL (Structured Query Language) for the database. It is defined
within the C# or VB code.
LINQ Query Syntax:
from <range variable> in <IEnumerable<T> or IQueryable<T> Collection>
The LINQ query syntax starts with from keyword and ends with select keyword. The
following is a sample LINQ query that returns a collection of strings which contains a word
"Tutorials".
Query syntax starts with a From clause followed by a Range variable. The From clause is
structured like "From rangeVariableName in IEnumerablecollection". In English,
this means, from each object in the collection. It is similar to a foreach loop:
foreach(Student s in studentList).
After the From clause, you can use different Standard Query Operators to filter, group, join
elements of the collection. There are around 50 Standard Query Operators available in
LINQ. In the above figure, we have used "where" operator (aka clause) followed by a
condition. This condition is generally expressed using lambda expression.
LINQ query syntax always ends with a Select or Group clause. The Select clause is used to
shape the data. You can select the whole object as it is or only some properties of it. In the
above example, we selected the each resulted string elements.
In the following example, we use LINQ query syntax to find out teenager students from the
Student collection (sequence).
Points to Remember :
1. As name suggest, Query Syntax is same like SQL (Structure Query Language) syntax.
2. Query Syntax starts with from clause and can be end with Select or GroupBy clause.
3. Use various other opertors like filtering, joining, grouping, sorting operators to construct
the desired result.
4. Implicitly typed variable - var can be used to hold the result of the LINQ query.
LINQ Method Syntax
In the previous section, you have learned about LINQ Query Syntax. Here, you will learn
about Method syntax.
The compiler converts query syntax into method syntax at compile time.
Method syntax (also known as fluent syntax) uses extension methods included in the
Enumerable or Queryable static class, similar to how you would call the extension method
of any class.
The following is a sample LINQ method syntax query that returns a collection of strings
which contains a word "Tutorials".
As you can see in the above figure, method syntax comprises of extension methods and
Lambda expression. The extension method Where() is defined in the Enumerable class.
If you check the signature of the Where extension method, you will find the Where method
accepts a predicate delegate as Func<Student, bool>. This means you can pass any delegate
function that accepts a Student object as an input parameter and returns a Boolean value as
shown in the below figure. The lambda expression works as a delegate passed in the Where
clause. Learn lambda expression in the next section.
The following example shows how to use LINQ method syntax query with the
IEnumerable<T> collection.
The above anonymous method can be represented using a Lambda Expression in C# and
VB.Net as below:
Let's see how the lambda expression evolved from the following anonymous method.
The Lambda expression evolves from anonymous method by first removing the delegate
keyword and parameter type and adding a lambda operator =>.
Lambda Expression from Anonymous Method
The above lambda expression is absolutely valid, but we don't need the curly braces, return
and semicolon if we have only one statement that returns a value. So we can eliminate it.
Thus, we got the lambda expression: s => s.Age > 12 && s.Age < 20 where s is a
parameter, => is the lambda operator and s.Age > 12 && s.Age < 20 is the body
expression:
The lambda expression can be invoked same way as delegate using ().
Note:
You can wrap the parameters in parenthesis if you need to pass more than one parameter, as
below:
You can also give type of each parameters if parameters are confusing:
It is not necessary to have atleast one parameter in a lambda expression. The lambda
expression can be specify without any parameter also.
You can wrap expressions in curly braces if you want to have more than one statement in
the body:
End Function
Declare Local Variable in Lambda Expression Body
You can declare a variable in the expression body to use it anywhere in the expression
body, as below:
End Function
Lambda expression can also be assigned to built-in delegates such as Func, Action and
Predicate.
The lambda expression can be assigned to Func<in T, out TResult> type delegate. The
last parameter type in a Func delegate is the return type and rest are input parameters. Visit
Func delegate section of C# tutorials to know more about it.
Consider the following lambda expression to find out whether a student is a teenager or not.
In the above example, the Func delegate expects the first input parameter to be of Student
type and the return type to be boolean. The lambda expression s => s.age > 12 &&
s.age < 20 satisfies the Func<Student, bool> delegate requirement, as shown below:
Func
delegate with Lambda Expression
The Func<> delegate shown above, would turn out to be a function as shown below.
bool isStudentTeenAger(Student s)
{
return s.Age > 12 && s.Age < 20;
}
Action Delegate
Unlike the Func delegate, an Action delegate can only have input parameters. Use the
Action delegate type when you don't need to return any value from lambda expression.
Usually lambda expression is used with LINQ query. Enumerable static class includes
Where extension method for IEnumerable<T> that accepts Func<TSource,bool>. So, the
Where() extension method for IEnumerable<Student> collection is required to pass
Func<Student,bool>, as shown below:
So now, you can pass the lambda expression assigned to the Func delegate to the Where()
extension method in the method syntax as shown below:
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;
var teenStudents =
studentList.Where(isStudentTeenAger).ToList<Student>();
Example: Func Delegate in LINQ Query Syntax
IList<Student> studentList = new List<Student>(){...};
Func<Student, bool> isStudentTeenAger = s => s.age > 12 && s.age < 20;
You can follow the same method in VB.Net to pass Func delegate.
Points to Remember :
Standard Query
Operators in Query Syntax
Standard query operators in query syntax is converted into extension methods at compile
time. So both are same.
Standard Query Operators can be classified based on the functionality they provide. The
following table lists all the classification of Standard Query Operators:
Concatenation Concat
Equality SequenceEqual
The following table lists all the filtering operators available in LINQ.
Filtering
Description
Operators
Returns values from the collection based on a specified type. However, it will
OfType
depend on their ability to cast to a specified type.
Where
The Where operator (Linq extension method) filters the collection based on a given criteria
expression and returns a new collection. The criteria can be specified as lambda expression
or Func delegate type.
The Where extension method has following two overloads. Both overload methods accepts
a Func delegate type parameter. One overload required Func<TSource,bool> input
parameter and second overload method required Func<TSource, int, bool> input parameter
where int is for index:
The following query sample uses a Where operator to filter the students who is teen ager
from the given collection (sequence). It uses a lambda expression as a predicate function.
In the above example, filteredResult will include following students after query execution.
John
Bill
Ron
In the above sample query, the lambda expression body s.Age > 12 && s.Age < 20 is
passed as a predicate function Func<TSource, bool> that evaluates every student in the
collection.
Alternatively, you can also use a Func type delegate with an anonymous method to pass as
a predicate function as below (output would be the same):
You can also call any method that matches with Func parameter with one of Where()
method overloads.
As mentioned above, the Where extension method also have second overload that includes
index of current element in the collection. You can use that index in your logic if you need.
The following example uses the Where clause to filter out odd elements in the collection
and return only even elements. Please remember that index starts from zero.
return false;
});
Output:
John
Bill
Ron
You can call the Where() extension method more than one time in a single LINQ query.
Points to Remember :
Use OfType operator to filter the above collection based on each element's type
The above sample queries will return items whose type is string in the mixedList.
stringResult contains following elements after execution:
One
Two
0
3
Bill
You can use OfType<TResult>() extension method in linq method syntax as shown below.
Example: OfType in C#
var stringResult = mixedList.OfType<string>();
Example: OfType in VB.Net
Dim stringResult = mixedList.OfType(Of String)
One
Two
Points to Remember :
Sorts the collection based on specified fields in descending order. Only valid
OrderByDescending
in method syntax.
ThenBy Only valid in method syntax. Used for second level sorting in ascending order.
Sorting Operator Description
Only valid in method syntax. Used for second level sorting in descending
ThenByDescending
order.
Reverse Only valid in method syntax. Sorts the collection in reverse order.
OrderBy
OrderBy sorts the values of a collection in ascending or descending order. It sorts the
collection in ascending order by default because ascending keyword is optional here. Use
descending keyword to sort collection in descending order.
orderByResult in the above example would contain following elements after execution:
Bill
John
Ram
Ron
Steve
OrderBy extension method has two overloads. First overload of OrderBy extension method
accepts the Func delegate type parameter. So you need to pass the lambda expression for
the field based on which you want to sort the collection.
The second overload method of OrderBy accepts object of IComparer along with Func
delegate type to use custom comparison for sorting.
The following example sorts the studentList collection in ascending order of StudentName
using OrderBy extension method.
Method syntax does not allow the decending keyword to sorts the collection in decending order.
Use OrderByDecending() method for it.
OrderByDescending
OrderByDescending sorts the collection in descending order.
OrderByDescending is valid only with the Method syntax. It is not valid in query syntax
because the query syntax uses ascending and descending attributes as shown above.
Example: OrderByDescending C#
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
A result in the above example would contain following elements after execution.
Steve
Ron
Ram
John
Bill
Please note that OrderByDescending is not supported in query syntax. Use the decending
keyword instead.
Multiple Sorting
You can sort the collection on multiple fields seperated by comma. The given collection
would be first sorted based on the first field and then if value of first field would be the
same for two elements then it would use second field for sorting and so on.
In the above example, studentList collection includes two identical StudentNames, Ram. So
now, studentList would be first sorted based on StudentName and then by Age in ascending
order. So, orderByResult would contain following elements after execution
Note:
Multiple sorting in method syntax works differently. Use ThenBy or ThenByDecending extension
methods for secondary sorting.
Points to Remember :
The OrderBy() method sorts the collection in ascending order based on specified field. Use
ThenBy() method after OrderBy to sort the collection on another field in ascending order.
Linq will first sort the collection based on primary field which is specified by OrderBy
method and then sort the resulted collection in ascending order again based on secondary
field specified by ThenBy method.
The same way, use ThenByDescending method to apply secondary sorting in descending
order.
The following example shows how to use ThenBy and ThenByDescending method for
second level sorting:
As you can see in the above example, we first sort a studentList collection by StudentName
and then by Age. So now, thenByResult would contain follwoing elements after sorting:
thenByDescResult would contain following elements. Please notice that Ram with age 20
comes before Ram with age 18 because it has used ThenByDescending.
You can use ThenBy and ThenByDescending method same way in VB.Net as below:
Grouping
Description
Operators
The GroupBy operator returns groups of elements based on some key value. Each
GroupBy
group is represented by IGrouping<TKey, TElement> object.
ToLookup is the same as GroupBy; the only difference is the execution of GroupBy
ToLookup
is deferred whereas ToLookup execution is immediate.
GroupBy
The GroupBy operator returns a group of elements from the given collection based on some
key value. Each group is represented by IGrouping<TKey, TElement> object. Also, the
GroupBy method has eight overload methods, so you can use appropriate extension method
based on your requirement in method syntax.
The result of GroupBy operators is a collection of groups. For example, GroupBy returns
IEnumerable<IGrouping<TKey,Student>> from the Student collection:
Return type of GroupBy()
The following example creates a groups of students who have same age. Students of the
same age will be in the same collection and each grouped collection will have a key and
inner collection, where the key will be the age and the inner collection will include students
whose age is matched with a key.
Use "Into Group" with the 'Group By' clause in VB.Net as shown below.
Notice that each group will have a property name on which group is performed. In the
above example, we have used Age to form a group so each group will have "Age" property
name instead of "Key" as a property name.
Output:
AgeGroup: 18
StudentName: John
StudentName: Bill
AgeGroup: 21
StudentName: Steve
StudentName: Abram
AgeGroup: 20
StudentName: Ram
ToLookup is the same as GroupBy; the only difference is GroupBy execution is deferred,
whereas ToLookup execution is immediate. Also, ToLookup is only applicable in Method
syntax. ToLookup is not supported in the query syntax.
Points to Remember :
1. GroupBy & ToLookup return a collection that has a key and an inner collection based on a
key field value.
2. The execution of GroupBy is deferred whereas that of ToLookup is immediate.
3. A LINQ query syntax can be end with the GroupBy or Select clause.
Joining
Usage
Operators
Join The Join operator joins two sequences (collections) based on a key and returns a
Joining
Usage
Operators
resulted sequence.
The GroupJoin operator joins two sequences based on keys and returns groups of
GroupJoin
sequences. It is like Left Outer Join of SQL.
Join
The Join operator operates on two collections, inner collection & outer collection. It returns
a new collection that contains elements from both the collections which satisfies specified
expression. It is the same as inner join of SQL.
As you can see in the first overload method takes five input parameters (except the first
'this' parameter): 1) outer 2) inner 3) outerKeySelector 4) innerKeySelector 5)
resultSelector.
Let's take a simple example. The following example joins two string collection and return
new collection that includes matching strings in both the collection.
Now, let's understand join metohod using following Student and Standard class where
Student class includes StandardID that matches with StandardID of Standard class.
Example Classes
public class Student{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int StandardID { get; set; }
}
The following image illustrate the parts of Join operator in the above example.
join operator
In the above example of join query, studentList is outer sequence because query starts from
it. First parameter in Join method is used to specify the inner sequence which is
standardList in the above example. Second and third parameter of Join method is used to
specify a field whose value should be match using lambda expression in order to include
element in the result. The key selector for the outer sequence student =>
student.StandardID indicates that take StandardID field of each elements of studentList
should be match with the key of inner sequence standard => standard.StandardID. If
value of both the key field is matched then include that element into result.
The last parameter in Join method is an expression to formulate the result. In the above
example, result selector includes StudentName and StandardName property of both the
sequence.
StandardID Key of both the sequences (collections) must match otherwise the item will not
be included in the result. For example, Ron is not associated with any standard so Ron is
not included in the result collection. innerJoinResult in the above example would contain
following elements after execution:
John - Standard 1
Moin - Standard 1
Bill - Standard 2
Ram - Standard 2
The following example demonstrates the Join operator in method syntax in VB.Net.
Example: Join operator VB.Net
Dim innerJoin = studentList.Join(standardList,
Function(s) s.StandardID,
Function(std) std.StandardID,
Function(s, std) New With
{
.StudentName = s.StudentName,
.StandardName = std.StandardName
});
Join operator in query syntax works slightly different than method syntax. It requires outer
sequence, inner sequence, key selector and result selector. 'on' keyword is used for key
selector where left side of 'equals' operator is outerKeySelector and right side of 'equals' is
innerKeySelector.
select ...
The following example of Join operator in query syntax returns a collection of elements
from studentList and standardList if their Student.StandardID and
Standard.StandardID is match.
Note:
Use the equals operator to match key selector in query syntax. == is not valid.
Points to Remember :
GroupJoin requires same parameters as Join. GroupJoin has following two overload
methods:
GroupJoin Overload Methods:
public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey,
TResult>(this IEnumerable<TOuter> outer, IEnumerable<TInner> inner,
Func<TOuter, TKey> outerKeySelector, Func<TInner, TKey> innerKeySelector,
Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);
As you can see in the first overload method takes five input parameters (except the first
'this' parameter): 1) outer 2) inner 3) outerKeySelector 4) innerKeySelector 5)
resultSelector. Please notice that resultSelector is of Func delegate type that has second
input parameter as IEnumerable type for inner sequence.
Now, let's understand GroupJoin using following Student and Standard class where Student
class includes StandardID that matches with StandardID of Standard class.
Example Classes
public class Student{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int StandardID { get; set; }
}
In the above example of GroupJoin query, standardList is the outer sequence, because the
query starts from it. The first parameter in GroupJoin method is to specify the inner
sequence, which is studentList in the above example. The second and third parameters of
the GroupJoin() method are to specify a field whose value should be matched using lambda
expression, in order to include element in the result. The key selector for the outer sequence
standard => standard.StandardID indicates that StandardID field of each elements in
standardList should be match with the key of inner sequence studentList student =>
student.StandardID. If value of both the key field is matched then include that element
into grouped collection studentsGroup where key would be StandardID.
The last parameter in Join method is an expression to formulate the result. In the above
example, result selector includes grouped collection studentGroup and StandardName.
The following image illustrate that inner sequence grouped into studentsGroup collection
for matching StandardID key and that grouped collection can be used to formulate the
result.
Grouping Operator - GroupJoin
Resultset would include an anonymous objects that has the Students and StandardFullName
properties. Students property will be a collection of Students whose StandardID matches
with Standard.StandardID.
You can access the result using a 'foreach' loop. Each element will have the
StandardFullName & Students property, where Students will be a collection.
Console.WriteLine(item.standardName)
Next
Output:
Standard 1:
John,
Moin,
Standard 2:
Bill,
Ram,
Standard 3:
GroupJoin operator in query syntax works slightly different than method syntax. It requires
an outer sequence, inner sequence, key selector and result selector. 'on' keyword is used for
key selector where the left side of 'equals' operator is the outerKeySelector and the right
side of 'equals' is the innerKeySelector. Use the into keyword to create the grouped
collection.
into groupedCollection
select ...
In the VB.Net, the InTo keyword will create a group of all students of same standard and
assign it to the Group keyword. So, use Group in the projection result.
Note:
Select
The Select operator always returns an IEnumerable collection which contains elements
based on a transformation function. It is similar to the Select clause of SQL that produces a
flat result set.
Now, let's understand Select query operator using the following Student class.
LINQ query syntax must end with a Select or GroupBy clause. The following example
demonstrates select operator that returns a string collection of StudentName.
The following example of the select clause returns a collection of anonymous type
containing the Name and Age property.
// iterate selectResult
foreach (var item in selectResult)
Console.WriteLine("Student Name: {0}, Age: {1}", item.Name,
item.Age);
Example: Select in Query Syntax VB.Net
Dim selectResult = From s In studentList
Select New With {.Name = s.StudentName, .Age = s.Age}
Output:
Student Name: Mr. John, Age: 13
Student Name: Mr. Moin, Age: 21
Student Name: Mr. Bill, Age: 18
Student Name: Mr. Ram, Age: 20
Student Name: Mr. Ron, Age: 15
The Select operator is optional in method syntax. However, you can use it to shape the data.
In the following example, Select extension method returns a collection of anonymous
object with the Name and Age property:
In the above example, selectResult would contain anonymous objects with Name and Age
property as shown below in the debug view.
The SelectMany operator projects sequences of values that are based on a transform
function and then flattens them into one sequence.
Quantifier Operators
The quantifier operators evaluate elements of the sequence on some condition and return a
boolean value to indicate that some or all elements satisfy the condition.
Operator Description
All Checks if all the elements in a sequence satisfies the specified condition
Any Checks if any of the elements in a sequence satisfies the specified condition
The All operator evalutes each elements in the given collection on a specified condition and
returns True if all the elements satisfy a condition.
Console.WriteLine(areAllStudentsTeenAger);
Example: All operator VB.Net
Dim areAllStudentsTeenAger = studentList.All(Function(s) s.Age > 12 And
s.Age < 20)
Output:
false
Any
Any checks whether any element satisfy given condition or not? In the following example,
Any operation is used to check whether any student is teen ager or not.
Note:
The Contains() extension method has following two overloads. The first overload method
requires a value to check in the collection and the second overload method requires
additional parameter of IEqualityComparer type for custom equalality comparison.
Contains() Overloads:
public static bool Contains<TSource>(this IEnumerable<TSource> source,
TSource value);
As mentioned above, the Contains() extension method requires a value to check as a input
parameter. Type of a value must be same as type of generic collection. The following
example of Contains checks whether 10 exists in the collection or not. Please notice that
int is a type of generic collection.
The above example works well with primitive data types. However, it will not work with a
custom class. Consider the following example:
Error:
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 }
,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
Example: IEqualityComperer
class StudentComparer : IEqualityComparer<Student>
{
public bool Equals(Student x, Student y)
{
if (x.StudentID == y.StudentID &&
x.StudentName.ToLower() ==
y.StudentName.ToLower())
return true;
return false;
}
Now, you can use the above StudentComparer class in second overload method of Contains
extension method that accepts second parameter of IEqualityComparer type, as below:
So thus, you have to use comparer class in order to get corrent result from Contains
extension method for custom classes.
Return False
End Function
Sub Main
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age =
18},
New Student() With {.StudentID = 2, .StudentName = "Steve", .Age
= 15},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age =
25},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age =
20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age =
19}
}
Method Description
Aggregate
The Aggregate method performs an accumulate operation. Aggregate extension method has
the following overload methods:
Aggregate() Overloads:
public static TSource Aggregate<TSource>(this IEnumerable<TSource>
source,
Func<TSource, TSource, TSource>
func);
The following example demonstrates Aggregate method that returns comma seperated
elements of the string list.
Console.WriteLine(commaSeperatedString);
Output:
One, Two, Three, Four, Five
In the above example, Aggregate extension method returns comma separated strings from
strList collection. The following image illustrates the whole aggregate operation performed
in the above example.
As per the above figure, first item of strList "One" will be pass as s1 and rest of the items
will be passed as s2. The lambda expression (s1, s2) => s1 + ", " + s2 will be
treated like s1 = s1 + ", " + s1 where s1 will be accumulated for each item in the
collection. Thus, Aggregate method will return comma separated string.
Example: Aggregate in Method Syntax VB.Net
Dim strList As IList(Of String) = New List(Of String) From {
"One",
"Two",
"Three",
"Four",
"Five"
}
The second overload method of Aggregate requires first parameter for seed value to
accumulate. Second parameter is Func type delegate:
TAccumulate Aggregate<TSource, TAccumulate>(TAccumulate seed,
Func<TAccumulate, TSource, TAccumulate> func); .
The following example uses string as a seed value in the Aggregate extension method.
Console.WriteLine(commaSeparatedStudentNames);
Example: Aggregate with Seed Value VB.Net
// Student collection
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age =
13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age =
21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age =
18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age =
20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age =
15}
}
Dim commaSeparatedStudentNames = studentList.Aggregate(Of String)(
"Student Names: ",
Function(str, s) str + s.StudentName + ",")
Console.WriteLine(commaSeparatedStudentNames);
Output:
Student Names: John, Moin, Bill, Ram, Ron,
In the above example, the first parameter of the Aggregate method is the "Student Names: "
string that will be accumulated with all student names. The comma in the lambda
expression will be passed as a second parameter.
The following example use Aggregate operator to add the age of all the students.
Now, let's see third overload method that required the third parameter of the Func delegate
expression for result selector, so that you can formulate the result.
Console.WriteLine(commaSeparatedStudentNames);
Console.WriteLine(commaSeparatedStudentNames);
Output:
John, Moin, Bill, Ram, Ron
Note:
You can specify an int, decimal, double or float property of a class as a lambda expression
of which you want to get an average value. The following example demonstrates Average
method on the complex type.
The Average operator in query syntax is Not Supported in C#. However, it is supported in
VB.Net as shown below.
Example: Average in Query Syntax VB.Net
Dim studentList = New List(Of Student) From {
New Student() With {.StudentID = 1, .StudentName = "John", .Age =
13},
New Student() With {.StudentID = 2, .StudentName = "Moin", .Age =
21},
New Student() With {.StudentID = 3, .StudentName = "Bill", .Age =
18},
New Student() With {.StudentID = 4, .StudentName = "Ram", .Age =
20},
New Student() With {.StudentID = 5, .StudentName = "Ron", .Age =
15}
}
Count() Overloads:
int Count<TSource>();
The first overload method of Count returns the number of elements in the specified
collection, whereas the second overload method returns the number of elements which have
satisfied the specified condition given as lambda expression/predicate function.
Example: Count() - C#
IList<int> intList = new List<int>() { 10, 21, 30, 45, 50 };
The following example demonstrates Count() method on the complex type collection.
Example: Count() in C#
IList<Student> studentList = new List<Student>>() {
new Student() { StudentID = 1, StudentName = "John", Age = 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age =
21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age =
18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20} ,
new Student() { StudentID = 5, StudentName = "Mathew" , Age =
15 }
};
Note:
C# Query Syntax doesn't support aggregation operators. However, you can wrap the query
into brackets and use an aggregation functions as shown below.
return 0;
});
The following example demonstrates Max() method on the complex type collection.
Example: Max() in C#
public class Student : IComparable<Student>
{
public int StudentID { get; set; }
public string StudentName { get; set; }
public int Age { get; set; }
public int StandardID { get; set; }
return 0;
}
}
class Program
{
static void Main(string[] args)
{
// Student collection
IList<Student> studentList = new List<Student>>() {
new Student() { StudentID = 1, StudentName = "John", Age
= 13} ,
new Student() { StudentID = 2, StudentName = "Moin", Age
= 21 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age
= 18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age
= 20} ,
new Student() { StudentID = 5, StudentName = "Steve" ,
Age = 15 }
};
Note:
You can use Min extension method/operator the same way as Max.
As per the above example, to find the student with the longest name, you need to
implement IComparable<T> interface and compare student names' length in CompareTo
method. So now, you can use Max() method which will use CompareTo method in order to
return appropriate result.
return 0;
});
The following example calculates sum of all student's age and also number of adult
students in a student collection.
Element Operators
Description
(Methods)
Returns the first element of a collection, or the first element that satisfies
First
a condition.
Returns the first element of a collection, or the first element that satisfies
FirstOrDefault
a condition. Returns a default value if index is out of range.
Returns the last element of a collection, or the last element that satisfies
Last
a condition
Returns the last element of a collection, or the last element that satisfies
LastOrDefault
a condition. Returns a default value if no such element exists.
The ElementAt() method returns an element from the specified index from a given
collection. If the specified index is out of the range of a collection then it will throw an
Index out of range exception. Please note that index is a zero based index.
The ElementAtOrDefault() method also returns an element from the specified index from a
collaction and if the specified index is out of range of a collection then it will return a
default value of the data type instead of throwing an error.
Learn about another element operator First and FirstOrDefault in the next section.
Element
Description
Operators
Returns the first element of a collection, or the first element that satisfies a
First
condition.
Returns the first element of a collection, or the first element that satisfies a
FirstOrDefault
condition. Returns a default value if index is out of range.
First and FirstOrDefault has two overload methods. The first overload method doesn't take
any input parameter and returns the first element in the collection. The second overload
method takes the lambda expression as predicate delegate to specify a condition and returns
the first element that satisfies the specified condition.
The First() method returns the first element of a collection, or the first element that satisfies
the specified condition using lambda expression or Func delegate. If a given collection is
empty or does not include any element that satisfied the condition then it will throw
InvalidOperation exception.
The FirstOrDefault() method does the same thing as First() method. The only difference is
that it returns default value of the data type of a collection if a collection is empty or doesn't
find any element that satisfies the condition.
Console.WriteLine("emptyList.First() throws an
InvalidOperationException");
Console.WriteLine("------------------------------------------------------
-------");
Console.WriteLine(emptyList.First());
Output:
1st Element in intList: 7
1st Even Element in intList: 10
1st Element in strList:
emptyList.First() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception: Sequence contains no elements...
Returns the last element from a collection, or the last element that satisfies a
Last
condition
Returns the last element from a collection, or the last element that satisfies a
LastOrDefault
condition. Returns a default value if no such element exists.
Last and LastOrDefault has two overload methods. One overload method doesn't take any
input parameter and returns last element from the collection. Second overload method takes
a lambda expression to specify a condition and returns last element that satisfies the
specified condition.
The LastOrDefault() method does the same thing as Last() method. The only difference is
that it returns default value of the data type of a collection if a collection is empty or doesn't
find any element that satisfies the condition.
Console.WriteLine("emptyList.Last() throws an
InvalidOperationException");
Console.WriteLine("------------------------------------------------------
-------");
Console.WriteLine(emptyList.Last());
Output:
Last Element in intList: 87
Last Even Element in intList: 50
Last Element in strList: Five
emptyList.Last() throws an InvalidOperationException
-------------------------------------------------------------
Run-time exception: Sequence contains no elements...
Single and SingleOrDefault have two overload methods. The first overload method doesn't
take any input parameter and returns a single element in the collection. The second
overload method takes the lambda expression as a predicate delegate that specifies the
condition and returns a single element that satisfies the specified condition.
Single() returns the only element from a collection, or the only element that satisfies the
specified condition. If a given collection includes no elements or more than one elements
then Single() throws InvalidOperationException.
The SingleOrDefault() method does the same thing as Single() method. The only difference
is that it returns default value of the data type of a collection if a collection is empty,
includes more than one element or finds no element or more than one element for the
specified condition.
//following throws error because list contains more than one element
which is less than 100
Console.WriteLine("Element less than 100 in intList: {0}",
intList.Single(i => i < 100));
//following throws error because list contains more than one element
which is less than 100
Console.WriteLine("Element less than 100 in intList: {0}",
intList.SingleOrDefault(i => i <
100));
//following throws error because list contains more than one elements
Console.WriteLine("The only Element in intList: {0}", intList.Single());
//following throws error because list contains more than one elements
Console.WriteLine("The only Element in intList: {0}",
intList.SingleOrDefault());
//following throws error because list does not contains any element
Console.WriteLine("The only Element in emptyList: {0}",
emptyList.Single());
Points to Remember :
If the collection contains elements of primitive data types then it compares the values and
number of elements, whereas collection with complex type elements, checks the references
of the objects. So, if the objects have the same reference then they considered as equal
otherwise they are considered not equal.
The following example demonstrates the SequenceEqual method with the collection of
primitive data types.
If the order of elements are not the same then SequenceEqual() method returns false.
Example: SequenceEqual in C#
Student std = new Student() { StudentID = 1, StudentName = "Bill" };
In the above example, studentList1 and studentList2 contains the same student object, std.
So studentList1.SequenceEqual(studentList2) returns true. But, stdList1 and
stdList2 contains two seperate student object, std1 and std2. So now,
stdList1.SequenceEqual(stdList2) will return false even if std1 and std2 contain the
same value.
To compare the values of two collection of complex type (reference type or object), you
need to implement IEqualityComperar<T> interface as shown below.
return false;
}
Now, you can use above StudentComparer class in SequenceEqual extension method as a
second parameter to compare the values:
Example: Compare object type elements using SequenceEqual C#
IList<Student> studentList1 = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 }
,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
Points to Remember :
1. The SequenceEqual method compares the number of items and their values for
primitive data types.
2. The SequenceEqual method compares the reference of objects for complex data
types.
3. Use IEqualityComparer class to compare two colection of complex type using
SequenceEqual method.
Example: Concat in C#
IList<string> collection1 = new List<string>() { "One", "Two", "Three" };
IList<string> collection2 = new List<string>() { "Five", "Six"};
Example: Concat in C#
IList<int> collection1 = new List<int>() { 1, 2, 3 };
IList<int> collection2 = new List<int>() { 4, 5, 6 };
Example: DefaultIfEmpty C#
IList<string> emptyList = new List<string>();
Example: DefaultIfEmpty C#
IList<int> emptyList = new List<int>();
Method Description
Empty
The Empty() method is not an extension method of IEnumerable or IQueryable like other
LINQ methods. It is a static method included in Enumerable static class. So, you can call it
the same way as other static methods like Enumerable.Empty<TResult>(). The Empty()
method returns an empty collection of a specified type as shown below.
Example: Enumerable.Empty()
var emptyCollection1 = Enumerable.Empty<string>();
var emptyCollection2 = Enumerable.Empty<Student>();
The Range() method returns a collection of IEnumerable<T> type with specified number of
elements and sequential values starting from the first element.
Example: Enumerable.Range()
var intCollection = Enumerable.Range(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());
Repeat
The Repeat() method generates a collection of IEnumerable<T> type with specified number
of elements and each element contains same specified value.
Example: Repeat
var intCollection = Enumerable.Repeat<int>(10, 10);
Console.WriteLine("Total Count: {0} ", intCollection.Count());
Set
Usage
Operators
Returns the difference between two sequences, which means the elements of one
Except
collection that do not appear in the second collection.
Returns the intersection of two sequences, which means elements that appear in
Intersect
both the collections.
Returns unique elements from two sequences, which means unique elements that
Union
appear in either of the two sequences.
The following figure shows how each set operators works on the collections:
LINQ Set operators
Distinct
The Distinct extension method returns a new collection of unique elements from the given
collection.
Example: Distinct C#
IList<string> strList = new List<string>(){ "One", "Two", "Three", "Two",
"Three" };
foreach(var i in distinctList2)
Console.WriteLine(i);
Output:
One
Two
Three
1
2
3
4
5
The Distinct extension method doesn't compare values of complex type objects. You need
to implement IEqualityComparer<T> interface in order to compare the values of complex
types. In the following example, StudentComparer class implements
IEqualityComparer<Student> to compare Student< objects.
return false;
}
Now, you can pass an object of the above StudentComparer class in the Distinct() method
as a parameter to compare the Student objects as shown below.
Example: Distinct in C#
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 }
,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
var distinctStudents = studentList.Distinct(new StudentComparer());
The Distinct operator is Not Supported in C# Query syntax. However, you can use
Distinct method of query variable or wrap whole query into brackets and then call
Distinct().
return false;
}
Now, you can pass above StudentComparer class in Except extension method in order to
get the correct result:
The Except operator is Not Supported in C# & VB.Net Query syntax. However, you can
use Distinct method on query variable or wrap whole query into brackets and then call
Except().
The following figure shows how each set operators works on the collections:
The Intersect extension method doesn't return the correct result for the collection of
complex types. You need to implement IEqualityComparer interface in order to get the
correct result from Intersect method.
return false;
}
Now, you can pass above StudentComparer class in the Intersect extension method in order
to get the correct result:
The Intersect operator is Not Supported in C# & VB.Net Query syntax. However, you can
use the Intersect method on a query variable or wrap whole query into brackets and then
call Intersect().
The following figure shows how each set operators works on the collections:
The Union extension method doesn't return the correct result for the collection of complex
types. You need to implement IEqualityComparer interface in order to get the correct result
from Union method.
return false;
}
Now, you can pass above StudentComparer class in the Union extension method to get the
correct result:
Example: Union operator C#
IList<Student> studentList1 = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 15 }
,
new Student() { StudentID = 3, StudentName = "Bill", Age =
25 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 19 }
};
Query Syntax
The Union operator is Not Supported in C# & VB.Net Query syntax. However, you can
use Union method on query variable or wrap whole query into brackets and then call
Union().
The following figure shows how each set operators works on the collections:
LINQ Set operators
Method Description
Skip Skips elements up to a specified position starting from the first element in a sequence.
Skips elements based on a condition until an element does not satisfy the condition. If
SkipWhile the first element itself doesn't satisfy the condition, it then skips 0 elements and
returns all the elements in the sequence.
Take Takes elements up to a specified position starting from the first element in a sequence.
Returns elements from the first element until an element does not satisfy the
TakeWhile condition. If the first element itself doesn't satisfy the condition then returns an empty
collection.
Skip
The Skip() method skips the specified number of element starting from first element and
returns rest of the elements.
Example: Skip() - C#
IList<string> strList = new List<string>(){ "One", "Two", "Three",
"Four", "Five" };
The Skip & SkipWhile operator is Not Supported in C# query syntax. However, you can
use Skip/SkipWhile method on a query variable or wrap whole query into brackets and then
call Skip/SkipWhile.
As the name suggests, the SkipWhile() extension method in LINQ skip elements in the
collection till the specified condition is true. It returns a new collection that includes all the
remaining elements once the specified condition becomes false for any element.
The SkipWhile() method has two overload methods. One method accepts the predicate of
Func<TSource, bool> type and other overload method accepts the predicate
Func<TSource, int, bool> type that pass the index of an element.
In the following example, SkipWhile() method skips all elements till it finds a string whose
length is equal or more than 4 characters.
Example: SkipWhile in C#
IList<string> strList = new List<string>() {
"One",
"Two",
"Three",
"Four",
"Five",
"Six" };
var resultList = strList.SkipWhile(s => s.Length < 4);
In the above example, SkipWhile() skips first two elements because their length is less than
3 and finds third element whose length is equal or more than 4. Once it finds any element
whose length is equal or more than 4 characters then it will not skip any other elements
even if they are less than 4 characters.
Now, consider the following example where SkipWhile() does not skip any elements
because the specified condition is false for the first element.
Example: SkipWhile in C#
IList<string> strList = new List<string>() {
"Three",
"One",
"Two",
"Four",
"Five",
"Six" };
The second overload of SkipWhile passes an index of each elements. Consider the
following example.
In the above example, the lambda expression includes element and index of an elements as
a parameter. It skips all the elements till the length of a string element is greater than it's
index.
Skip & SkipWhile operator is NOT Supported in C# query syntax. However, you can use
Skip/SkipWhile method on a query variable or wrap whole query into brackets and then
call Skip/SkipWhile().
Example: Take() in C#
IList<string> strList = new List<string>(){ "One", "Two", "Three",
"Four", "Five" };
Take & TakeWhile operator is Not Supported in C# query syntax. However, you can use
Take/TakeWhile method on query variable or wrap whole query into brackets and then call
Take/TakeWhile().
The TakeWhile() extension method returns elements from the given collection until the
specified condition is true. If the first element itself doesn't satisfy the condition then
returns an empty collection.
The TakeWhile method has two overload methods. One method accepts the predicate of
Func<TSource, bool> type and the other overload method accepts the predicate
Func<TSource, int, bool> type that passes the index of element.
In the following example, TakeWhile() method returns a new collection that includes all the
elements till it finds a string whose length less than 4 characters.
Example: TakeWhile in C#
IList<string> strList = new List<string>() {
"Three",
"Four",
"Five",
"Hundred" };
In the above example, TakeWhile() includes only first element because second string
element does not satisfied the condition.
Conversion Operators
The Conversion operators in LINQ are useful in converting the type of the elements in a
sequence (collection). There are three types of conversion operators: As operators
(AsEnumerable and AsQueryable), To operators (ToArray, ToDictionary, ToList and
ToLookup), and Casting operators (Cast and OfType).
Method Description
IEnumerable<T>)
ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.AsEnumerable());
ReportTypeProperties(studentArray.AsQueryable());
}
}
Output:
Compile-time type: Student[]
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1
As you can see in the above example AsEnumerable and AsQueryable methods convert
compile time type to IEnumerable and IQueryable respectively
Cast
Cast does the same thing as AsEnumerable<T>. It cast the source object into
IEnumerable<T>.
ReportTypeProperties( studentArray);
ReportTypeProperties(studentArray.Cast<Student>());
}
}
Output:
Compile-time type: Student[]
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
Compile-time type: IEnumerable`1
Actual type: Student[]
As the name suggests, ToArray(), ToList(), ToDictionary() method converts a source object
into an array, List or Dictionary respectively.
To operators force the execution of the query. It forces the remote query provider to
execute a query and get the result from the underlying data source e.g. SQL Server
database.
The following figure shows how studentDict in the above example contains a key-value
pair, where key is a StudentID and the value is Student object.
LINQ-ToDictionary Operator
Expression in LINQ
We have learned that the lambda Expression can be assigned to the Func or Action type
delegates to process over in-memory collections. The .NET compiler converts the lambda
expression assigned to Func or Action type delegate into executable code at compile time.
LINQ introduced the new type called Expression that represents strongly typed lambda
expression. It means lambda expression can also be assigned to Expression<TDelegate>
type. The .NET compiler converts the lambda expression which is assigned to
Expression<TDelegate> into an Expression tree instead of executable code. This expression
tree is used by remote LINQ query providers as a data structure to build a runtime query
out of it (such as LINQ-to-SQL, EntityFramework or any other LINQ query provider that
implements IQueryable<T> interface).
The following figure illustrates differences when the lambda expression assigned to the
Func or Action delegate and the Expression in LINQ.
Expression and Func
We will learn Expression tree in the next section but first, let's see how to define and
invoke an Expression.
Define an Expression
For example, you can assign lambda expression to the isTeenAger variable of Func type
delegate, as shown below:
Func<Student, bool> isTeenAger = s => s.Age > 12 && s.Age < 20;
Example: Define Func delegate for an expression in VB.Net
Dim isTeenAger As Func(Of Student, Boolean) = Function(s) s.Age > 12 And
s.Age < 20
And now, you can convert the above Func type delegate into an Expression by wrapping
Func delegate with Expresson, as below:
Thus, you can define Expression<TDelegate> type. Now, let's see how to invoke delegate
wrapped by an Expression<TDelegate>.
Invoke an Expression
You can invoke the delegate wrapped by an Expression the same way as a delegate, but
first you need to compile it using the Compile() method. Compile() returns delegateof Func
or Action type so that you can invoke it like a delegate.
//Invoke
bool result = isTeenAger(new Student(){ StudentID = 1, StudentName =
"Steve", Age = 20});
Example: Invoke Expression in VB.Net
Dim isTeenAgerExpr As Expression(Of Func(Of Student, Boolean)) =
Function(s) s.Age >
12 And s.Age < 20
Expression Tree
You have learned about the Expression in the previous section. Now, let's learn about the
Expresion tree here.
Expression tree as name suggests is nothing but expressions arranged in a tree-like data
structure. Each node in an expression tree is an expression. For example, an expression tree
can be used to represent mathematical formula x < y where x, < and y will be represented
as an expression and arranged in the tree like structure.
The expression tree makes the structure of the lambda expression transparent and explicit.
You can interact with the data in the expression tree just as you can with any other data
structure.
Example: Expression in C#
Expression<Func<Student, bool>> isTeenAgerExpr = s => s.age > 12 && s.age
< 20;
The compiler will translate the above expression into the following expression tree:
You can also build an expression tree manually. Let's see how to build an expression tree
for the following simple lambda expression:
This Func type delegate will be treated like the following method:
C#:
public bool function(Student s)
{
return s.Age > 18;
}
To create the expression tree, first of all, create a parameter expression where Student is the
type of the parameter and 's' is the name of the parameter as below:
Now, use Expression.Property() to create s.Age expression where s is the parameter and
Age is the property name of Student. (Expression is an abstract class that contains static
helper methods to create the Expression tree manually.)
Till now, we have built expression trees for s.Age (member expression) and 18 (constant
expression). We now need to check whether a member expression is greater than a constant
expression or not. For that, use the Expression.GreaterThanOrEqual() method and pass the
member expression and constant expression as parameters:
Thus, we have built an expression tree for a lambda expression body s.Age >= 18. We now
need to join the parameter and body expressions. Use Expression.Lambda(body, parameters
array) to join the body and parameter part of the lambda expression s => s.age >= 18:
This way you can build an expression tree for simple Func delegates with a lambda
expression.
The following image illustrates the whole process of creating an expression tree:
Construct Expression Tree
We have seen in the previous section that the lambda expression assigned to Func<T>
compiles into executable code and the lambda expression assigned to
Expression<TDelegate> type compiles into Expression tree.
Executable code excutes in the same application domain to process over in-memory
collection. Enumerable static classes contain extension methods for in-memory collections
that implements IEnumerable<T> interface e.g. List<T>, Dictionary<T>, etc. The
Extension methods in an Enumerable class accept a predicate parameter of Func type
delegate. For example, the Where extension method accepts Func<TSource, bool>
predicate. It then compiles it into IL (Intermediate Language) to process over in-memory
collections that are in the same AppDomain.
The following image shows Where extension method in Enumerable class includes Func
delegate as a parameter:
Func delegate is for in-memory collections because it will be processed in the same
AppDomain, but what about remote LINQ query providers like LINQ-to-SQL,
EntityFramework or other third party products that provides LINQ capabilities? How
would they parse lambda expression that has been compiled into raw executable code to
know about the parameters, return type of lambda expression and build runtime query to
process further? The answer is Expression tree.
If you debug the code, Expression delegate will be represented as shown below:
Now you can see the difference between a normal delegate and an Expression. An
expression tree is transparent. You can retrieve a parameter, return type and body
expression information from the expression, as below:
LINQ query for LINQ-to-SQL or Entity Framework is not executed in the same app
domain. For example, the following LINQ query for Entity Framework is never actually
executed inside your program:
It is first translated into an SQL statement and then executed on the database server.
The code found in a query expression has to be translated into an SQL query that can be
sent to another process as a string. For LINQ-to-SQL or Entity Frameworks, that process
happens to be an SQL server database. It is obviously going to be much easier to translate a
data structure such as an expression tree into SQL than it is to translate raw IL or
executable code into SQL because, as you have seen, it is easy to retrieve information from
an expression.
Expression trees were created for the task of converting code such as a query expression
into a string that can be passed to some other process and executed there.
Queryable static class includes extension methods that accept a predicate parameter of
Expression type. This predicate expression will be converted into an Expression Tree and
then will be passed to the remote LINQ provider as a data structure so that the provider can
build an appropriate query from the expression tree and execute the query.
Expression Tree Process
Deferred Execution
In the above example, you can see the query is materialized and executed when you iterate
using the foreach loop. This is called deferred execution. LINQ processes the studentList
collection when you actually access each object from the collection and do something with
it.
To check whether deferred execution returns the latest data each time, add one more teen
ager student after the foreach loop and check the teenager student list:
Deferred Execution
As you can see, the second foreach loop executes the query again and returns the latest
data. Deferred execution re-evaluates on each execution; this is called lazy evaluation.
This is one of the major advantages of deferred execution: it always gives you the latest
data.
Implementing Deferred Execution
You can implement deferred execution for your custom extension methods for
IEnumerable using the yield keyword of C#.
For example, you can implement custom extension method GetTeenAgerStudents for
IEnumerable that returns a list of all students who are teenagers.
Notice that we print the student name on the console whenever GetTeenAgerStudents() gets
called.
C#:
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", age = 13
} ,
new Student() { StudentID = 2, StudentName = "Steve", age =
15 } ,
new Student() { StudentID = 3, StudentName = "Bill", age =
18 } ,
new Student() { StudentID = 4, StudentName = "Ram" , age = 12
} ,
new Student() { StudentID = 5, StudentName = "Ron" , age = 21
}
};
As you can see from the output, GetTeenAgerStudents() is getting called when you iterate
studentList using the foreach loop.
Deferred Execution
So, in this way you can create custom methods using the yield keyword to get the
advantage of deferred execution.
Method Syntax
In the following example, ToList() extension method executes the query immediately and
returns the result.
Query Syntax
C#:
var teenAgerStudents = from s in studentList
where s.age > 12 && s.age < 20
select s;
The above query will not execute immediately. You won't find any result as shown below:
Immediate Execution
Query Syntax doesn't support 'To' operators but can use ToList(), ToArray() or
ToDictionary() for immediate execution as below:
C#:
IList<Student> teenAgerStudents = (from s in studentList
where s.age > 12 && s.age < 20
select s).ToList();
VB.Net:
Dim teenAgerStudents As IList(Of Student) = (From s In studentList _
Where s.Age > 12 And s.Age < 20 _
Select s).ToList()
Immediate Execution
Further Reading
Charlies' blog
MSDN
let keyword
The 'let' keyword is useful in query syntax. It projects a new range variable, allows re-use
of the expression and makes the query more readable.
For example, you can compare string values and select the lowercase string value as shown
below:
As you can see, the ToLower() method is used multiple times in the above query. The
following example use 'let' to introduce new variable 'lowercaseStudentName' that will be
then used in every where. Thus, let keyword to make the query more readable.
into keyword
We have already used the 'into' keyword in grouping. You can also use the 'into' keyword to
continue a query after a select clause.
In the above query, the 'into' keyword introduced a new range variable teenStudents, so the
first range variable s goes out of scope. You can write a further query after the into
keyword using a new range variable.
Sample Collections:
IList<Student> studentList = new List<Student>() {
new Student() { StudentID = 1, StudentName = "John", Age = 18,
StandardID = 1 } ,
new Student() { StudentID = 2, StudentName = "Steve", Age = 21,
StandardID = 1 } ,
new Student() { StudentID = 3, StudentName = "Bill", Age = 18,
StandardID = 2 } ,
new Student() { StudentID = 4, StudentName = "Ram" , Age = 20,
StandardID = 2 } ,
new Student() { StudentID = 5, StudentName = "Ron" , Age = 21 }
};
The following query returns Enumerable of anonymous object that has only StudentName
property:
Group By
To remove a student who doesn't have a StandardID, use a where operator before the group
operator:
Use left outer join to display students under each standard. Display the standard name even
if there is no student assigned to that standard.
group.Students.ToList().ForEach(st =>
Console.WriteLine(st.StudentName));
}
Output:
Standard 1:
John
Steve
Standard 2:
Bill
Ram
Standard 3:
In the following example of group by query, we sort the group and select only
StudentName:
Sorting
The following query returns list of students by ascending order of StandardID and Age.
Example: Sorting
var sortedStudents = from s in studentList
orderby s.StandardID, s.age
select new {
StudentName = s.StudentName,
Age = s.age,
StandardID = s.StandardID };
Inner Join
Example: LINQ Inner join - C#
var studentWithStandard = from s in studentList
join stad in standardList
on s.StandardID equals stad.StandardID
select new {
StudentName = s.StudentName,
StandardName = stad.StandardName
};
Nested Query
C#:
var nestedQueries = from s in studentList
where s.age > 18 && s.StandardID ==
(from std in standardList
where std.StandardName == "Standard 1"
select std.StandardID).FirstOrDefault()
select s;
http://www.tutorialsteacher.com/linq/linq-useful-resources