CREATING WEB API IN ASP.NET CORE 2.0

CREATING WEB API IN ASP.NET CORE 2.0

Introduction
Let’s create a Web API with the latest version of ASP.NET Core and Entity Framework Core.
In this guide, we’ll use WideWorldImporters database to create a Web API.
REST APIs provide at least the following operations:
  • GET
  • POST
  • PUT
  • DELETE
There are other operations for REST, but they aren’t necessary for this guide.
Those operations allow clients to perform actions through REST API, so our Web API must contain those operations.
WideWorldImporters database contains 4 schemas:
Application Purchasing Sales Warehouse
In this guide, we’ll work with Warehouse.StockItems table. We’ll add code to work with this entity: allow to retrieve stock items, retrieve stock item by id, create, update and delete stock items from database.
The version for this API is 1.
This is the route table for API:
VERB URL DESCRIPTION
GET api/v1/Warehouse/StockItem Retrieves stock items
GET api/v1/Warehouse/StockItem/id Retrieves a stock item by id
POST api/v1/Warehouse/StockItem Creates a new stock item
PUT api/v1/Warehouse/StockItem/id Updates an existing stock item
DELETE api/v1/Warehouse/StockItem/id Deletes an existing stock item
Keep these routes in mind because API must implement all routes.

Prerequisites

Software
  • .NET Core
  • NodeJS
  • Visual Studio 2017 with last update
  • SQL Server
  • WideWorldImporters database
Skills
  • C#
  • ORM (Object Relational Mapping)
  • TDD (Test Driven Development)
  • RESTful services

Using the Code

For this guide, the working directory for source code is C:\Projects.
Also, This is the GitHub repository for this guide.

Step 01 – Create Project

Open Visual Studio and follow these steps:
Go to File > New > Project
Go to Installed > Visual C# > .NET Core
Set the name for project as WideWorldImporters.API
Click OK
Create Project
In the next window, select API and the latest version for .ASP.NET Core, in this case is 2.1:
Configuration for API
Once Visual Studio has finished with creation for solution, we’ll see this window:
Overview for Api

Step 02 – Install Nuget Packages

In this step, We need to install the following NuGet packages:
* EntityFrameworkCore.SqlServer
* Swashbuckle.AspNetCore
Now, we’ll proceed to install EntityFrameworkCore.SqlServer package from Nuget, right click on WideWorldImporters.API project:
Manage NuGet Packages
Change to Browse tab and type Microsoft.EntityFrameworkCore.SqlServer:
Install EF Core Package
Next, install Swashbuckle.AspNetCore package:
Install Swashbuckle Package
This is the structure for project.
Now run the project to check if solution is ready, press F5 and Visual Studio will show this browser window:
First Run
By default, Visual Studio adds a file with name ValuesController in Controllers directory, remove it from project.

Step 03 – Add Models

