Sunday 9 October 2016

ASP.NET Core 1.0 MVC TagHelper

Tag Helpers are special feature to enable server side code to create, update and render HTML in view file. They are said to be evaluation of Html Helpers. Although, Html Helpers do exist, yet Tag Helpers are very popular as they are just additional attributes in existing Html elements and are very easy for UI designers or front stack developers to understand.
Tag Helpers are attached to HTML tags without effecting raw view. On the other hand, HTML Helpers are methods which are called to yield required HTML. Furthermore, Tag Helper has powered by IntelliSense in Visual Studio, while HTML Helper does not support IntelliSense much. In nutshell, Tag Helpers are efficient, easier to code and make code cleaner with respect to HTML Helper along with many features out of box. Generally all Tag Helpers has use "asp-" attributes to specify special values, for example:
  • asp-controller: is used to specify controller to be used.
  • asp-action: is used to specify action method to be used.
  • asp-area: is used to specify area to be used.
  • asp-for: is used to specify property to be used. Generally, this property is bond to specified control. 
  • asp-route: is used to specify named route instead of controller and action method. 
  • asp-validation-for: is used to specify property to be validated.
  • asp-validation-summary:is used to specify mode of validation summary to be used.
  • asp-antiforgery: is used to enable or disable antiforgery.
  • asp-append-version: is used to add version number to resource, so if there is any change in resource then version number is also changed. It ensures that in case of any change one resource is not used from cache.

ASP.NET Core provides a set of predefined Tag Helpers in Microsoft.AspNetCore.Mvc.TagHelpers. This namespace provides us following important Tag Helpers:
  • AnchorTagHelper
  • FormTagHelper
  • ImageTagHelper
  • InputTagHelper
  • LabelTagHelper
  • LinkTagHelper
  • OptionTagHelper
  • ScriptTagHelper
  • SelectTagHelper
  • TextAreaTagHelper
  • ValidationMessageTagHelper
  • ValidationSummaryTagHelper
  • CacheTagHelper
  • DistributedCacheTagHelper
  • EnvironmentTagHelper

AnchorTagHelper

AnchorTagHelper is used with a tag. It allows data element to be mapped a tag through asp-area, asp-controller, asp-action, asp-route to specify area, controller, action method and route. We can also pass parameters asp-route- construct.

 <a asp-controller="Contact" asp-action="GetContact" asp-route-id="1">Get Details</a> 

FormTagHelper

FormTagHelper is used with form tag. It allows to specify controller, action method. It also allows to specify route name instead of controller and action. Furthermore, it provides services to handle cross-site request forgery. It is important to remember that on submit action form uses name fields of inner objects to create response body.

 <form asp-controller="Contact" asp-action="CreateContact" asp-antiforgery="true" method="post">  
   ...  
 </form>  

ImageTagHelper

ImageTagHelper is used with img tag. It allows to specify asp-append-version, which is used to address image cache problem.

 <img asp-append-version="true" src="/logo.png" alt="My ORganization" /> 

InputTagHelper

InputTagHelper is used with input tag. It allows data element to be mapped input tag through asp-for attribute. While input tag type is decided through data element type and data annotation. While data validation rules are applied through data annotation.
For example element data type Boolen will make type="checkbox", String will make type="text", DateTime will make type="datetime"and Byte, Integer, Single, Double will make type="number". Similarly data annotation EmailAddress will make type="email" , Url will make type="url", HiddenInput will make type="hidden", Phone will make type="tel", Password will make type="password", Date will make type="date"and Time will make type="time".

 <input asp-for="Name" class="form-control" />  

LabelTagHelper

LabelTagHelper is used with label tag. It allows data element to be mapped input tag through asp-for attribute. It uses Display data annotation value of specified data element to display label. If Display attribute has not been applied then element name is used.

 <label asp-for="Name" class="col-md-2 control-label"></label>  

LinkTagHelper

LinkTagHelper is used with link tag. It allows to control link behavior, for example specify and control source and fallback source.

 <link asp-append-version="true" /link>

OptionTagHelper

OptionTagHelper is used with option tag in select tag. It allows to manipulate option elements individually by SelectTagHelper.

 <select asp-for="Title" asp-items="Model.Titles"></select>

ScriptTagHelper

ScriptTagHelper is used with script tag. It allows to control script block behavior, for example specify and control source and fallback source.

 <script asp-append-version="true">
    ...
 </script>

SelectTagHelper

SelectTagHelper is used with select tag. It allows data element to be mapped select tag and option through asp-for and asp-items attributes, asp-for is used to specify selected value element and asp-items is used to specify list to be bounded with options. While data validation rules are applied through data annotation.

 <select asp-for="Title" asp-items="Model.Titles"></select>

TextAreaTagHelper

TextAreaTagHelper is used with textarea tag. It allows data element to be mapped textarea tag through asp-for attribute. While data validation rules are applied through data annotation.

 <textarea asp-for="Description" rows="5" cols="30" />

ValidationMessageTagHelper

ValidationMessageTagHelper is used with span tag. It allows validation messages mapped to span tag through asp-validation-for attribute.

 <span asp-validation-for="Name" class="text-danger" />

ValidationSummaryTagHelper

ValidationSummaryTagHelper is used with div tag. It allows all validation messages mapped to div tag filtered through asp-validation-summary attribute. Possible values for asp-validation-summary as: All, ModelOnly, None.

 <div asp-validation-summary="ModelOnly" class="text-danger"></div>

CacheTagHelper

CacheTagHelper is used to cache content for any section of a view. It is not applied to any standard HTML tags, rather than, it is a server side control. It uses MemoryCache to store.
Please refer to In Memory Caching for more details. It allows us to control cache expiry as per requirement with following attributes:

  • expires attribute allow to specify: 
    • Time interval after which cached data will expire using expires-after.
    • Time interval after which cached data will expire if not used using expires-sliding.
    • Fixed time interval on which cached data will expire using expires-on.

 <cache expires-after="@TimeSpan.FromSeconds(100)">
    ...
 </cache>
  • vary-by attribute allows to specify cache data:
    • Based on some key or model data using vary-by.
    • Based on user using vary-by-user
    • Based on cookie using vary-by-cookie
    • Based on some header value using vary-by-header
    • Based on some query string attribute using vary-by-query
    • Based on route using vary-by-route

 <cache vary-by-user="true">
    ...
 </cache>
  • priority allow to specify priority of cached content. When system runs out of memory, it starts clearing cached contents, in such case items are cleared priority wise. We use Microsoft.Extensions.Caching.Memory.CacheItemPriority to specify priority.

 <cache priority="@CacheItemPriority.Low">
    ...
 </cache> 
  • We can use different attributes together to have mixed mode as per our requirements. But it is important to remember that there will be cached copy for each combination and it can lead to use a huge memory.
 <cache expires-sliding="@TimeSpan.FromSeconds(100)"  vary-by-user="true" priority="@CacheItemPriority.Low">
    ...
 </cache> 

DistributedCacheTagHelper

 DistributedCacheTagHelper is used to cache content to distributed cache servers. It is very useful when we want to handle large amount of content or want to ensure that cached data is even available if web application is restarted. There are few requirements for distributed cache:
It is our responsibility to define Unique Cache Key, otherwise content will be overwritten.
This distributed cache service will be registered through Startup.ConfigureServices. If we do not configure any distributed cache server then ASP.NET Core will use default Memory Cache. We can use SqlServerCache or any other Cache like Radis Cache as per requirements. Please refer to Working with a Distributed Cache for more details.

 <distributed-cache name="UniqueCacheKey">
    ...
 </distributed-cache>

EnvironmentTagHelper

