AngularJS and Breeze – A simple crud app – Part 2 – Adding create, delete, reset and is dirty checking.

 

In my previous post I created a simple [AngularJS – Breeze] edit view. In this post I will add the create, delete, reset and “is dirty” (entity change state tracking) to the simple view.

 

Before create

image

 

Create

The user clicked on the create button, so an “is dirty” icon is shown and a new row is added to the grid.

image

 

Save

When the user fills the fields of the new row and clicks save, the “is dirty” icon will disappear and the id field will automatically be filled by the id generated on the server in the database.

 

image

 

Reset

When the user create, updated and deleted some records and pressed save, the original state of the database can be restored by pressing the reset button.

image

 

 

index.html

<!DOCTYPE html>
<html data-ng-app="app">
<head>
<title data-ng-bind="title">Angular and Breeze</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no" />
<!-- Libraries -->
<link rel="stylesheet" type="text/css" href="../../../Libraries/FontAwesome/css/font-awesome.min.css" />
<link rel="stylesheet" type="text/css" href="../../../Libraries/Toastr/toastr.min.css" />

<!-- App -->
<link rel="stylesheet" type="text/css" href="app.css" />
</head>
<body>
<div class="spa-page" data-ng-controller="admin as vm">
<div class="spa-grid-toolbar">
<a class="spa-action-link" ng-click="vm.save()">save</a> |
<a class="spa-action-link" ng-click="vm.reset()">reset</a> |
<a class="spa-action-link" ng-click="vm.create()">create</a>
<i class="fa fa-exclamation-circle" 
title="Some data has change. Press save to save the changes to the server!" 
ng-show="vm.isDirty"></i>
</div>
<table class="spa-grid">
<thead>
<tr>
<th> </th>
<th ng-repeat='(key, prop) in vm.entityFields'>{{ prop.name }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="entity in vm.entities">
<td><a class="spa-action-link" ng-click="vm.delete(entity)">delete</a></td>
<td ng-repeat='(key, prop) in vm.entityFields'>
<input ng-disabled="{{vm.isReadOnlyField(prop.name)}}" 
type='text' 
ng-model='entity[prop.name]'>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Libraries -->
<script type="text/javascript" src="../../../Libraries/Angular/angular.js"></script>
<script type="text/javascript" src="../../../Libraries/Breeze/breeze.debug.js"></script>
<script type="text/javascript" src="../../../Libraries/Breeze/breeze.angular.js"></script>
<!-- Add toastr which needs jQuery (Breeze does not need jQuery) -->
<script type="text/javascript" src="../../../Libraries/jQuery/jquery-2.1.1.js"></script>
<script type="text/javascript" src="../../../Libraries/Toastr/toastr.js"></script>

<!-- Add breeze.savequeuing which needs Q (Breeze does not need Q)--> <script type="text/javascript" src="../../../Libraries/Q/q.min.js"></script> <script type="text/javascript" src="../../../Libraries/Breeze/breeze.savequeuing.js"></script> <!-- App --> <script type="text/javascript" src="app.js"></script> </body> </html>

 

 

app.js

// Use namespaces to prevent pollution of the global namespace.
var spa = spa || {};
spa.controllers = spa.controllers || {};
// Angular module [app].
spa.app = (function () {
'use strict';
var app = angular.module('app', [
'breeze.angular' // The breeze service module.
]);
})();
// Angular controller [admin].
spa.controllers.admin = (function () {
'use strict';
var controllerId = 'admin';
angular.module('app').controller(controllerId, ['$http', 'breeze', admin]);
function admin($http, breeze) {
var entityChangedToken = null;
var entityTypeName = "Employee";
var manager = null;
var vm = this;
vm.create = function () {
// Create entity by breeze.
var entity = manager.createEntity(entityTypeName);
// Show entity to user.
vm.entities.push(entity);
};
vm.delete = function (entity) {
// Delete from UI
vm.entities.pop(entity);
// Mark for deletion.
entity.entityAspect.setDeleted();
};
vm.entities = [];
vm.entityFields = null;
vm.isDirty = false;
vm.isReadOnlyField = function (name) {
// Make 'id' fields read-only.
return (name === 'id');
};
vm.reset = function () {
// Re-seed database and refetch data.
$http.get('/breeze/breeze/ReSeed').then(getData).then(handleResetResult).catch(showError);
};
vm.save = function () {
manager.saveChanges().then(handleSaveResult).catch(showError);
};
function handleStateChange(args) {
vm.isDirty = true;
}
function getData() {
// Get entities from the server.
var query = new breeze.EntityQuery().from(entityTypeName);
manager.executeQuery(query).then(handleGetDataResult).catch(showError);
}
function initialize() {
// Use camel case for entity properties.
breeze.NamingConvention.camelCase.setAsDefault();
// Configure and create EntityManager (double breeze is needed, because of .
manager = new breeze.EntityManager('/breeze/breeze');
manager.enableSaveQueuing(true);
registerForStateChange();
getData();
}
function handleGetDataResult(data) {
// Get entity fields from metadata.
var entityMetaData = manager.metadataStore.getEntityType(entityTypeName);
vm.entityFields = entityMetaData.dataProperties;
// Show the enties from the server.
vm.entities = data.results;
vm.isDirty = false;
}
function handleResetResult() {
vm.isDirty = false;
toastr.info("Database re-seeded.");
}
function handleSaveResult() {
vm.isDirty = false;
toastr.info("Changes saved to the server.");
}
function registerForStateChange() {
// Make sure to only subscribe once.
if (entityChangedToken) { return; }
// Register for state change.
entityChangedToken = manager.entityChanged.subscribe(handleStateChange);
}
function showError(e) {
// Show xhr error.
toastr.error(e);
}
initialize();
}
})();

 

app.css

/* Resets */
html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre,abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset,
form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, 
figcaption, figure, footer, header, hgroup, menu, nav, section, summary, time, mark, audio, video {
border: 0;              /* Prevent unnecessary white space. */
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
box-sizing: border-box; /*  Border boxing is used, so the padding, margin and borders are within 
the width and height of the element. */
margin: 0;              /* Prevent unnecessary white space. */
outline: 0;             /* Prevent unnecessary white space. */
padding: 0;             /* Prevent unnecessary white space. */
font-size: 100%;
vertical-align: baseline;
}
html, body {
height: 100%;       /* Full screen single page app. */
max-height: 100%;   /* Full screen single page app. */
}
body {
padding: 20px;
}
a {
cursor: pointer;
}
a.spa-action-link {
color: #428bca;
text-decoration: none;
}
a.spa-action-link:hover, a.spa-action-link:focus {
color: #2a6496;
text-decoration: underline;
}
div.spa-page {
border: 1px solid rgb(212, 212, 212);
height: 100%;       /* Full screen single page app. */
max-height: 100%;   /* Full screen single page app. */
padding: 20px;
position: relative;
}
div.spa-page > a {
margin-bottom: 10px;
}
div.spa-grid-toolbar i.fa-exclamation-circle {
margin-left: 10px;
}
.spa-grid input[type="text"] {
padding-left: 2px;
}

 

BreezeController.cs

namespace Research.UI.Web.Server.Controllers
{
using Breeze.ContextProvider;
using Breeze.ContextProvider.EF6;
using Breeze.WebApi2;
using Newtonsoft.Json.Linq;
using Research.UI.Web.Server.Model;
using System.Data.Entity.Migrations;
using System.Linq;
using System.Web.Http;
[BreezeController]
public class BreezeController : ApiController
{
private readonly EFContextProvider<ResearchDbContext> _contextProvider;
public BreezeController(): this(null)
{
}
public BreezeController(EFContextProvider<ResearchDbContext> contextProvider)
{
_contextProvider = contextProvider ??  new EFContextProvider<ResearchDbContext>();
}
[HttpGet]
public IQueryable<Employee> Employee()
{
return _contextProvider.Context.Employees;
}
[HttpGet]
public string Metadata()
{
string result = _contextProvider.Metadata();
return result;
}
[HttpGet]
public void ReSeed()
{
// Remove all records from the "Employees" table.
_contextProvider.Context.Database.ExecuteSqlCommand("truncate table Employees");
// Run an "Update-Database" EF migrations command, this will update the database schema 
// to the latest state and run the Seed() method.
var configuration = new Research.UI.Web.Migrations.Configuration(); configuration.ContextType = typeof(ResearchDbContext); var migrator = new DbMigrator(configuration); migrator.Update(); } [HttpPost] public SaveResult SaveChanges(JObject saveBundle) { return _contextProvider.SaveChanges(saveBundle); } } }

 

 

For the complete code, see:

https://github.com/roelvanlisdonk/Research/tree/master/Research/Research.UI.Web/Client/Features/AngularJS_and_Breeze/Part2

AngularJS and Breeze – A simple crud app – Part 1 –Automatic field data binding.

 

I wanted a really simple view in AngularJS, that would allow me to edit the data in a database table.

The view should show a grid containing a row for each record in the database.

Each record should show textboxes (html inputs) for all columns in the database, except the “Id” column.

In this way I could edit all data in a database table.

 

Here’s the end result:

 

image

 

When the user clicks on the “save” button, the data is persisted to the database.

 

image

 

 

Breeze.js

I decided to use Breeze.js for the data interaction.

The main trick I used to automatically data bind the Breeze.js entity data properties (fields) to the UI in AngularJS, is getting the names of the entity data properties (database table column names) from the metadata and then using a ng-repeat to loop over the table records and within this ng-repeat an other ng-repeat to loop over de Breeze entity data properties.

 

Getting table column names with Breeze (part of the client side code):

var entityMetaData = manager.metadataStore.getEntityType(“Employee”);

vm.entityFields = entityMetaData.dataProperties;

Automatically data bind, Breeze entity data properties (part of the client side code):

<tbody> <tr ng-repeat="entity in vm.entities"> <td ng-repeat='(key, prop) in vm.entityFields'>
<input ng-disabled="{{vm.isReadOnlyField(prop.name)}}" type='text' ng-model='entity[prop.name]'>
</
td> </tr> </tbody>

Client side code

<!DOCTYPE html>
<html data-ng-app="app">
<head>
<title data-ng-bind="title">Research page</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, 
user-scalable=no" />
<!-- Libraries --> <link rel="stylesheet" type="text/css" href="../../Libraries/Toastr/toastr.min.css" /> <!-- App --> <style> /* Resets */ html, body, div, span, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp, small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead,
tr, th, td, article, aside, canvas, details, figcaption, figure, footer, header, hgroup, menu, nav,
section, summary, time, mark, audio, video { border: 0; /* Prevent unnecessary white space. */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; /* Padding, margin and borders are within the width and height of the element. */ margin: 0; /* Prevent unnecessary white space. */ outline: 0; /* Prevent unnecessary white space. */ padding: 0; /* Prevent unnecessary white space. */ font-size: 100%; vertical-align: baseline; } html, body { height: 100%; /* Full screen single page app. */ max-height: 100%; /* Full screen single page app. */ } body { padding: 20px; } a { cursor: pointer; } a.spa-action-link { color: #428bca; text-decoration: none; } a.spa-action-link:hover, a.spa-action-link:focus { color: #2a6496; text-decoration: underline; } div.spa-page { border: 1px solid rgb(212, 212, 212); height: 100%; /* Full screen single page app. */ max-height: 100%; /* Full screen single page app. */ padding: 20px; position: relative; } div.spa-page > a { margin-bottom: 10px; } </style> </head> <body> <div class="spa-page" data-ng-controller="admin as vm"> <a class="spa-action-link" ng-click="vm.save()">save</a> <table> <thead> <tr> <th ng-repeat='(key, prop) in vm.entityFields'>{{ prop.name }}</th> </tr> </thead> <tbody> <tr ng-repeat="entity in vm.entities"> <td ng-repeat='(key, prop) in vm.entityFields'>
<
input ng-disabled="{{vm.isReadOnlyField(prop.name)}}"
type='text'
ng-model='entity[prop.name]'>
</
td> </tr> </tbody> </table> </div> <!-- Libraries --> <script type="text/javascript" src="../../Libraries/Angular/angular.js"></script> <script type="text/javascript" src="../../Libraries/Breeze/breeze.debug.js"></script> <script type="text/javascript" src="../../Libraries/Breeze/breeze.angular.js"></script> <!-- Add toastr which needs jQuery (Breeze does not need jQuery) --> <script type="text/javascript" src="../../Libraries/jQuery/jquery-2.1.1.js"></script> <script type="text/javascript" src="../../Libraries/Toastr/toastr.js"></script>
<!-- Add breeze.savequeuing which needs Q (Breeze does not need Q)-->
<script type="text/javascript" src="../../Libraries/Q/q.min.js"></script> <script type="text/javascript" src="../../Libraries/Breeze/breeze.savequeuing.js"></script> <!-- App --> <script type="text/javascript"> // Use namespaces to prevent pollution of the global namespace. var spa = spa || {}; spa.controllers = spa.controllers || {}; // Angular module [app]. spa.app = (function () { 'use strict'; var app = angular.module('app', [ 'breeze.angular' // The breeze service module. ]); })(); // Angular controller [admin]. spa.controllers.admin = (function () { 'use strict'; var controllerId = 'admin'; angular.module('app').controller(controllerId, ['breeze', admin]); function admin(breeze) { var manager = null; var entityTypeName = "Employee"; var vm = this; vm.entities = []; vm.entityFields = null; vm.isReadOnlyField = function (name) { // Make 'id' fields read-only. return (name === 'id'); }; vm.save = function () { manager.saveChanges().then(showInfo).catch(showError); }; function initialize() { // Use camel case for entity properties. breeze.NamingConvention.camelCase.setAsDefault(); // Configure and create EntityManager.
// The first breeze is part of the routing, second breeze is the name of the Web Api
// controller).
manager = new breeze.EntityManager('/breeze/breeze'); manager.enableSaveQueuing(true); // Get entities from the server. var query = new breeze.EntityQuery().from(entityTypeName); manager.executeQuery(query).then(handleRefresh).catch(showError); } function handleRefresh(data) { // Get entity fields from metadata. var entityMetaData = manager.metadataStore.getEntityType(entityTypeName); vm.entityFields = entityMetaData.dataProperties; // Show the enties from the server. vm.entities = data.results; } function showError(e) { // Show xhr error. toastr.error(e); } function showInfo() { // Show info message. toastr.info(entityTypeName + " saved!"); } initialize(); } })(); </script> </body> </html>

 

Sever side code

 

Employee.cs

namespace Research.UI.Web.Server.Model
{
public class Employee
{
    public int Id { get; set; }
    public string FirstName { get; set; }
   public string LastName { get; set; }
  public string PhoneNumber { get; set; }
}
}

ResearchDbContext.cs

namespace Research.UI.Web.Server.Model
{
using System.Collections.Generic;
using System.Data.Entity;
public class ResearchDbContext : DbContext
{
public DbSet<Employee> Employees { get; set; }
}    
}

BreezeWebApiConfig.cs

using System.Web.Http;
[assembly: WebActivator.PreApplicationStartMethod(
typeof(Research.UI.Web.App_Start.BreezeWebApiConfig), "RegisterBreezePreStart")]
namespace Research.UI.Web.App_Start {
///<summary>
/// Inserts the Breeze Web API controller route at the front of all Web API routes
///</summary>
///<remarks>
/// This class is discovered and run during startup; see
/// http://blogs.msdn.com/b/davidebb/archive/2010/10/11/light-up-your-nupacks-with-startup-code-and-webactivator.aspx
///</remarks>
public static class BreezeWebApiConfig {
public static void RegisterBreezePreStart() {
GlobalConfiguration.Configuration.Routes.MapHttpRoute(
name: "BreezeApi",
routeTemplate: "breeze{controller}/{action}"
);
}
}
}

 

BreezeController.cs

namespace Research.UI.Web.Server.Controllers
{
using Breeze.ContextProvider;
using Breeze.ContextProvider.EF6;
using Breeze.WebApi2;
using Newtonsoft.Json.Linq;
using Research.UI.Web.Server.Components;
using Research.UI.Web.Server.Model;
using System.Linq;
using System.Web.Http;
[BreezeController]
public class BreezeController : ApiController
{
private readonly EFContextProvider<ResearchDbContext> _contextProvider;
public BreezeController(): this(null)
{
}
public BreezeController(EFContextProvider<ResearchDbContext> contextProvider)
{
_contextProvider = contextProvider ??  new EFContextProvider<ResearchDbContext>();
}
[HttpGet]
public string Metadata()
{
string result = _contextProvider.Metadata();
return result;
}
[HttpGet]
public IQueryable<Employee> Employee()
{
return _contextProvider.Context.Employees;
}

[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _contextProvider.SaveChanges(saveBundle);
}
}
}

C# snippet: Add CommonAssemblyInfo.cs as link to all C# projects.

We use a CommonAssemblyInfo.cs file, to contain all common AssemblyInfo information for all projects.

Like:

[assembly: AssemblyVersion("0.0.0.0")]
[assembly: AssemblyFileVersion("0.0.0.0")]
[assembly: AssemblyCompanyAttribute("ADA ICT")]
[assembly: AssemblyCopyrightAttribute("Copyright © ADA ICT 2014")]

Our continuous integration system, alters the CommonAssemblyInfo.cs file add build time, to sync the TFS build version with the assemblies found in the solution.

 

When you add this CommonAssemblyInfo.cs file as a link to your project in Microsoft Visual Studio:

image

 

Microsoft Visual Studio, will merge the information in the AssemblyInfo.cs with the information in the CommonAssemblyInfo.cs.

 

If you don’t want to add this link manual, you can use the following C# code:

 

VsSolution.cs

namespace Research.Core.CodeGeneration
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
public class VsSolution
{
/// <summary>
/// Add CommonAssemblyInfo as link to a project.
/// </summary>
public string AddCommonAssemblyInfo(string content)
{
string result = string.Empty;
if (!string.IsNullOrWhiteSpace(content))
{
result = content;
var findRegEx = new Regex(@"<ItemGroup>.*
<Compile Include=""..\\SharedSource\\CommonAssemblyInfo.cs"">
<Link>CommonAssemblyInfo.cs</Link>
</Compile>.*
</ItemGroup>", RegexOptions.Singleline);
if (!findRegEx.IsMatch(content))
{
var replaceRegEx = new Regex(@"<ItemGroup>");
result = replaceRegEx.Replace(result, @"<ItemGroup>
<Compile Include=""..\\SharedSource\\CommonAssemblyInfo.cs"">
<Link>CommonAssemblyInfo.cs</Link>
</Compile>", 1);
}
}
return result;
}
}
}

This code can be used with a small helper class to change all *.csproj files on disk:

 

FileSystem.cs

namespace Research.Core.Components
{
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
public class FileSystem
{
public async Task FindAndReplace(string path, string searchPattern, SearchOption searchOption, 
Func<string, string> updateContent)
{
string[] files = await GetFilesAsync(path, searchPattern, searchOption);
foreach (string file in files)
{
string content = await ReadAllTextAsync(file);
content = updateContent(content);
await WriteAllTextAsync(file, content);
}
}
public async Task<string[]> GetFilesAsync(string path, string searchPattern, SearchOption searchOption)
{
return await Task.Factory.StartNew(() =>
{
return Directory.GetFiles(path, searchPattern, searchOption);
});
}
public async Task<string> ReadAllTextAsync(string path)
{
string result = await Task.Factory.StartNew(() => { return File.ReadAllText(path); });
return result;
}
public async Task WriteAllTextAsync(string path, string content)
{
await Task.Factory.StartNew(() => { File.WriteAllText(path, content); });
}
}
}

To execute the code use:

[TestMethod] public void FindAndReplace_should_replace_common_assemblyinfo() { var solution = new VsSolution(); var fs = new FileSystem(); Task task = fs.FindAndReplace(@"C:\Projects\TNT\RouteMaker\Main-v1.0\Source",

"AssemblyInfo.cs", System.IO.SearchOption.AllDirectories, solution.RemoveCommonAssemblyInfo); task.Wait(); }

Code can be found at:

https://github.com/roelvanlisdonk/Research

C# snippet: remove common assembly information from AssemblyInfo.cs

A C# method that I used to remove common assembly information from a AssemblyInfo.cs.

This method was used with a small FileSystem.cs class.

 

/// <summary>
/// Remove common assembly info from the given content.
/// Like:
/// - AssemblyCompany
/// - AssemblyCopyright
/// - AssemblyVersion
/// - AssemblyFileVersion
/// </summary>
public string RemoveCommonAssemblyInfo(string content)
{
string result = string.Empty;
if (!string.IsNullOrWhiteSpace(content))
{
result = content;
var regexes = new List<Regex>();
regexes.Add(new Regex(@"\r\n\[assembly: AssemblyCompany\(""{1}.*""{1}\)]"));
regexes.Add(new Regex(@"\r\n\[assembly: AssemblyCopyright\(""{1}.*""{1}\)]"));
regexes.Add(new Regex(@"\r\n\[assembly: AssemblyVersion\(""{1}.*""{1}\)]"));
regexes.Add(new Regex(@"\r\n\[assembly: AssemblyFileVersion\(""{1}.*""{1}\)]"));
regexes.Add(new Regex(@"\r\n\r\n// Version information.*""{1}\)]", RegexOptions.Singleline));
regexes.ForEach(x =>
{
result = x.Replace(result, string.Empty);
});
}
return result;
}

namespace Research.Core.Components { using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; public class FileSystem { public async Task FindAndReplace(string path, string searchPattern, SearchOption searchOption,

Func<string, string> updateContent) { string[] files = await GetFilesAsync(path, searchPattern, searchOption); foreach (string file in files) { string content = await ReadAllTextAsync(file); content = updateContent(content); await WriteAllTextAsync(file, content); } } public async Task<string[]> GetFilesAsync(string path, string searchPattern, SearchOption searchOption) { return await Task.Factory.StartNew(() => { return Directory.GetFiles(path, searchPattern, searchOption); }); } public async Task<string> ReadAllTextAsync(string path) { string result = await Task.Factory.StartNew(() => { return File.ReadAllText(path); }); return result; } public async Task WriteAllTextAsync(string path, string content) { await Task.Factory.StartNew(() => { File.WriteAllText(path, content); }); } } }

 

To replace all common assembly info found in all AssemblyInfo.cs files in a folder, use the code:

 

var solution = new VsSolution(); var fs = new FileSystem(); Task task = fs.FindAndReplace(@"C:\Projects\Github\roelvanlisdonk\Research\Main",

"AssemblyInfo.cs", System.IO.SearchOption.AllDirectories, solution.RemoveCommonAssemblyInfo); task.Wait();

 

Code can be found at: https://github.com/roelvanlisdonk/Research

Dynamically call C# instance method by "string" name, without performance overhead.

 

There is no noticeable difference in calling a C# instance method directly or dynamically by "string" name, when you use a cached compiled LINQ expression.

 

In my test case I call a method 1.000.000 times directly and dynamically and both take 1,6s:

namespace Research.UnitTests
{
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using System.Linq.Expressions;
using System.Collections.Generic;
using System.Reflection;
[TestClass]
public class Research
{
[TestMethod]
public void TestWithTiming()
{
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
var calculator = new Calculator();           
// Get "Calculate" method.
MethodInfo methodInfo = typeof(Calculator).GetMethod("Calculate", new Type[] { typeof(int) });
// Create parameter "i" for Calculate method.
ParameterExpression param = Expression.Parameter(typeof(int), "i");           
// Create "thisParameter" needed to call instance methods.
var thisParameter = Expression.Constant(calculator);
// Create an expression for the method call "Calculate" and specify its parameter(s).
// If the method was a static method, the "thisParameter" must be removed.
MethodCallExpression methodCall = Expression.Call(thisParameter, methodInfo, param);
// Create lambda expression from MethodCallExpression.
Expression<Func<int, string>> lambda = Expression.Lambda<Func<int, string>>(
methodCall,
new ParameterExpression[] { param }
);
// Compile lambda expression to a Func<>.
Func<int, string> func = lambda.Compile();
// Dynamically call instance method by "name".
// Duration: 1620 ms (1,6s).
for (int i = 0; i < 1000000; i++)
{
string result = func(i);
}
// Direct call
// Duration: 1605ms (1,6s)
for (int i = 0; i < 1000000; i++)
{
string result = calculator.Calculate(i);
}
watch.Stop();
System.Console.WriteLine(watch.Elapsed.TotalMilliseconds);
}
}
public class Calculator
{
public string Calculate(int i)
{
string result = string.Empty;
// Execute some code.
DateTime now = DateTime.Now;
DateTime nextDay = now.AddDays(i);
result = nextDay.ToString();
return result;
}
}
}

Casting when dealing with nullable fields in a SqlDataReader

When dealing with nullable fields in a SqlDataReader, use:

int? field_a = reader["field_a"] as int?;
string field_b = reader["field_a"] as string;

instead of:

int? field_a = Convert.ToInt32(reader["field_a"]);
string field_b = Convert.ToString(reader["field_a"]);

http://stackoverflow.com/questions/2141575/how-to-efficiently-convert-cast-a-sqldatareader-field-to-its-corresponding

How to convert a string to a stream, without using encoding in C#

If you want to convert a string to a stream, without using encoding. You can use the following string extension:

 

usage

namespace PTB.Cs.Test.Research
{
using PTB.Cs.Extensions;
using System;
using System.IO;
using Xunit;
public class RliTester
{
[Fact]
public void Test()
{
string subject = "Some text.";
long expected = 10;
long actual = 0;
using (Stream stream = subject.ToStream())
{
actual = stream.Length;
}    
Assert.Equal(expected, actual);
}
}
}

Code

namespace Extensions
{
using System.IO;
public static class StringExtensions
{
/// <summary>
/// Convert a string to a stream, without using encoding.
/// Don't forget to dispose the "result" stream in the calling method.
/// </summary>
/// <param name="subject">The string to convert.</param>
/// <returns>A stream with position set to 0.</returns>
public static Stream ToStream(this string subject)
{
var result = new MemoryStream();
using(var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))
{
writer.Write(subject);
writer.Flush();
stream.Position = 0;
stream.CopyTo(result);
result.Position = 0;
}
return result;
}
}
}

How to change Application scope Settings (that are read-only) at runtime in C#

If you set your settings to the "Application" scope the settings will be read-only.

If you want to change these settings at runtime, you can use the following code from my unit test project:

 

First create a Settings class in your unit test project:

Right click on the unit test project and choose "Properties".

Click on "Settings":

Click on "This project does not contain a default settings file. Click here to create one."

 

image

 

At two test settings: "MyStringSetting" and "MyInSetting"":

 

image

 

image

 

The App.config will be changed like:

image

 

Now to show the code that changes the settings at runtime:

 

namespace UnitTestProject2
{
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using UnitTestProject2.Properties;
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var settings = new Settings();
Assert.AreEqual(settings.MyStringSetting, "This is some random text.");
settings.ChangeSetting("MyStringSetting", "This is some other text.");
Assert.AreEqual(settings.MyStringSetting, "This is some other text.");
Assert.AreEqual(settings.MyIntSetting, 999);
settings.ChangeSetting("MyIntSetting", 100);
Assert.AreEqual(settings.MyIntSetting, 100);
}
}
}
namespace UnitTestProject2.Properties
{
internal sealed partial class Settings
{
public void ChangeSetting<T>(string key, T value)
{
this[key] = value;
}
}
}

How to get the absolute root folder path of a ASP .NET website / MVC website.

 

The following code result in my case to rootFolderPath = "C:\inetpub\wwwroot\MvcApplication1".

Uri uri = new System.Uri(Assembly.GetAssembly(typeof(MvcApplication)).CodeBase);
string binFolderPath = Path.GetDirectoryName(uri.LocalPath);
string rootFolderPath = new DirectoryInfo(binFolderPath).Parent.FullName;