Now, create a directory with name Models and add the following files:
Entities.cs
Extensions.cs
Requests.cs
Responses.cs
Entities.cs will contains all code related to Entity Framework Core.
Extensions.cs will contain the extension methods for DbContext.
Requests.cs will contain definitions for request models.
Responses.cs will contain definitions for response models.
Code for Entities.cs file:
using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace WideWorldImporters.API.Models
{
#pragma warning disable CS1591
public partial class StockItem
{
public StockItem()
{
}

public StockItem(int? stockItemID)
{
StockItemID = stockItemID;
}

public int? StockItemID { get; set; }

public string StockItemName { get; set; }

public int? SupplierID { get; set; }

public int? ColorID { get; set; }

public int? UnitPackageID { get; set; }

public int? OuterPackageID { get; set; }

public string Brand { get; set; }

public string Size { get; set; }

public int? LeadTimeDays { get; set; }

public int? QuantityPerOuter { get; set; }

public bool? IsChillerStock { get; set; }

public string Barcode { get; set; }

public decimal? TaxRate { get; set; }

public decimal? UnitPrice { get; set; }

public decimal? RecommendedRetailPrice { get; set; }

public decimal? TypicalWeightPerUnit { get; set; }

public string MarketingComments { get; set; }

public string InternalComments { get; set; }

public string CustomFields { get; set; }

public string Tags { get; set; }

public string SearchDetails { get; set; }

public int? LastEditedBy { get; set; }

public DateTime? ValidFrom { get; set; }

public DateTime? ValidTo { get; set; }
}

public class StockItemsConfiguration : IEntityTypeConfiguration<StockItem>
{
public void Configure(EntityTypeBuilder builder)
{
// Set configuration for entity
builder.ToTable("StockItems", "Warehouse");

// Set key for entity
builder.HasKey(p => p.StockItemID);

// Set configuration for columns

builder.Property(p => p.StockItemName).HasColumnType("nvarchar(200)").IsRequired();
builder.Property(p => p.SupplierID).HasColumnType("int").IsRequired();
builder.Property(p => p.ColorID).HasColumnType("int");
builder.Property(p => p.UnitPackageID).HasColumnType("int").IsRequired();
builder.Property(p => p.OuterPackageID).HasColumnType("int").IsRequired();
builder.Property(p => p.Brand).HasColumnType("nvarchar(100)");
builder.Property(p => p.Size).HasColumnType("nvarchar(40)");
builder.Property(p => p.LeadTimeDays).HasColumnType("int").IsRequired();
builder.Property(p => p.QuantityPerOuter).HasColumnType("int").IsRequired();
builder.Property(p => p.IsChillerStock).HasColumnType("bit").IsRequired();
builder.Property(p => p.Barcode).HasColumnType("nvarchar(100)");
builder.Property(p => p.TaxRate).HasColumnType("decimal(18, 3)").IsRequired();
builder.Property(p => p.UnitPrice).HasColumnType("decimal(18, 2)").IsRequired();
builder.Property(p => p.RecommendedRetailPrice).HasColumnType("decimal(18, 2)");
builder.Property(p => p.TypicalWeightPerUnit).HasColumnType("decimal(18, 3)").IsRequired();
builder.Property(p => p.MarketingComments).HasColumnType("nvarchar(max)");
builder.Property(p => p.InternalComments).HasColumnType("nvarchar(max)");
builder.Property(p => p.CustomFields).HasColumnType("nvarchar(max)");
builder.Property(p => p.LastEditedBy).HasColumnType("int").IsRequired();

// Computed columns

builder
.Property(p => p.StockItemID)
.HasColumnType("int")
.IsRequired()
.HasComputedColumnSql("NEXT VALUE FOR [Sequences].[StockItemID]");

builder
.Property(p => p.Tags)
.HasColumnType("nvarchar(max)")
.HasComputedColumnSql("json_query([CustomFields],N'$.Tags')");

builder
.Property(p => p.SearchDetails)
.HasColumnType("nvarchar(max)")
.IsRequired()
.HasComputedColumnSql("concat([StockItemName],N' ',[MarketingComments])");

// Columns with generated value on add or update

builder
.Property(p => p.ValidFrom)
.HasColumnType("datetime2")
.IsRequired()
.ValueGeneratedOnAddOrUpdate();

builder
.Property(p => p.ValidTo)
.HasColumnType("datetime2")
.IsRequired()
.ValueGeneratedOnAddOrUpdate();
}
}

public class WideWorldImportersDbContext : DbContext
{
public WideWorldImportersDbContext(DbContextOptions options)
: base(options)

{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
// Apply configurations for entity

modelBuilder
.ApplyConfiguration(new StockItemsConfiguration());

base.OnModelCreating(modelBuilder);
}

public DbSet StockItems { get; set; }
}
#pragma warning restore CS1591
}
Code for Extensions.cs file:
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;

namespace WideWorldImporters.API.Models
{
#pragma warning disable CS1591
public static class WideWorldImportersDbContextExtensions
{
public static IQueryable GetStockItems(this WideWorldImportersDbContext dbContext, int pageSize = 10, int pageNumber = 1, int? lastEditedBy = null, int? colorID = null, int? outerPackageID = null, int? supplierID = null, int? unitPackageID = null)
{
// Get query from DbSet
var query = dbContext.StockItems.AsQueryable();

// Filter by: 'LastEditedBy'
if (lastEditedBy.HasValue)
query = query.Where(item => item.LastEditedBy == lastEditedBy);

// Filter by: 'ColorID'
if (colorID.HasValue)
query = query.Where(item => item.ColorID == colorID);

// Filter by: 'OuterPackageID'
if (outerPackageID.HasValue)
query = query.Where(item => item.OuterPackageID == outerPackageID);

// Filter by: 'SupplierID'
if (supplierID.HasValue)
query = query.Where(item => item.SupplierID == supplierID);

// Filter by: 'UnitPackageID'
if (unitPackageID.HasValue)
query = query.Where(item => item.UnitPackageID == unitPackageID);

return query;
}

public static async Task GetStockItemsAsync(this WideWorldImportersDbContext dbContext, StockItem entity)
=> await dbContext.StockItems.FirstOrDefaultAsync(item => item.StockItemID == entity.StockItemID);

public static async Task GetStockItemsByStockItemNameAsync(this WideWorldImportersDbContext dbContext, StockItem entity)
=> await dbContext.StockItems.FirstOrDefaultAsync(item => item.StockItemName == entity.StockItemName);
}

public static class IQueryableExtensions
{
public static IQueryable Paging(this IQueryable query, int pageSize = 0, int pageNumber = 0) where TModel : class
=> pageSize > 0 && pageNumber > 0 ? query.Skip((pageNumber - 1) * pageSize).Take(pageSize) : query;
}
#pragma warning restore CS1591
}
Code for Requests.cs file:
using System;
using System.ComponentModel.DataAnnotations;