EnvironmentTagHelper is a server side Tag Helper which is used to specify different HTML handling to be used for different environment. It becomes very handy when we have to specify different URLs for links and scripts for different environments. Please refer to Working with Multiple Environments for more details. We can find related example in _Layout.cshtml.



 <environment names="Development">
    <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.css" />
    <link rel="stylesheet" href="~/css/site.css" />
 </environment>
 <environment names="Staging,Production">
    <link rel="stylesheet" href="https://ajax.aspnetcdn.com/ajax/bootstrap/3.3.6/css/bootstrap.min.css"
            asp-fallback-href="~/lib/bootstrap/dist/css/bootstrap.min.css"
            asp-fallback-test-class="sr-only" asp-fallback-test-property="position" asp-fallback-test-value="absolute" />
    <link rel="stylesheet" href="~/css/site.min.css" asp-append-version="true" />
 </environment>

Monday 3 October 2016

.NET Core CSV Writer

Let's discuss how to implementation of generic CSV Writer, which may take input any List and return a CSV string or write to specified file if specified. Although, this is a generic C# implementation and can be used in any .NET Framework supporting generics, yet we are going to discuss this with .NET Core. We are going to use .NET Core Console Application from previous discussion Welcome to .NET Core Console Application.

Add new Class in DotNetCore.ConsoleApplication