namespace WideWorldImporters.API.Models
{
#pragma warning disable CS1591
public class PostStockItemsRequest
{
[Key]
public int? StockItemID { get; set; }

[Required]
[StringLength(200)]
public string StockItemName { get; set; }

[Required]
public int? SupplierID { get; set; }

public int? ColorID { get; set; }

[Required]
public int? UnitPackageID { get; set; }

[Required]
public int? OuterPackageID { get; set; }

[StringLength(100)]
public string Brand { get; set; }

[StringLength(40)]
public string Size { get; set; }

[Required]
public int? LeadTimeDays { get; set; }

[Required]
public int? QuantityPerOuter { get; set; }

[Required]
public bool? IsChillerStock { get; set; }

[StringLength(100)]
public string Barcode { get; set; }

[Required]
public decimal? TaxRate { get; set; }

[Required]
public decimal? UnitPrice { get; set; }

public decimal? RecommendedRetailPrice { get; set; }

[Required]
public decimal? TypicalWeightPerUnit { get; set; }

public string MarketingComments { get; set; }

public string InternalComments { get; set; }

public string CustomFields { get; set; }

public string Tags { get; set; }

[Required]
public string SearchDetails { get; set; }

[Required]
public int? LastEditedBy { get; set; }

public DateTime? ValidFrom { get; set; }

public DateTime? ValidTo { get; set; }
}

public class PutStockItemsRequest
{
[Required]
[StringLength(200)]
public string StockItemName { get; set; }

[Required]
public int? SupplierID { get; set; }

public int? ColorID { get; set; }

[Required]
public decimal? UnitPrice { get; set; }
}

public static class Extensions
{
public static StockItem ToEntity(this PostStockItemsRequest request)
=> new StockItem
{
StockItemID = request.StockItemID,
StockItemName = request.StockItemName,
SupplierID = request.SupplierID,
ColorID = request.ColorID,
UnitPackageID = request.UnitPackageID,
OuterPackageID = request.OuterPackageID,
Brand = request.Brand,
Size = request.Size,
LeadTimeDays = request.LeadTimeDays,
QuantityPerOuter = request.QuantityPerOuter,
IsChillerStock = request.IsChillerStock,
Barcode = request.Barcode,
TaxRate = request.TaxRate,
UnitPrice = request.UnitPrice,
RecommendedRetailPrice = request.RecommendedRetailPrice,
TypicalWeightPerUnit = request.TypicalWeightPerUnit,
MarketingComments = request.MarketingComments,
InternalComments = request.InternalComments,
CustomFields = request.CustomFields,
Tags = request.Tags,
SearchDetails = request.SearchDetails,
LastEditedBy = request.LastEditedBy,
ValidFrom = request.ValidFrom,
ValidTo = request.ValidTo
};
}
#pragma warning restore CS1591
}
Code for Responses.cs file:
using System.Collections.Generic;
using System.Net;
using Microsoft.AspNetCore.Mvc;

namespace WideWorldImporters.API.Models
{
#pragma warning disable CS1591
public interface IResponse
{
string Message { get; set; }

bool DidError { get; set; }

string ErrorMessage { get; set; }
}

public interface ISingleResponse<TModel> : IResponse
{
TModel Model { get; set; }
}

public interface IListResponse<TModel> : IResponse
{
IEnumerable Model { get; set; }
}

public interface IPagedResponse<TModel> : IListResponse<TModel>
{
int ItemsCount { get; set; }

double PageCount { get; }
}

public class Response : IResponse
{
public string Message { get; set; }

public bool DidError { get; set; }

public string ErrorMessage { get; set; }
}

public class SingleResponse<TModel> : ISingleResponse<TModel>
{
public string Message { get; set; }

public bool DidError { get; set; }

public string ErrorMessage { get; set; }

public TModel Model { get; set; }
}

public class ListResponse<TModel> : IListResponse<TModel>
{
public string Message { get; set; }

public bool DidError { get; set; }

public string ErrorMessage { get; set; }

public IEnumerable Model { get; set; }
}

public class PagedResponse<TModel> : IPagedResponse<TModel>
{
public string Message { get; set; }

public bool DidError { get; set; }

public string ErrorMessage { get; set; }

public IEnumerable Model { get; set; }

public int PageSize { get; set; }

public int PageNumber { get; set; }

public int ItemsCount { get; set; }

public double PageCount
=> ItemsCount < PageSize ? 1 : (int)(((double)ItemsCount / PageSize) + 1);
}

public static class ResponseExtensions
{
public static IActionResult ToHttpResponse(this IResponse response)
{
var status = response.DidError ? HttpStatusCode.InternalServerError : HttpStatusCode.OK;

return new ObjectResult(response)
{
StatusCode = (int)status
};
}

public static IActionResult ToHttpResponse(this ISingleResponse response)
{
var status = HttpStatusCode.OK;

if (response.DidError)
status = HttpStatusCode.InternalServerError;
else if (response.Model == null)
status = HttpStatusCode.NotFound;

return new ObjectResult(response)
{
StatusCode = (int)status
};
}

public static IActionResult ToHttpResponse(this IListResponse response)
{
var status = HttpStatusCode.OK;

if (response.DidError)
status = HttpStatusCode.InternalServerError;
else if (response.Model == null)
status = HttpStatusCode.NoContent;

return new ObjectResult(response)
{
StatusCode = (int)status
};
}
}
#pragma warning restore CS1591
}
Understanding Models
ENTITIES
StockItems class is the representation for Warehouse.StockItems table.
StockItemsConfiguration class contains the mapping for StockItems class.
WideWorldImportersDbContext class is the link between database and C# code, this class handles queries and commits the changes in database and of course, another things.
EXTENSIONS
WideWorldImportersDbContextExtensions contains extension methods to provide linq queries.
IQueryableExtensions contains extension methods to allow paging in IQueryable instances.
REQUESTS
We have the following definitions:
PostStockItemsRequest
PutStockItemsRequest
PostStockItemsRequestModel represents the model to create a new stock item, contains all required properties to save in database.
PutStockItemsRequestModel represents the model to update an existing stock item, in this case contains only 4 properties: StockItemName, SupplierID, ColorID and UnitPrice. This class doesn’t contain StockItemID property because id is in route for controller’s action.
The models for requests do not require to contain all properties like entities, because we don’t need to expose full definition in a request or response, it’s a good practice to limit data using models with few properties.
Extensions class contains an extension method for PostStockItemsRequestModel, to return an instance of StockItem class from request model.
RESPONSES
These are the interfaces:
IResponse
ISingleResponse
IListResponse
IPagedResponse
Each one of these interfaces has implementations, why do we need these definitions if it’s more simple to return objects without wrapping them in these models? Keep in mind this Web API will provide operations for clients, with UI or without UI and it’s more easy to have properties to send message, to have a model or send information if an error occurs, in addition, we set Http status code in response to describe the result from request.
These classes are generic, because in this way, we save time to define responses in future, this Web API only returns a response for a single entity, a list and a paged list.
ISingleResponse represents a response for a single entity.
IListResponse represents a response with a list, for example all shipping to existing order without paging.
IPagedResponse represents a response with pagination, for example all orders in a date range.
ResponseExtensions class contains extension methods to convert a response in a Http response, these methods return InternalServerError (500) status if an error occurs, OK (200) if it’s OK and NotFound (404) if an entity does not exist in database or NoContent (204) for list responses without model.

Step 04 – Add Controller

Now, inside of Controllers directory, add a code file with name WarehouseController.cs and add this code:
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using WideWorldImporters.API.Models;