We are going to add a new class CsvWriter in DotNetCore.ConsoleApplication.
  • Open existing Solution in Visual Studio 2015.
  • Now add a new class CsvWriter.cs.
    • Open Add New Item Screen through DotNetCore.ConsoleApplication Context Menu of Common folder >> Add >> Class >> Installed >> .NET Core >> Class.
    • Name it CsvWriter.cs.
    • Click OK Button. 
  • Add CsvWriter implementation.
    • Write<T> (IList<T> list, bool includeHeader = true)
    • Creates and returns generated CSV. 
    • Write<T> (IList<T> list, string fileName, bool includeHeader = true)
      Creates and returns generated CSV and saves the generated CSV to specified path.
    • CreateCsvHeaderLine
      Creates CSV header line if includeHeader is sent true.
    • CreateCsvLine<T>(T item, PropertyInfo[] properties)
      Creates a CSV line for given type of object.
    • CreateCsvLine(IList<string> list)
      Creates a CSV line for given list of string by joining them delimated by comma.
    • CreateCsvItem
      Adds provided value item to processed list used to create CSV line.
    • CreateCsvStringListItem
      Adds provided string list as single item to processed list used to create CSV line.
    • CreateCsvStringArrayItem
      Adds provided string array as single item to processed list used to create CSV line.
    • CreateCsvStringItem
      Adds provided string value item to processed list used to create CSV line.
    • ProcessStringEscapeSequence
      Processes the provided data to handle double qoutes and comma value. If we do not apply escape sequences then they can croupt data.
    • WriteFile
      Writes the generated CSV data to file.

 public class CsvWriter
 {
    private const string DELIMITER = ",";

    public string Write<T>(IList<T> list, bool includeHeader = true)
    {
        StringBuilder sb = new StringBuilder();

        Type type = typeof(T);

        PropertyInfo[] properties = type.GetProperties();

        if (includeHeader)
        {
            sb.AppendLine(this.CreateCsvHeaderLine(properties));
        }

        foreach (var item in list)
        {
            sb.AppendLine(this.CreateCsvLine(item, properties));
        }

        return sb.ToString();
    }

    public string Write<T>(IList<T> list, string fileName, bool includeHeader = true)
    {
        string csv = this.Write(list, includeHeader);

        this.WriteFile(fileName, csv);

        return csv;
    }

    private string CreateCsvHeaderLine(PropertyInfo[] properties)
    {
        List<string> propertyValues = new List<string>();

        foreach (var prop in properties)
        {
            string formatString = string.Empty;
            string value = prop.Name;

            var attribute = prop.GetCustomAttribute(typeof(DisplayAttribute));
            if (attribute != null)
            {
                value = (attribute as DisplayAttribute).Name;
            }

            this.CreateCsvStringItem(propertyValues, value);
        }

        return this.CreateCsvLine(propertyValues);
    }

    private string CreateCsvLine<T>(T item, PropertyInfo[] properties)
    {
        List<string> propertyValues = new List<string>();

        foreach (var prop in properties)
        {
            string formatString = string.Empty;
            object value = prop.GetValue(item, null);

            if (prop.PropertyType == typeof(string))
            {
                this.CreateCsvStringItem(propertyValues, value);
            }
            else if (prop.PropertyType == typeof(string[]))
            {
                this.CreateCsvStringArrayItem(propertyValues, value);
            }
            else if (prop.PropertyType == typeof(List<string>))
            {
                this.CreateCsvStringListItem(propertyValues, value);
            }
            else
            {
                this.CreateCsvItem(propertyValues, value);
            }
        }

        return this.CreateCsvLine(propertyValues);
    }

    private string CreateCsvLine(IList<string> list)
    {
        return string.Join(CsvWriter.DELIMITER, list);
    }

    private void CreateCsvItem(List<string> propertyValues, object value)
    {
        if (value != null)
        {
            propertyValues.Add(value.ToString());
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringListItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            value = this.CreateCsvLine((List<string>)value);
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringArrayItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            value = this.CreateCsvLine(((string[])value).ToList());
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private string ProcessStringEscapeSequence(object value)
    {
        return value.ToString().Replace("\"", "\"\"");
    }

    public bool WriteFile(string fileName, string csv)
    {
        bool fileCreated = false;

        if (!string.IsNullOrWhiteSpace(fileName))
        {
            File.WriteAllText(fileName, csv);

            fileCreated = true;
        }

        return fileCreated;
    }
 }

Add Test Model Class in DotNetCore.ConsoleApplication

We are going to add a new class TestVM in DotNetCore.ConsoleApplication.
  • Open existing Solution in Visual Studio 2015.
  • Now add a new class TestVM.cs.
    • Open Add New Item Screen through DotNetCore.ConsoleApplication Context Menu of Common folder >> Add >> Class >> Installed >> .NET Core >> Class.
    • Name it TestVM.cs.
    • Click OK Button. 
  • Add TestVM implementation.
  • Update Program.cs to initialize List<TestVM> with dummy data and call CsvWriter.



 public class TestVM  
 {  
   [Display(Name = "Test Id")]  
   public int TestId { get; set; }  
   [Display(Name = "Name")]  
   public string TestName { get; set; }  
 }  

 public class Program  
 {  
   public static void Main(string[] args)  
   {  
     Console.WriteLine("Welcome to .NET Core Console Application");  
     List<TestVM> tests = new List<TestVM>  
     {  
       new TestVM {TestId=1, TestName="Bill Gates" },  
       new TestVM {TestId=2, TestName="Warren Buffett" },  
       new TestVM {TestId=3, TestName="Amancio Ortega" },  
       new TestVM {TestId=4, TestName="Carlos Slim Helu" }  
     };  
     string fileName = string.Format("{0}\\test.csv", System.AppContext.BaseDirectory);  
     CsvWriter csvWriter = new CsvWriter();  
     csvWriter.Write(tests, fileName, true);  
     Console.WriteLine("{0} has been created.", fileName);  
     Console.ReadKey();  
   }  
 }  

Run Application in Debug Mode

  • Press F5 or Debug Menu >> Start Debugging or Start Console Application Button on Toolbar to start application in debugging mode. It will start application console in debug mode.
  • It will generate test.csv at given path. Therefore at C:\ASP.NET Core\CSV Writer\DotNetCore\ConsoleApplication.NetCore\bin\Debug\netcoreapp1.0.


Sample Source Code

We have placed sample code for this session in ".NET Core CSV Writer_Code.zip" in https://aspdotnetcore.codeplex.com/SourceControl/latest CodePlex repository.

Sunday 2 October 2016

Welcome to .NET Core 1.0 Console Application

Let’s create our first .NET Core Console Application. We assume that we already have Visual Studio 2015 Update 3 and .NET Core 1.0.0 - VS 2015 Tooling Preview 2. If you have not installed .NET Core yet then I may recommend you to follow our initial discussion How to install .NET Core 1.0. Alternatively you can follow Microsoft Official Site directly.

Create a new Solution

We are going to create a new solution. If we don't perform this task then Visual Studio aromatically creates a solution for a project:
  • Open Visual Studio 2015.
  • Open New Project Screen through menu File >> New >> Project.
  • Select Blank Solution through Installed >> Templates >> Other Projects >> Visual Studio Solutions.
  • Name solution as “DotNetCore”. Set suitable location as “C:\ASP.NET Core\Welcome To .NET Core 1.0\”.
  • Click OK Button.
  • It will create a new solution.

Create new Console Application .NET Core

We are going to add a new Console Application.
  • Open Add New Project Screen through Solution Context Menu >> Add >> New Project or File >> New >> Project.
  • Select Class Console Application (.NET Core) through Installed >> Templates >> Visual C# >> .NET Core.
  • Name project as “DotNetCore.ConsoleApplication”.
  • Set suitable location as “C:\ASP.NET Core\Welcome To .NET Core 1.0\DotNetCore\” (selected by default to solution root).
  • Click OK Button.
  • Add Write greetings and ReadKey in Program.cs.
    •  Console.WriteLine("Welcome to .NET Core Console Application"); prints message on console,
    • Console.ReadKey(); holds the program from termination until a key is pressed.

 public class Program  
 {  
   public static void Main(string[] args)  
   {  
     Console.WriteLine("Welcome to .NET Core Console Application");  
     Console.ReadKey();  
   }  
 }  

Run Application in Debug Mode

To run application, we can chose any of following:
  • Press F5 or Debug Menu >> Start Debugging or Start Console Application Button on Toolbar to start application in debugging mode. It will start application console in debug mode.
  • Make project self contained and it will generate exe file which is directly executable. Please refer to Self Contained Deployment for more details.

Application Deployment

.NET Core allows us two methodologies for compilation and deployment as following, these methodologies can be configured and through project.json:
  • Framework Dependent Deployment
  • Self Contained Deployment

Framework Dependent Deployment

Framework Dependent Deployment allows to build and run application as dll, and in this mode application is executed through dotnet.exe. In this case a single distributable is created which is executed system provided runtime components. By default, Visual Studio 2015 uses this mode. If we observe build directory, then it contains dlls and config files only.
To execute application in this mode:
  • Open  command line prompt or Power Shell.
  • Go to output folder containing ConsoleApplication.NetCore.dll. In our example we have path as: C:\ASP.NET Core\Welcome To .NET Core 1.0\DotNetCore\ConsoleApplication.NetCore\bin\Debug\netcoreapp1.0.
  • Execute command dotnet ConsoleApplication.NetCore.dll
  • It will execute application.


 {   
  "version": "1.0.0-*",   
  "buildOptions": {   
   "emitEntryPoint": true   
  },   
  "dependencies": {   
   "Microsoft.NETCore.App": {   
   "type": "platform",   
   "version": "1.0.0"   
   }   
  },   
  "frameworks": {   
   "netcoreapp1.0": {   
   "imports": "dnxcore50"   
   }   
  }   
  }  

Self Contained Deployment

Self Contained Deployment allows to build and distribute application as an exe, which is execuatable directly. In this case an OS dependent disreputable is created which is executed contains all required runtime components. We may have to do few or more configuration changes in project.json in dependencies, runtimes and others as per requirements. In our case we have to just remove "type": "platform" from dependencies and to add runtimes section.  If we observe build directory, then it contains exe along with dlls and config files only.
To execute application in this mode
  • Open  command line prompt or Power Shell and enter ConsoleApplication.NetCore.exe command
  • Or directly double click ConsoleApplication.NetCore.exe in Windows Explorer.
  • It will execute application.

 {  
  "version": "1.0.0-*",  
  "buildOptions": {  
   "emitEntryPoint": true  
  },  
  "dependencies": {  
   "Microsoft.NETCore.App": {  
    "version": "1.0.0"  
   }  
  },  
  "frameworks": {  
   "netcoreapp1.0": {  
    "imports": "dnxcore50"  
   }  
  },  
  "runtimes": {  
   "win81-x64": {}  
  }  
 }   

Please refer to .NET Core Application Deployment for more details. Few important runtimes are:

  • win7-x86
  • win7-x64
  • win81-x86
  • win81-x64
  • win10-x86
  • win10-x64
  • osx.10.10-x64

Sample Source Code

We have placed sample code for this session in "Welcome To .NET Core Console Application_Code.zip" and "Welcome To .NET Core Console Application_SelfContained_Code.zip" in https://aspdotnetcore.codeplex.com/SourceControl/latest CodePlex repository.



Friday 30 September 2016

ASP.NET Core 1.0 MVC Controller

Controller is heart of MVC. It is a glue between View and Model. It accepts request as input through Action Methods, while an action method may generate some response (for example list page and details page) or perform some task (for example add, update and delete). In simple, we can call Controller a group of related Action Methods with set of applicable rules. And it is responsible to manipulate data in form of Models and rendering of views as final result.



It is not required, but we have few conventions, which are followed throughout community but in actual they are not required. They are just followed as best practice.
  • A Controller has Controller Suffix. This convention is only followed to avoid name conflict and to make it easier to identify Controllers.

  • A Controller has to be in Controller Folder. We know that final output assembly have no concern of folder structure used in code. So this convention is solely in practice for code maintenance.
  • A Controller must inherent from Microsoft.AspNetCore.Mvc.Controller Class directly or indirectly. This practice is mainly used as Microsoft.AspNetCore.Mvc.Controller class provides us many methods also called Controller Helper methods and properties out of box. Controller helper methods are generally used to process and return response:
    • View
      • View helper method allows controller to specify view and model to be used.
      •  return View();  
         return View("ViewName");  
         return View(someObject);  
         return View("ViewName", someObject);  
        
    • Http Status Code
      • Http Status Code helper methods are a set of methods, which are used to return Http status code of specific type. Few important examples are as following:
        • BadRequest
        • NoContent
        • NotFound
        • Forbid
        • Unauthorized
      •  return BadRequest();  
         return Unauthorized();  
    • Formatted Response
      • Formatted Response helper methods allows the action method to return result in specific format. Few important examples are as following:
        • Json
        • Content
        • File
      •  return Json(someObject);  
         return Content(someObject);  
    • Content negotiated response
      • Content Negotiated Response helper methods allow to return a content negotiated response instead of custom object. Few important examples are as following:
        • Created
        • CreatedAtRoute 
        • CreatedAtAction
        • ChallengeResult
      •  return Created(uri, someObject);  
    • Redirect
      • Redirect helper methods allow to redirect the flow of request to some other action methods or route. Few important examples are as following:
        • Redirect
        • LocalRedirect
        • RedirectToAction
        • RedirectToRoute
      •  return RedirectToAction("ActionName");  
         return RedirectToAction("ActionName", someObject);   
         return RedirectToAction("ControllerName", "ActionName", someObject);
    • Any Object or Type
      • If an action method just returns an object or a collection of objects then returned data is formatted based on request parameters. For ASP.NET Core Json is default option. 
        • Native Types (int, string)
        • Complex Type (any class or generics)
      •  return "Hello Controllers";  
         return someObject;  return ListOfObjects;

Action Method

Action Method is unit of Controller. It is any public method and may have parameter of native or complex type, for example, Index or List Action Method may not have any parameter, Get Action Method may have a parameter as Id and a Update or Create Action Method may have complex ViewModel as parameter. Action Method parameters are populated using Model Binding, please refer to ASP.NET Core 1.0 MVC Model for more details on Model Binding. It is not rough and tough rule, but in general, an action methods perform following set of tasks:
  • Process request parameters and map them to data provider components. We may also consider InputFormatter and Parameter Mapping in this area. It may also involve input Data Validation. For more details on Model Binding and Parameter Mapping, please refer to ASP.NET Core 1.0 MVC Model. We will discuss InputFormatter and Data Validation in detail in future sessions.
  • These data provider components can be any repository, any data service or any business logic component. For .NET Core it is recommended to use data provider components as services, and these services are generally made available to Controller using Dependency Injection. We will discuss Dependency Injection in detail in future sessions.
  • Process response data and map them to final response output. Depending upon type of application, action method selects the response type. In normal MVC application, we mostly cater with IActionResult. We may return view. Please refer to ASP.NET Core 1.0 MVC View for more details about Views.

Additional Features

There are many other features related with controllers like following, but we may discuss them in different sessions in future:
  • Filters
  • Exception Handling
  • Response Cache
  • Routing
  • Controller Scaffolding
  • Web API
  • Authentication and Authorization
  • Dependency Injection
  • Testing

Further Reading

For further details, please refer to official documentation at: https://docs.asp.net/en/latest/mvc/controllers/index.html.

Friday 23 September 2016

CRUD operations in ASP.NET Core 1.0 MVC Application Part 8

Let's discuss how to export data or list in CSV format. For this purpose, we will implement Custom  Response Formatter CsvOutputFormatter and a generic helper CsvWriter to convert any List of objects to CSV format. We are going to extend our application from last discussion  CRUD operations in ASP.NET Core 1.0 MVC Application Part 7.

Add CsvWriter in WebApplicationCore.NetCore

  • Open existing Solution in Visual Studio 2015.
  • Now add a new folder Common in WebApplicationCore.NetCore.
    • Open Context Menu of project >> Add >> New Folder.
    • Name it Common.
  • Now add a new class CsvWriter.cs in Common folder in WebApplicationCore.NetCore.
    • Open Add New Item Screen through Solution Context Menu of Common folder >> Add >> Class >> Installed >> .NET Core >> Class.
    • Name it CsvWriter.cs.
    • Click OK Button.
  • It will add a new class CsvWriter.cs in Common folder.
  • Add required implementation in CsvWriter to generate CSV string for provided list of objects. CsvWriter is a helper class and it provides facility to generate CSV of provided List of objects. We have changed it for our requirements, please refer to .NET Core CSV Writer for more details.

 public class CsvWriter
 {
    private const string DELIMITER = ",";

    public string Write(IList list, bool includeHeader = true)
    {
        StringBuilder sb = new StringBuilder();

        Type type = list.GetType().GetGenericArguments()[0];

        //Get property collection and set selected property list
        PropertyInfo[] properties = type.GetProperties();

        //Add Header Names to Csv 
        if (includeHeader)
        {
            sb.AppendLine(this.CreateCsvHeaderLine(properties));
        }

        //Iterate through data list collection
        foreach (var item in list)
        {
            sb.AppendLine(this.CreateCsvLine(item, properties));
        }

        return sb.ToString();
    }

    private string CreateCsvHeaderLine(PropertyInfo[] properties)
    {
        List<string> propertyValues = new List<string>();

        foreach (var prop in properties)
        {
            string formatString = string.Empty;
            string value = prop.Name;

            var attribute = prop.GetCustomAttribute(typeof(DisplayAttribute));
            if (attribute != null)
            {
                value = (attribute as DisplayAttribute).Name;
            }

            this.CreateCsvStringItem(propertyValues, value);
        }

        return this.CreateCsvLine(propertyValues);
    }

    private string CreateCsvLine(object item, PropertyInfo[] properties)
    {
        List<string> propertyValues = new List<string>();

        foreach (var prop in properties)
        {
            string formatString = string.Empty;
            object value = prop.GetValue(item, null);

            if (prop.PropertyType == typeof(string))
            {
                this.CreateCsvStringItem(propertyValues, value);
            }
            else if (prop.PropertyType == typeof(string[]))
            {
                this.CreateCsvStringArrayItem(propertyValues, value);
            }
            else if (prop.PropertyType == typeof(List<string>))
            {
                this.CreateCsvStringListItem(propertyValues, value);
            }
            else
            {
                this.CreateCsvItem(propertyValues, value);
            }
        }

        return this.CreateCsvLine(propertyValues);
    }

    private string CreateCsvLine(IList<string> list)
    {
        return string.Join(CsvWriter.DELIMITER, list);
    }

    private void CreateCsvItem(List<string> propertyValues, object value)
    {
        if (value != null)
        {
            propertyValues.Add(value.ToString());
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringListItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            value = this.CreateCsvLine((List<string>)value);
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringArrayItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            value = this.CreateCsvLine(((string[])value).ToList());
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private void CreateCsvStringItem(List<string> propertyValues, object value)
    {
        string formatString = "\"{0}\"";
        if (value != null)
        {
            propertyValues.Add(string.Format(formatString, this.ProcessStringEscapeSequence(value)));
        }
        else
        {
            propertyValues.Add(string.Empty);
        }
    }

    private string ProcessStringEscapeSequence(object value)
    {
        return value.ToString().Replace("\"", "\"\"");
    }
 }

Add CsvOutputFormatter in WebApplicationCore.NetCore

  • Now add a new class CsvOutputFormatter.cs in Common folder in WebApplicationCore.NetCore.
    • Open Add New Item Screen through Solution Context Menu of Common folder >> Add >> Class >> Installed >> .NET Core >> Class.
    • Name it CsvOutputFormatter.cs.
    • Click OK Button.
  • It will add a new class CsvOutputFormatter.cs in Common folder.
  • Implement Custom Output Formatter in CsvOutputFormatter class to generate response in CSV format using CsvWriter. To create a new Custom Output Formatter we can use one of following approaches:
    • Inherent existing output formatter base class TextOutputFormatter, OutputFormatter or StreamOutputFormatter as per requirement. For example, JsonOutputFormatter and XmlSerializerOutputFormatter inherit TextOutputFormatter. Although, this approach provides many features out of box due to base class, yet it makes formatter little heavier. 
    • Alternatively, Implement IOutputFormatter interface and we just have to implement two methods: CanWriteResult and WriteAsync. Where CanWriteResult is used to check if this formatter can be used to process response or not, while WriteAsync method performs actual processing on response. We have used this approach as it is simple and efficient.
    • ASP.NET Core provisions us to implement Custom Response Formatter and Custom Request Formatter separately. In this way, we can use any kind of Response and Request formatter as per requirements. We will discuss Custom Response and Request Formatter in detail in future sessions.
  • We also need to register CsvOutputFormatter, for this purpose, we register it in ConfigureServices method of Startup class with MVC service as Setup Action. In simple, we have to add CsvOutputFormatter in collection of OutputFormatters of MVC Service.

 public class CsvOutputFormatter : IOutputFormatter
 {
    public bool CanWriteResult(OutputFormatterCanWriteContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        if (context.ContentType == null || context.ContentType.ToString() == "text/csv")
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    public async Task WriteAsync(OutputFormatterWriteContext context)
    {
        if (context == null)
        {
            throw new ArgumentNullException(nameof(context));
        }

        var response = context.HttpContext.Response;
        response.ContentType = "text/csv";

        using (var writer = context.WriterFactory(response.Body, Encoding.UTF8))
        {
            IList lst = context.Object as IList;
            CsvWriter csvWriter = new CsvWriter();

            string csv = csvWriter.Write(lst, true);

            writer.Write(csv);

            await writer.FlushAsync();
        }
    }
 }


 public void ConfigureServices(IServiceCollection services)
 {
    // Add framework services.
    services.AddMvc(options=>options.OutputFormatters.Add(new CsvOutputFormatter()));

    services.AddSingleton<IConfigurationRoot>(sp => { return this.Configuration; });
    services.AddScoped<IContactDataAccess, ContactDataAccess>();
    services.AddScoped<IContactBusinessLogic, ContactBusinessLogic>();
 }

GetCsv Action Method and Get CSV Link

  • Now add a new action method GetCsv in WebApplicationCore.NetCore.ContactController class. It is similar to Index Action Method with exception that it returns List<ContactListVM> and has [Produces("text/csv")] attribute to mark content type to enforce ustilization of CsvOutputFormatter. We are explicitly checking content type == "text/csv" in CanWriteResult.
  •  Add Get CSV link in Contract\Index.cshtml for GetCsv action method.

 [Produces("text/csv")]
 public List<ContactListVM> GetCsv()
 {
    List<Contact> contacts = this.ContactBusinessLogic.GetContacts();
    List<ContactListVM> contactVMs = new List<ContactListVM>();
    ContactListVM contactVM;

    foreach (Contact contact in contacts)
    {
        contactVM = new ContactListVM
        {
            ContactId = contact.ContactId,
            ContactNumber = contact.ContactNumber,
            Email = contact.Email,
            Name = contact.Name,
            WebSite = contact.WebSite
        };
        contactVMs.Add(contactVM);
    }

    return contactVMs;
 }

 <th>
    <a asp-controller="Contact" asp-action="GetCsv">Get CSV</a>
 </th>

Run Application in Debug Mode

  • Press F5 or Debug Menu >> Start Debugging or Start IIS Express Button on Toolbar to start application in debugging mode.
  • It will show Home Page in browser.
  • Click Contact List Menu Open to open Contact List Page.
  • Click Get CSV link it will show open save dialog.
  • Save response as CSV.
  • Open file, it will open CSV file in default program, most probably in Excel or Notepad.

Sample Source Code

We have placed sample code for this session in "CRUD operations in ASP.NET Core 1.0 MVC Application Part 8_Code.zip" in https://aspdotnetcore.codeplex.com/SourceControl/latest CodePlex repository.


CRUD Operations in AP.NET Core 1.0 All Parts

CRUD operations in ASP.NET Core 1.0 MVC Application Part 1
CRUD operations in ASP.NET Core 1.0 MVC Application Part 2
CRUD operations in ASP.NET Core 1.0 MVC Application Part 3
CRUD operations in ASP.NET Core 1.0 MVC Application Part 4
CRUD operations in ASP.NET Core 1.0 MVC Application Part 5
CRUD operations in ASP.NET Core 1.0 MVC Application Part 6
CRUD operations in ASP.NET Core 1.0 MVC Application Part 7 
CRUD operations in ASP.NET Core 1.0 MVC Application Part 8

Tuesday 20 September 2016

ASP.NET Core 1.0 MVC View

View is said to be UI part of a web application. In simple, it can be called HTML Template which is used to generate final HTML. It is important to note that Razor code is executed server side to generate final HTML of a page with Help of Razor Engine. ASP.NET Core MVC Views has .cshtml extension (for C# ) and by default these files are stored in Views folder. Generally, controller has its own folder with views for related controller action methods.



By use, there following main types of views:
  • Action Specific Views
  • Partial Views
  • Layouts
  • Special View

Action Specific Views

Action Specific View are called from some action method and they are generally stored in view folder related controller and by default have same name as of action method. We can call views of different name by specifying view name and from different folder by specifying full path from an action method. Generally full qualified path is like “~/Views/FolderPath/ViewName.cshtml” or with relative path “../FolderPath/ViewName.cshtml”. Please refer to ASP.NET Core 1.0 MVC Controller for more details about Controllers.

Partial views

Partial View are said to be reusable components and very similar to web control in ASP.Net Web Forms. They can also be used to decompose complex structures into smaller parts. But main purpose of them is reusability. Partial View is rendered within another view. Partial views has same extension like view .cshtml and it is not required but a practice to start partical view with underscore (_). Technically, partial view is same as normal view but we make its Layout null. Furthermore, special views like _ViewStart are not executed for partial views.
We can add partial view into a view with @Html.Partial(“_ViewName”), while partial view can have relative or full qualified path.  And if we have strongly typed partial view, then we may add partial view with @Html.Partial(“_ViewName”, dataModel).It is important to note that partial views can be nested. So we can add a partial view in another partial view. Within each view or partial view, relative paths are always relative to that view, not the root or parent view. We are not allowed to have partial views loop cycle (circular nesting).

Layouts

Layout Views are said to be main structure and they are very similar to Master Page in ASP.NET Web Forms. Layout View defines main structure of a web application and may contain header, menu, footer and page content area as per requirements. They facilitate us to define and handle all these at one place. It is common to have at least one layout view, but we can have more than one layout views to meet different requirements. For example, we can have different layouts for front office and back office. Or to have different layout for popups. It is customary to have layout view as “_Layout.cshtml” in Shared Folder of Views. We set layout of a page with following statement in view or in _ViewStart.cshtml.

 @{  
  Layout = “_Layout”;  
 }  

Layout view contain special tag @RenderBody() in which main called view is added and @RenderSection() which specifies section to be rendered in view. We will discuss sections in detail in future sessions.

Special View

Like Layout view, ASP.NET has couple of other special views:
  • _ViewImports.cshtml
  • _ViewStart.cshtml

_ViewImports.cshtml

_ViewImports view is used to perform activities like:  importing namespaces or performing dependency injection, shared directive. Generally, we have _ViewImports  at the root Views folder, but we can have as many as required. For example, we can add _ViewImports view in each folder. In this case current folder settings are added to settings from upper folder. And in case of conflict settings from from nearest _ ViewImports view get preference. The _ViewImports file supports the following directives:
  • @addTagHelper
  • @removeTagHelper
  • @tagHelperPrefix
  • @using
  • @model
  • @inherits
  • @inject

_ViewStart.cshtml

_ViewStart.cshtml is used to execute common tasks like setting Layout View. The statements listed in _ViewStart.cshtml are run before every view except layouts, and partial views. Generally, _ViewStart.cshtml is located in the Views folder. Like _ViewImports.cshtml every folder can have _ViewStart.cshtml. These are executed from parent to child in sequence.

View Discovery

View Discovery in the process to identify the viewed called by an action method or a partial view during rendering of final Html. If a view name is not specified or name without path is specified then this process determines which view file will be used based on predefined steps. For example, when an action returns the View without view name then action name is used as the view name. Similarly, runtime looks for a controller-specific view first, then looks for matching view name in the Shared folder. And when view is specified with a full qualified path then only specific view file is used.

View Categorization based on Model

We can categorize views on bases of Model or data manipulation as following:
  • Loosely Typed or Type Less Views
  • Strongly Typed Views
  • Dynamic Views

Loosely Typed or Type Less Views

We can pass data to views using loosely typed data collections: ViewData and ViewBag.

ViewData

ViewData is a dictionary object accessed through string keys. We can store and retrieve objects in it, and we may need to cast them to a specific type. We can use ViewData to pass data from a controller to views, as well as within views (and partial views and layouts). String data can be stored and used directly, without the need for a cast.
 In Action Method   
 public IActionResult About()  
 {  
   ViewData["Message"] = "Your application description page.";  
   return View();  
 }  
 In View  
 @{  
   ViewData["Title"] = "About";  
 }  
 <h2>@ViewData["Title"].</h2>  
 <h3>@ViewData["Message"]</h3>  

ViewBag

The ViewBag property is a wrapper around ViewData that provides a dynamic view over that collection. It is not a separate collection. The ViewBag objects provides dynamic access to the objects stored in ViewData. This can be more convenient to work with, since it doesn’t require casting.
 In Action Method   
 public IActionResult Contact()  
 {  
   ViewBag.Message = "Your contact page.";  
   return View();  
 }  
 In View  
 @{  
   ViewBag.Title = "Contact";  
 }  
 <h2>@ViewBag.Title</h2>  
 <h3>@ViewBag.Message</h3>  

Which One to Use

Although ViewBag is just a wraper on ViewData collection and we can mix and match between ViewData and ViewBag without any issue, yet it is better to use one approach in a project.

Strongly Typed Views

Strongly Typed View has a specific a model type in the view, and it is mapped to an instance of this type passed to the view from the action as parameter. We can specify a model for a view using the @model directive then the instance sent to the view can be accessed in a strongly-typed manner using @Model as object of specified type.It is highly practiced and is most recommended option to pass data as it gives lot of benefits like robustness, compilation protection over other approaches.
Although we can use any type as model, but it is recommend to use Plain Old CLR Object (POCO) ViewModels. Please refer to ASP.NET Core 1.0 MVC Model for more details about Model and ViewModel,

Dynamic Views

Dynamic Views are hybrid of both Strongly Typed and Loosely Typed Views. In this kind of view model is not declared but have a model instance passed to them. But @model and it's properties  can be used in view dynamically. In this case we don't have compilation protection or IntelliSense. If the property doesn’t exist, then application crashes at runtime.

Additional Features

There are many other features related with Views like following, but we may discuss them in different sessions in future:
  • Tag Helper
  • HTML Helper
  • View Scaffolding
  • Razor Engine

Further Reading

For further details, please refer to official documentation at: https://docs.asp.net/en/latest/mvc/views/index.html.

Monday 19 September 2016

ASP.NET Core 1.0 MVC Model

Model is an object representing data item and set of applicable operations. It can be of simple native type like: integer, string or complex structure like class, array. Ideally, model represents state of an application. It is said to be data holder in MVC structure.

For data centric applications, Model is representation of an Entity and is generally used to transport data between Database and View through controller. For example, in Entity Framework or any ORM, Model Classes represent underlying entities.



It is common practice to pass custom models to views called as ViewModel particularly in case of Strongly Typed Views. Please refer to ASP.NET Core 1.0 MVC View for more details about Views. There are many reasons and advantages to use View Models:
  • ViewModels can be subset of a single model or multiple models and they are designed to fulfill data requirements of view without effecting actual model. For example, for a list page, we may use a ViewModel which has as few fields as few column as required on list page instead of having all of fields. On the other hand, for a complex view we can have a composite ViewModel having fields from different Models or additional fields.
  • When we bind Model with View then they can make model details available in rendered Html, but with usage of ViewModel we can hide actual model details. Therefor they provide additional security.
  • It increase performance by minimizing data transfer to and from view. 
There are many other features related with Models like following:
  • Model Binding 
  • Data Annotation and Model Validation
  • Response Data Formatting

Model Binding

Model Binding or Data mapping is responsible to map data from request to actual action method. Please refer to ASP.NET Core 1.0 MVC Controller for more details about Controllers and Action Methods. For simplicity, we have to keep following points in mid:
  • Model Binding is based on key value pair mapping and this mapping is not case sensitive, Data Elements are mapped using reflection and recursion.
  • For data mapping following collections are checked order wise: Form, Route and then Query String. So for parameter data mapping first of all Form values are parsed, if parameter is not found in Form then Route Values are check, Even if value not found then Query String is check. If a value not found in any of these then it is tried to set it to null.
  • ASP.NET Core provide us flexibility to change default binding behavior through predefined attributes including following:
    • BindRequired
    • BindNever
    • FromHeader
    • FromQuery
    • FromRoute
    • FromForm
    • FromServices
    • FromBody
    • ModelBinder (It allows us to define custom data binder) 

Data Annotation and Model Validation

Data Annotation is used to decorate a model. These are Attribute and used  to add additional details or metadata to model. This additional set of information can be used for a variety of purposes like: Labeling, Data Validation, Data Formatting, and Data Mapping.
System.ComponentModel.DataAnnotations provides a set of validation attributes. Most of the time data annotations are used for Labeling and Data Validation. Most commonly used data annotations are:
  • Required
  • StringLength
  • MinLength
  • MaxLength
  • RegularExpression
  • DataType
  • Display
  • DisplayFormat
  • Compare
  • Editable
  • CustomValidation
Basically all validation data annotations are driven from ValidationAttribute, which is driven from Attribute. Please refer to CRUD operations in ASP.NET Core 1.0 MVC Application Part 4 to see most of data annotations in action.
We can provide custom message as per requirements through ErrorMessage and if we don't provide ErrorMessage then default message is used. We can also use localization through resource files to centrally control labels and messages in single or in multiple languages. For this purpose, we specify resource through ErrorMessageResourceType parameter and resource filed with ErrorMessageResourceName parameter. We can also define new data annotation to perform both of client side and server side validations. We will discuss creating new data annotations in detail in future sessions.

Required

RequiredAttribute inherits from ValidationAttribute and specifies that a data field value is required.
[Required]

StringLength

StringLengthAttribute inherits from ValidationAttribute and specifies the minimum and maximum length of characters that are allowed in a data field.
[StringLength(100, MinimumLength = 3)]

MinLength

MinLengthAttribute inherits from ValidationAttribute  and specifies the minimum length of array or string data.
[MinLength(3)] 

MaxLength

MaxLengthAttribute inherits from ValidationAttribute and specifies the maximum length of array or string data.
[MaxLength(100)]

RegularExpression

RegularExpressionAttribute inherits from ValidationAttribute and specifies that a data field value must match the specified regular expression
[RegularExpression("[a-zA-Z ]*$", ErrorMessage = "Name can only contain alphbetics and space.")]

DataType

DataTypeAttribute inherits from ValidationAttribute and specifies the name of an additional type to associate with a data field. We also have specific purpose data validators like CreditCard, EmailAddress, FileExtensions, Phone, Url driven from DataTypeAttribute. They are used to validate string values for specific format acceptable for credit card number, email address, file extensions, phone number and Urls.
[DataType(DataType.Time)]

Display

DisplayAttribute inherits from Attribute and provides a general-purpose attribute that lets you specify localizable strings. This is basically used to display label instead of validation.
[Display(Name = "Contact Id")]

DisplayFormat

DisplayFormatAttribute inherits from Attribute and specifies how data fields are displayed and formatted.
[DisplayFormat(DataFormatString ="9,999.##", ApplyFormatInEditMode =true)]

Compare

CompareAttribute inherits from ValidationAttribute and specifies that value of a data filed is compared tothe value of other data field.
[Compare("PropertyToCompare")]

Editable

EditableAttribute inherits from Attribute and specifies that data field is editable or not. 
[Editable(false)]

CustomValidation

CustomValidationAttribute inherits from ValidationAttribute and allows to specify a custom validation method that is used to validate a property or class instance. Where we can define our custom method to perform complex task like validating unique email, address validation or any complex validation activity.

Response Data Formatting

ASP.NET Core supports JSON as default data format for request, and we can also use XML by using Microsoft.AspNetCore.Mvc.Formatters.Xml package. Furthermore, we can have many other formats like CSV or any other as per requirements with custom implementations. We will discuss Response Data Formatting in detail in future sessions.

Further Reading

For further details, please refer to official documentation at:  https://docs.asp.net/en/latest/mvc/models/index.html.

Monday 12 September 2016

CRUD operations in ASP.NET Core 1.0 MVC Application Part 6

Let’s implement Delete Contact for our Contacts Application. We are going to extend our application from last discussion CRUD operations in ASP.NET Core 1.0 MVC Application Part 5.

Add DeleteContact Method in ContactBusinessLogic

  • Open existing Solution in Visual Studio 2015.
  • Open WebApplicationCore.NetCore.BusinessLogic.ContactBusinessLogic class.
  • Add new DeleteContact method.
  • It may delete existing contact from mockup list data.
    public bool DeleteContact(int contactId)
    {
        bool deleted = false;

        Contact contact = ContactBusinessLogic.Contacts.FirstOrDefault(c => c.ContactId == contactId);

        if (contact != null)
        {
            ContactBusinessLogic.Contacts.Remove(contact);
            deleted = true;
        }

        return deleted;
    }


Add DeleteContact Action Methods in ContactController

  • Add two new DeleteContact Methods.
    • One DeleteContact method with ContactId parameter and HttpGet attribute to explicitly specify that this is get method. It will take user to confirmation page.
    • Other DeleteContact method with parameter of ContactVM  type and HttpPost attribute to explicitly specify that this is post method. It will be called if user confirms to delete contact, after deleting contact list page will be loaded.
  • It looks odd to have two methods to delete a simple item. We can perform this task with single delete method and even without involving a view. Alternatively, we could have some confirmation dialog to perform delete. Or some other solution with single delete method. I also had such questions in my mind when I read about this practice for first time. Let me summarize this for you:
    • It may create a security holes as anyone can use use a direct link to attack and to delete data. Even a search engine crawler can hit this method unnecessarily. Although we can use Authorize filter to control Delete method call, yet I am convinced that it is an improvisation not a best solution.
    • And as per REST standards, Get method may not change data. And therefor it is not a good practice.
    • In simple, it is not a good practice to perform a delete operation with a get call.
    [HttpGet]
    public IActionResult DeleteContact(int id)
    {
        ContactVM contactVM = new ContactVM
        {
            ContactId = id
        };

        return View(contactVM);
    }

    [HttpPost]
    public IActionResult DeleteContact(ContactVM contactVM)
    {
        ContactBusinessLogic contactBL = new ContactBusinessLogic();

        contactBL.DeleteContact(contactVM.ContactId);

        return RedirectToAction("Index");
    }

Add Contact DeleteContact View

  • Add new View to Contact\Contact folder.
  • Open Add New Item Screen through Solution Context Menu of Contact >> Add >> New Item >> Installed >> .NET Core >> MVC View Page.
  • Name it DeleteContact.cshtml.
  • Click OK Button.
  • It will add a new view in Contact view folder.
    • Now, we have ContactVM objects as model.
    • Delete button to delete contact and Cancel button to return back to list page without deleting contact.
  • Change Index view implementation to add Delete Details option with each record.
@model ContactVM

<h2>Delete Contact</h2>

<form asp-action="DeleteContact">
    <input type="hidden" asp-for="ContactId" />
    <div class="form-horizontal">
        <div class="form-group">
            <label>Please confirm to delete contact</label>
            <div class="col-md-10">
                <input type="submit" value="Delete" class="btn btn-default" />
                <a asp-action="Index"class="btn btn-default">Cancel</a>
            </div>
        </div>
    </div>
</form>

<td>
    <a asp-controller="Contact" asp-action="GetContact" asp-route-id="@item.ContactId">Get Details</a> |
    <a asp-controller="Contact" asp-action="UpdateContact" asp-route-id="@item.ContactId">Edit Details</a> |
    <a asp-controller="Contact" asp-action="DeleteContact" asp-route-id="@item.ContactId">Delete Details</a>
</td>


Run Application in Debug Mode

  • Press F5 or Debug Menu >> Start Debugging or Start IIS Express Button on Toolbar to start application in debugging mode.
  • It will show Home Page in browser.
  • Click Contact List Menu Open to open Contact List Page.
  • Click Delete Details link to open Delete Contact Page and URL will change to http://localhost:21840/Contact/DeleteContact/3.
  • Click Delete button. It will delete contact and it will load contact list page.


Saturday 10 September 2016

.NET Core 1.0 Connecting SQL Server Database

Let's discuss how to connect to databases. In this session, we will connect to SQL Server Database from .NET Core class library and we will use Microsoft SQL Server Database Provider named as "Microsoft.EntityFrameworkCore.SqlServer". Although, these are simple steps and can be performed in any project, but for simplicity and continuity of our work, we are going to use project created in our discussion Welcome to ASP.NET Core 1.0 MVC.

It is important to note that .NET Core does not have DataSet, DataTable and related objects anymore as of writing. But we have all of core features like Connection, Command, Paramter, DataReader and other related objects.

.NET Core Database Provider

A .NET Core application can connect to a database through Database Provider. Database Provider are database connectivity implementation for specific technology and are extension of System.Data.Common package.  At the moment .NET Core provides following Database Providers:
  • Microsoft SQL Server
  • SQLite
  • PostgreSQL
  • Microsoft SQL Server Compact Edition
  • IBM Data Servers
  • InMemory
  • MySQL (Under Devlopment)
  • Oracle (Under Devlopment)
Please refer to MSDN for more details on Database Providers.

Create Data Access Project

  • Open existing Solution in Visual Studio 2015.
  • Now add new Client Library .NET Core project in Solution.
    • Open Add New Project Screen through Solution Context Menu >> Add >> New Project Or File >> New >> Project.
    • Select Class Library (.NET Core) Template through Installed >> Templates >> Visual C# >> .NET Core.
    • Name project as “WebApplicationCore.NetCore.DataAccess”.
    • Set suitable location as “C:\ASP.NET Core\Welcome To .NET Core 1.0\ ASP.NET Core” (selected by default to solution root).
    • Click OK Button.
  • It will create a new class library project.
  • Add Reference to Microsoft.EntityFrameworkCore.SqlServer using one of following methods:
    • Open Package Manger Console through Tools >> NuGet Packet Manger >> Package Manger Console and run install command "Install-Package Microsoft.EntityFrameworkCore.SqlServer" for WebApplicationCore.NetCore.DataAccess project.
    • Open NuGet Manager through WebApplicationCore.NetCore.DataAccess Reference context menu >> References >> Manage NuGet  Packages. in Browse tab search for "Microsoft.EntityFrameworkCore.SqlServer" and install.
  • Rename Class1 as BaseDataAccess and add required implementation to connect to SQL Server Database. 
 public class BaseDataAccess
 {
    protected string ConnectionString { get; set; }

    public BaseDataAccess()
    {
    }

    public BaseDataAccess(string connectionString)
    {
        this.ConnectionString = connectionString;
    }

    private SqlConnection GetConnection()
    {
        SqlConnection connection = new SqlConnection(this.ConnectionString);
        if (connection.State != ConnectionState.Open)
            connection.Open();
        return connection;
    }

    protected DbCommand GetCommand(DbConnection connection, string commandText, CommandType commandType)
    {
        SqlCommand command = new SqlCommand(commandText, connection as SqlConnection);
        command.CommandType = commandType;
        return command;
    }

    protected SqlParameter GetParameter(string parameter, object value)
    {
        SqlParameter parameterObject = new SqlParameter(parameter, value != null ? value : DBNull.Value);
        parameterObject.Direction = ParameterDirection.Input;
        return parameterObject;
    }

    protected SqlParameter GetParameterOut(string parameter, SqlDbType type, object value = null, ParameterDirection parameterDirection = ParameterDirection.InputOutput)
    {
        SqlParameter parameterObject = new SqlParameter(parameter, type); ;

        if (type == SqlDbType.NVarChar || type == SqlDbType.VarChar || type == SqlDbType.NText || type == SqlDbType.Text)
        {
            parameterObject.Size = -1;
        }

        parameterObject.Direction = parameterDirection;

        if (value != null)
        {
            parameterObject.Value = value;
        }
        else
        {
            parameterObject.Value = DBNull.Value;
        }

        return parameterObject;
    }

    protected int ExecuteNonQuery(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
    {
        int returnValue = -1;

        try
        {
            using (SqlConnection connection = this.GetConnection())
            {
                DbCommand cmd = this.GetCommand(connection, procedureName, commandType);

                if (parameters != null && parameters.Count > 0)
                {
                    cmd.Parameters.AddRange(parameters.ToArray());
                }

                returnValue = cmd.ExecuteNonQuery();
            }
        }
        catch (Exception ex)
        {
            //LogException("Failed to ExecuteNonQuery for " + procedureName, ex, parameters);
            throw;
        }

        return returnValue;
    }

    protected object ExecuteScalar(string procedureName, List<SqlParameter> parameters)
    {
        object returnValue = null;

        try
        {
            using (DbConnection connection = this.GetConnection())
            {
                DbCommand cmd = this.GetCommand(connection, procedureName, CommandType.StoredProcedure);

                if (parameters != null && parameters.Count > 0)
                {
                    cmd.Parameters.AddRange(parameters.ToArray());
                }

                returnValue = cmd.ExecuteScalar();
            }
        }
        catch (Exception ex)
        {
            //LogException("Failed to ExecuteScalar for " + procedureName, ex, parameters);
            throw;
        }

        return returnValue;
    }

    protected DbDataReader GetDataReader(string procedureName, List<DbParameter> parameters, CommandType commandType = CommandType.StoredProcedure)
    {
        DbDataReader ds;

        try
        {
            DbConnection connection = this.GetConnection();
            {
                DbCommand cmd = this.GetCommand(connection, procedureName, commandType);
                if (parameters != null && parameters.Count > 0)
                {
                    cmd.Parameters.AddRange(parameters.ToArray());
                }

                ds = cmd.ExecuteReader(CommandBehavior.CloseConnection);
            }
        }
        catch (Exception ex)
        {
            //LogException("Failed to GetDataReader for " + procedureName, ex, parameters);
            throw;
        }

        return ds;
    }
 }

BaseDataAccess 

BaseDataAccess is a helper class which encapsulates all the implementation to connect and fetch data. It will not only help us to maintain database connectivity related code separately, but will also facilitate to easily replace SQL Database Provider with any other Data Provider as per requirements. We have explicitly returned bases classes DbConnection, DbCommand, DbParameter and DbDataReader instead of SqlConnection, SqlCommand, SqlParameter and SqlDataReader to abstract  database connectivity from implementer. In this way, we have to just change BaseDataAccess to target to some other database. We have following Components in this class:
  • ConnectionString
  • GetConnection
  • GetCommand
  • GetParameter
  • GetParameterOut
  • ExecuteNonQuery
  • ExecuteScalar
  • GetDataReader

ConnectionString

ConnectionString holds the connection string, we can either initialize directly from configurations by code or we can also initilize it throug parameterized constructor. We will initialize it with following value: "Server=SqlServerInstanceName;Database=DatabaseName;Trusted_Connection=True;MultipleActiveResultSets=true". 

GetConnection

GetConnection creates a new connection of SqlConnection type and return it after opening.

GetCommand

GetCommand creates a new command of SqlCommand according to specified parameters.

GetParameter

GetParameter creates a new parameter of SqlParameter and initialize it with provided value.

GetParameterOut

GetParameterOut creates a new parameter of SqlParameter type with parameter direct set to Output type.

ExecuteNonQuery

ExecuteNonQuery initializes connection, command and executes ExecuteNonQuery method of command object. Although the ExecuteNonQuery returns no rows, any output parameters or return values mapped to parameters are populated with data. For UPDATE, INSERT, and DELETE statements, the return value is the number of rows affected by the command. Please refer to MSDN for more details about SqlCommand.ExecuteNonQuery.

ExecuteScalar

ExecuteScalar initializes connection, command and executes  ExecuteScalar method of command object. Executes the query, and returns the first column of the first row in the result set returned by the query. Additional columns or rows are ignored.  Please refer to MSDN for more details about SqlCommand.ExecuteScalar.

ExecuteReader

ExecuteReader initializes connection, command and executes ExecuteReader method of command object. Provides a way of reading a forward-only stream of rows from a SQL Server database. We have explicitly omitted using block for connection as we need to return DataReader with open connection state. Now question raises that how will we handle connection close open, for this we have created DataReader with "CommandBehavior.CloseConnection", which means, connection will be closed as related DataReader is closed.  Please refer to MSDN for more details about SqlCommand.ExecuteReader and SqlDataReader.

Using BaseDataAccess 

We may recommend to use BaseDataAccess as base class of any other class, ideally your actual DataAccess component. If you think, you don't need full DataAccess layer, the you can make this concrete class by removing abstract keyword from declaration  and also make its protected methods to public/internal as per requirements. 

 public class TestDataAccess : BaseDataAccess
 {
    public TestDataAccess(string connectionString) : base(connectionString)
    {
    }

    public List<Test> GetTests()
    {
        List<Test> Tests = new List<Test>();
        Test TestItem = null;

        List<DbParameter> parameterList = new List<DbParameter>();
            
        using (DbDataReader dataReader = base.ExecuteReader("Test_GetAll", parameterList, CommandType.StoredProcedure))
        {
            if (dataReader != null && dataReader.HasRows)
            {
                while (dataReader.Read())
                {
                    TestItem = new Test();
                    TestItem.TestId = (int)dataReader["TestId"];
                    TestItem.Name = (string)dataReader["Name"];

                    Tests.Add(TestItem);
                }
            }
        }
        return Tests;
    }

    public Test CreateTest(Test Test)
    {
        List<DbParameter> parameterList = new List<DbParameter>();

        DbParameter TestIdParamter = base.GetParameterOut("TestId", SqlDbType.Int, Test.TestId);
        parameterList.Add(TestIdParamter);
        parameterList.Add(base.GetParameter("Name", Test.Name));

        base.ExecuteNonQuery("Test_Create", parameterList, CommandType.StoredProcedure);

        Test.TestId = (int)TestIdParamter.Value;

        return Test;
    }
 }

  public class Test  
  {  
    public object TestId { get; internal set; }  
    public object Name { get; internal set; }  
  }  

Connection String from Configurations

If we are interested to read Connection String from configurations then we may add reference to Microsoft.Extensions.Configuration.Abstractions and define a Construct with IConfiguration type of parameter to get connection string from configuratuions.



 public BaseDataAccess(IConfigurationRoot configuration)
 {
    this.ConnectionString = configuration["ConnectionStrings:DefaultConnection"];
 }