namespace WideWorldImporters.API.Controllers
{
#pragma warning disable CS1591
[ApiController]
[Route("api/v1/[controller]")]
public class WarehouseController : ControllerBase
{
protected readonly ILogger Logger;
protected readonly WideWorldImportersDbContext DbContext;

public WarehouseController(ILogger logger, WideWorldImportersDbContext dbContext)
{
Logger = logger;
DbContext = dbContext;
}
#pragma warning restore CS1591

// GET
// api/v1/Warehouse/StockItem

///
/// Retrieves stock items
///

/// Page size
/// Page number
/// Last edit by (user id)
/// Color id
/// Outer package id
/// Supplier id
/// Unit package id
/// A response with stock items list
/// Returns the stock items list
/// If there was an internal server error
[HttpGet("StockItem")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task GetStockItemsAsync(int pageSize = 10, int pageNumber = 1, int? lastEditedBy = null, int? colorID = null, int? outerPackageID = null, int? supplierID = null, int? unitPackageID = null)
{
Logger?.LogDebug("'{0}' has been invoked", nameof(GetStockItemsAsync));

var response = new PagedResponse();

try
{
// Get the "proposed" query from repository
var query = DbContext.GetStockItems();

// Set paging values
response.PageSize = pageSize;
response.PageNumber = pageNumber;

// Get the total rows
response.ItemsCount = await query.CountAsync();

// Get the specific page from database
response.Model = await query.Paging(pageSize, pageNumber).ToListAsync();

response.Message = string.Format("Page {0} of {1}, Total of products: {2}.", pageNumber, response.PageCount, response.ItemsCount);

Logger?.LogInformation("The stock items have been retrieved successfully.");
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = "There was an internal error, please contact to technical support.";

Logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(GetStockItemsAsync), ex);
}

return response.ToHttpResponse();
}

// GET
// api/v1/Warehouse/StockItem/5

///
/// Retrieves a stock item by ID
///

/// Stock item id
/// A response with stock item
/// Returns the stock items list
/// If stock item is not exists
/// If there was an internal server error
[HttpGet("StockItem/{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(404)]
[ProducesResponseType(500)]
public async Task GetStockItemAsync(int id)
{
Logger?.LogDebug("'{0}' has been invoked", nameof(GetStockItemAsync));

var response = new SingleResponse();

try
{
// Get the stock item by id
response.Model = await DbContext.GetStockItemsAsync(new StockItem(id));
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = "There was an internal error, please contact to technical support.";

Logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(GetStockItemAsync), ex);
}

return response.ToHttpResponse();
}

// POST
// api/v1/Warehouse/StockItem/

///
/// Creates a new stock item
///

/// Request model
/// A response with new stock item
/// Returns the stock items list
/// A response as creation of stock item
/// For bad request
/// If there was an internal server error
[HttpPost("StockItem")]
[ProducesResponseType(200)]
[ProducesResponseType(201)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task PostStockItemAsync([FromBody]PostStockItemsRequest request)
{
Logger?.LogDebug("'{0}' has been invoked", nameof(PostStockItemAsync));

var response = new SingleResponse();

try
{
var existingEntity = await DbContext
.GetStockItemsByStockItemNameAsync(new StockItem { StockItemName = request.StockItemName });

if (existingEntity != null)
ModelState.AddModelError("StockItemName", "Stock item name already exists");

if (!ModelState.IsValid)
return BadRequest();

// Create entity from request model
var entity = request.ToEntity();

// Add entity to repository
DbContext.Add(entity);

// Save entity in database
await DbContext.SaveChangesAsync();

// Set the entity to response model
response.Model = entity;
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = "There was an internal error, please contact to technical support.";

Logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(PostStockItemAsync), ex);
}

return response.ToHttpResponse();
}

// PUT
// api/v1/Warehouse/StockItem/5

///
/// Updates an existing stock item
///

/// Stock item ID
/// Request model
/// A response as update stock item result
/// If stock item was updated successfully
/// For bad request
/// If there was an internal server error
[HttpPut("StockItem/{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(400)]
[ProducesResponseType(500)]
public async Task PutStockItemAsync(int id, [FromBody]PutStockItemsRequest request)
{
Logger?.LogDebug("'{0}' has been invoked", nameof(PutStockItemAsync));

var response = new Response();

try
{
// Get stock item by id
var entity = await DbContext.GetStockItemsAsync(new StockItem(id));

// Validate if entity exists
if (entity == null)
return NotFound();

// Set changes to entity
entity.StockItemName = request.StockItemName;
entity.SupplierID = request.SupplierID;
entity.ColorID = request.ColorID;
entity.UnitPrice = request.UnitPrice;

// Update entity in repository
DbContext.Update(entity);

// Save entity in database
await DbContext.SaveChangesAsync();
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = "There was an internal error, please contact to technical support.";

Logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(PutStockItemAsync), ex);
}

return response.ToHttpResponse();
}

// DELETE
// api/v1/Warehouse/StockItem/5

///
/// Deletes an existing stock item
///

/// Stock item ID
/// A response as delete stock item result
/// If stock item was deleted successfully
/// If there was an internal server error
[HttpDelete("StockItem/{id}")]
[ProducesResponseType(200)]
[ProducesResponseType(500)]
public async Task DeleteStockItemAsync(int id)
{
Logger?.LogDebug("'{0}' has been invoked", nameof(DeleteStockItemAsync));

var response = new Response();

try
{
// Get stock item by id
var entity = await DbContext.GetStockItemsAsync(new StockItem(id));

// Validate if entity exists
if (entity == null)
return NotFound();

// Remove entity from repository
DbContext.Remove(entity);

// Delete entity in database
await DbContext.SaveChangesAsync();
}
catch (Exception ex)
{
response.DidError = true;
response.ErrorMessage = "There was an internal error, please contact to technical support.";

Logger?.LogCritical("There was an error on '{0}' invocation: {1}", nameof(DeleteStockItemAsync), ex);
}

return response.ToHttpResponse();
}
}
}
The process for all controller’s actions is:
Log the invocation for method.
Create the instance for response according to action (Paged, list or single).
Perform access to database through DbContext instance.
If invocation for DbContext extension method fails, set DidError property as true and set ErrorMessage property with: There was an internal error, please contact to technical support., because it isn't recommended to expose error details in response, it's better to save all exception details in log file.
Return result as Http response.
Keep in mind all names for methods that end with Async sufix because all operations are async but in Http attributes, we don’t use this suffix.

Step 05 – Setting Up Dependency Injection

ASP.NET Core enables dependency injection in native way, this means we don’t need any 3rd party framework to inject dependencies in controllers.
This is a great challenge because we need to change our mind from Web Forms and ASP.NET MVC, for those technologies use a framework to inject dependencies it was a luxury, now in ASP.NET Core dependency injection is a basic aspect.
Project template for ASP.NET Core has a class with name Startup, in this class we must to add the configuration to inject instances for DbContext, Repositories, Loggers, etc.
Modify the code of Startup.cs file to look like this:
using System;
using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Swashbuckle.AspNetCore.Swagger;
using WideWorldImporters.API.Controllers;
using WideWorldImporters.API.Models;

namespace WideWorldImporters.API
{
#pragma warning disable CS1591
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; }

// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

// Add configuration for DbContext
// Use connection string from appsettings.json file
services.AddDbContext(options =>
{
options.UseSqlServer(Configuration["AppSettings:ConnectionString"]);
});

// Set up dependency injection for controller's logger
services.AddScoped<ILogger, Logger>();

// Register the Swagger generator, defining 1 or more Swagger documents
services.AddSwaggerGen(options =>
{
options.SwaggerDoc("v1", new Info { Title = "WideWorldImporters API", Version = "v1" });

// Get xml comments path
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);

// Set xml path
options.IncludeXmlComments(xmlPath);
});
}

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
app.UseDeveloperExceptionPage();

// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();

// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "WideWorldImporters API V1");
});

app.UseMvc();
}
}
#pragma warning restore CS1591
}
The ConfigureServices method specifies how dependencies will be resolved, in this method. We need to set up DbContext, Repositories and Logging.
The Configure method adds the configuration for Http request runtime.

Step 06 – Running Web API

Before you run Web API project, add the connection string in appsettings.json file:
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*",
"AppSettings": {
"ConnectionString": "server=(local);database=WideWorldImporters;integrated security=yes;"
}
}
In order to show descriptions in help page, enable XML documentation for your Web API project:
1. Right click on Project > Properties
2. Go to Build > Output
3. Enable XML documentation file
4. Save changes
Enable Xml Documentation File
Now, press F5 to start debugging for Web API project, if everything it’s OK, we’ll get the following output in the browser:
Get Stock Items In Browser
Help Page

 

Algorithm to find second largest number in arry

public class Demo { 
   public static void Main()  {
      int[] arr = new int[5] {99, 95, 93, 89, 87};
      int i, max, min, n;
      // size of the array
      n = 5;
      max = arr[0];
      min = arr[0];
      for(i=1; i<n; i++) {
         if(arr[i]>max) {
            max = arr[i];
         }
         if(arr[i]<min) {
            min = arr[i];
         }
      }
      Console.Write(“Maximum element = {0}\n”, max);
      Console.Write(“Minimum element = {0}\n\n”, min);
   }
}

second largest by Lamda
var numbers = new int[] { 3, 5, 1, 5, 4 };
var result=numbers.OrderByDescending(x=>x).Distinct().Skip(1).First();

Kestrel Webserver

What is Kestrel Web server?


Kestrel is an open source, cross platform, light weight and a default webserver used for Asp.Net Core applications. Asp.Net Core applications run Kestrel webserver as in-process server to handle web request. Kestrel webserver is based on async I/O library called libuv primarily developed for Node.js.
By default, all Asp.Net core project templates include Kestrel webserver when we create new Asp.Net Core Projects. As said before, Kestrel is a very light weight webserver that does not have every advanced features of webservers like IIS, Nginx, Apache, etc has. Due to its lightweight nature, Kestrel provides better request processing performance to Asp.Net Core applications. Some features of Kestrel,
  1. Kestrel does not support multiple applications sharing same port similar to IIS where applications are differentiated by host header value.
  2. Kestrel is cross platform, runs in Windows, LINUX and Mac.
  3. Kestrel webserver supports SSL.
Let’s get, why there is a new webserver called Kestrel when we already have a feature-rich and most used webserver IIS.

Why Kestrel Web server when we have IIS/Apache?

The primary requirement of Asp.Net Core is to make Asp.Net Core applications to run across multiple platforms (or cross platform). Though, IIS is feature rich and highly used web server it is a windows-only web server. Without Kestrel, to run Asp.Net Core application on other cross platform web servers like Nginx, Apache, the Asp.Net Core application need to satisfy the Startup criteria of each of these web servers. In other words, each web server has a different Startup configurations and this will make Asp.Net Core applications have different Startup mechanisms. This is why Asp.Net Core applications use Kestrel web server as an in-process server where the application will have same and consistent Startup (Main() and Startup.ConfigireServices() & Startup.Configure()) process even when offering cross platform support.
How to use Kestrel?
Kestrel server is by default included in the Asp.Net Core project templates. It is included in the project as a Nuget package Microsoft.AspNetCore.Server.Kestrel in Project.json(in Visual Studio 2015) and as an implicitly included package when you using Visual Studio 2017 project template.
Note – All Asp.Net Core project should use Visual Studio 2017 as it is the latest and default project template for Asp.Net Core projects henceforth. Read here to know more.
Let’s see how kestrel server is configured in an Asp.Net Core project. Below is the Program.Main() method in a Asp.Net Core application.
public class Program
{
public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseIISIntegration()
        .UseStartup()
        .UseApplicationInsights()
        .Build();

    host.Run();
}
}
In the above Main() method, calling UseKestrel() on WebHostBuilder object will configure the Kestrel webserver for the application.
Note – Every Asp.Net Core application requires a Host process to start Kestrel webserver and initialize application for request processing. Calling UseIISIntegration() integrates Kestrel with IIS webserver, let’s see this in detail in next section.
The UseKestrel() also takes KestrelServerOptions class as argument to customize Kestrel server.
Asp.Net Core Deployment Options
We generally deploy Asp.Net Core (also Asp.Net applications) for 2 scenarios listed below.
  1. Internal Hosted applications
  2. Externally Hosted applications
Let’s see how Kestrel webserver can be used in both of these scenarios.
  1. Internally Hosted applications
For internal applications, the applications can just be hosted with Kestrel webserver alone. The features provided by Kestrel and with some additional middlewares (for response compressions, authentication) is sufficient for serving internally hosted applications.  
  1. Externally Hosted applications
As it is said before, Kestrel is a very light webserver and it does not support all features of a full-fledged webserver like IIS provide. So, if your application is external facing public website then the application should be deployed behind a full-fledged webserver like IIS or Nginx or Apache for increased security and to get feature rich support. These webservers act as proxy (commonly called reverse proxy in this scenario) and forward the request to Kestrel for request processing. This is why the Program.Main() code calls UseIISIntegration() to integrate IIS as reverse proxy to forward request to Kestrel. This is the default mode the project template code uses.  The request flow goes like below,
Note – This requires IIS integration module commonly called Asp.Net Core module that comes with Nuget package Microsoft.AspNetCore.Server.IISIntegration
Executing the Asp.Net Core Application with Kestrel
We can start the Asp.Net application that uses Kestrel webserver in two ways. Assuming, you have created a default Asp.Net Core project in Visual Studio 2017.
  1. Visual Studio
By default, press F5 to start the application with IISExpress as reverse proxy. To start the application from Kestrel webserver click project name menu item in run dropdown like below. ASPNETCoreVS2017Demo is my project name.
This will start the app directly form Kestrel webserver.
  1. Dotnet CLI
You can also start the app from command prompt using dotnet CLI(Command Line Interface) provide by Asp.Net Core. To do this, open Command prompt and change directory to project root. Type the below command
dotnet run
This will start the app with Kestrel webserver and server will start listening to port 5000 by default. Refer the below image.
Visiting http://localhost:5000 will bring the application like below,

Oops Concepts in C#

OOPs Concepts

OOP is a technique to develop logical modules, such as classes that contains properties, fields and events. OOP provides many concepts such as inheritance, data binding, polymorphism etc.
Object means a real word entity such as pen,paper, chair, table etc.
 It simplifies the software development and maintenance by providing some concepts:
  1. Object
  2. Class
  3. Inheritance
  4. Polymorphism
  5. Abstraction
  6. Encapsulation

Object:

Any entity that has state and behavior is known as an object. For example: chair, pen, table, keyboard, bike etc. It can be physical and logical.

Class:

Collection of objects is called class. It is a logical entity.

Inheritance:

When one object acquires all the properties and behaviours of parent object i.e. known as inheritance. It provides code reusability. It is used to achieve runtime polymorphism.

Polymorphism:

When one task is performed by different ways i.e. known as polymorphism. For example:  to draw something e.g. shape or rectangle etc.
In C#, we use method overloading and method overriding to achieve polymorphism.
Abstraction:
Hiding internal details and showing functionality is known as abstraction. For example: phone call, we don’t know the internal processing.

Encapsulation:

Binding (or wrapping) code and data together into a single unit is known as encapsulation. For example: capsule, it is wrapped with different medicines.

C# Access Modifiers

Encapsulation in Object Oriented Programming C#

  • A software development technique in which each module’s interfaces reveal as little as possible about the module’s inner working and other modules are prevented from using information about the module that is not in the module’s interface specification.

What is Encapsulation ? 

  1. Encapsulation is a process of hiding the members from outside of class and implemented using access specifiers
  2. Encapsulation is also called as information hiding.
  3. Encapsulation provides a way to preserve the integrity of state data. Rather than defining public fields, private data fields should be defined.
  4. Well-encapsulated class should hide its data and the details of how it operates on data from the outside world. This is termed black box programming.
  5. Using this,implementation of the method can be changed by the class author without breaking any existing code making use of it.
An access specifier defines the scope and visibility of a class member. C# supports the following access specifiers:
  • Public
  • Private
  • Protected
  • Internal
  • Protected internal

Public Access Specifier:  

Public access specifier allows a class to expose its member variables and member functions to other functions and objects. Any public member can be accessed from outside the class.


Private Access Specifier: 

Private access specifier allows a class to hide its member variables and member functions from other functions and objects. Only functions of the same class can access its private members. Even an instance of a class cannot access its private members.

Protected Access Specifier:

Protected access specifier allows a child class to access the member variables and member functions of its base class. This way it helps in implementing inheritance

Internal Access Specifier:

Internal access specifier allows a class to expose its member variables and member functions to other functions and objects in the current assembly. In other words, any member with internal access specifier can be accessed from any class or method defined within the application in which the member is defined.

What is new in C# 7?

Here is an overview of new features in C#:
  • Out variables
  • Pattern matching
  • Tuples
  • Deconstruction
  • Discards
  • Local Functions
  • Binary Literals
  • Digit Separators
  • Ref returns and locals
  • Generalized async return types
  • More expression-bodied members
  • Throw expressions
  • // Out variables
    // Old way
    int parsedOld;
    string parseMeOld = 222224;
    int.TryParse(parseMeOld, out parsedOld);
    Console.WriteLine(parsedOld);
    // New way
    string parseMe = 3115;
    int.TryParse(parseMe, out int parsed);
    Console.WriteLine(parsed);

Tuples

List<int> numbers = new List<int> { 3, 5, 11, 4, 7 };
var result = GetLowestHighest(numbers);
Console.WriteLine(result.Item1); // ugly?
Console.WriteLine(result.Item2); // yeah, ugly..
// Notice the return type of the method. It’s tuple
private static(int, int) GetLowestHighest(IReadOnlyCollection < int > numbers) {
int lowest = numbers.Min(n => n);
int highest = numbers.Max(n => n);
return (lowest, highest);
}

Solved : we are unable to download content due to network issues Visual Studio

Issue  
1.  Visual Studio User account login failed when try to login.

Solution  

1. Right click on the visual studio > go to properties > shortcut tabs > click on Open File Location button and find “devenv.exe.config” open

 2.  Open devenv.config.exe and modify accordingly as below 

3.   Add the below details under system.net section in devenv.exe.config file 

 
<defaultProxy useDefaultCredentials=”trueenabled=“true”>
<proxy usesystemdefault=“true”/>
 
     
        <ipv6 enabled=“true”/>
<ServicePointManager except100Continue=“false”/>
     

   

4.  Finally, Close Visual Studio and Open, Login with User account, No error.

How to add twitter widget in blogspot ?

You can display your latest Tweets in your sidebar by pasting embed code for a Twitter widget in a text widget.
Here is an example of what it looks like:
Twitter Widget

ADD A TWITTER WIDGET

2.  Select what you want to embed.
  • For a User Timeline, enter the username of the user whose tweets you want to display.
Twitter username
  • For Lists, enter the URL of the list you want to display.
Twitter List
For a Hashtag or Search, you need to log into your Twitter account and then use Create A Search Widget.
3.  Choose your display option. We are using the Embedded Timeline option.
Select display option
4. Click on set customization option.
Click on Customize
5.  Set the height and width of the widget and click Update.  You can also change the widget color and default link color.
  • We recommend 600 high by 220 wide.
Customize the widget
6.  Copy the embed code.
Copy embed code
7. Click on the Text tab in the text widget in your sidebar.
Click on Text
8.  Paste the embed code from Twitter into the text widget.
Paste twitter embed code
9.   Click Save and Close.
10.  You should see a Twitter widget in your sidebar.

How to view deleted files in TFS Visual Studio?

Visual Studio TFS View Deleted Files


Have you ever wanted to view the deleted files or source code branch missing in visual studio

1.  Open Visual Studio 
2.  Go to Tools > Options  > Source Control
3.  Tick the Show deleted items in Source Control Explorer
4.  Click OK
5.  Now look for the deleted files. 

Resolved TFS Server is not working

Visual Studio TFS Server Not working 

Have you ever wondered how to resolve TFS Server not working correctly, please read till end to solve.

As a developer, when you work on daily basis, there might be a chance you would have worked with Fiddler Tool to capture .Net request/response from server that was required to add default proxy to machine.config file 

Solution 
Remove the tag from machine.config file and try connecting TFS Server. 

Cheers !



In General Fiddler is the free version tool available online, and one of the tools is 
Fiddler – Free Web Debugging Proxy – Telerik

1. Download Fiddler https://www.telerik.com/download/fiddler
2. To trace incoming from .Net project required to add .net settings in machine config file
3. Now the question is how to do ?
4. Open notepad as Run as Administrator 
5. Notepad File menu click on open and paste this code %WinDir%\Microsoft.NET\Framework\v2.0.50727\CONFIG
6.  Choose the file type as all files 
7. Look for machine.config file
8. Open it
9. Add the following lines after   tag and save 

Add the following XML block as a peer to the existing system.net element, replacing any existing default Proxy

element if present:
 

<defaultProxy
                enabled = “true”
                useDefaultCredentials = “true”>
<proxy autoDetect="false" bypassonlocal="false" proxyaddress="http://127.0.0.1:8888” usesystemdefault=”false” />

10. Now Start the Fiddler
11. Fiddler will capture all the requests from .Net 





Design a site like this with WordPress.com
Get started