private const string FileName = @"C:\myFile.xls"; private const string XmlFileName = @"c:\\myFile.xml"; private static void CreateXmlFile() { DataTable data = new ExcelReader().ReadFirstSheet(FileName); var xdoc = new XDocument(); var root = new XElement("ReportEntitlementMappings"); foreach (DataRow row in data.Rows) { var mapping = new XElement("Mapping"); mapping.SetAttributeValue("From", row[0]); mapping.SetAttributeValue("To", row[1]); root.Add(mapping); } xdoc.Add(root); xdoc.Save(XmlFileName); } public interface IExcelReader { DataTable ReadFirstSheet(string fileName); DataTableCollection ReadAllSheets(string fileName); } public class ExcelReader : IExcelReader { const string ConnectionStringFormat = "Provider=Microsoft.Jet.OLEDB.4.0; data source={0}; Extended Properties=Excel 8.0;"; public DataTable ReadFirstSheet(string fileName) { return ReadAllSheets(fileName)[0]; } public DataTableCollection ReadAllSheets(string fileName) { var adapter = new OleDbDataAdapter("SELECT * FROM [Mappings$]", ConnectionStringFormat.FormatWith(fileName)); var ds = new DataSet(); adapter.Fill(ds); return ds.Tables; } }EPPLUS tool supports reading from Excel 2007 and 2010 files: http://epplus.codeplex.com/
Wednesday 26 November 2014
Create Xml from Excel
Friday 21 November 2014
Why you should use ConcurrentBag with Parallel Foreach?
namespace ConsoleApp { using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; class Program { static void Main(string[] args) { var targetCount = 10000; // Shows 7456! RunThreadUnsafeDemo(targetCount); // Shows 10000 RunThreadSafeDemo(targetCount); Console.ReadKey(); } // The target count is less than actual. static void RunThreadUnsafeDemo(int count) { var sourceList = Enumerable.Range(1, count); var targetList = new List(); // Bad idea Parallel.ForEach(sourceList, i => { targetList.Add(i); }); Console.WriteLine("Thread Unsafe Count: {0}.", targetList.Count); } // The target count equals to actual. static void RunThreadSafeDemo(int count) { var sourceList = Enumerable.Range(1, count); var targetList = new ConcurrentBag (); // Good one Parallel.ForEach(sourceList, i => { targetList.Add(i); }); Console.WriteLine("Thread Safe Count: {0}.", targetList.Count); } } }
Tuesday 5 August 2014
Command Query Responsibility Segregation (CQRS)
Command Query Responsibility Segregation (CQRS)
- A design pattern that suggests we should separating methods that change state from those that don't. In which way, we can even separate the databases used for Reads and Writes and therefore being able to optimize such databases for Reads and Writes.
- Two main behaviours of a model is to be updated and displayed. For instance, you store a product in certain way and present it to the UI in another way.
- Query Models are to read data from database to be displayed for the presentation.
- Command Models are to execute Create/Update/Delete commands from the Presentation to the database.
- Syncing the separate databases with each other would be an overhead and one way to achieve it would be using Replication models (publisher and subscribers)
- The fundamental idea is that we should divide an object's methods into two separated categories:
- Queries: Return a result and do not change the observable state of the system (are free of side effects).
- Commands: Change the state of a system but do not return a value.
Example:
You'd refactor and group the methods of the Product repository into separate classes:
- ProductQuery
- ProductSaveCommand
- ProductDeleteCommand
Further reading:
- http://www.codeproject.com/Articles/555855/Introduction-to-CQRS
- http://msdn.microsoft.com/en-us/library/jj591573.aspx
- CQRS: http://cqrs.wordpress.com/documents/cqrs-introduction/
Event Sourcing
http://cqrs.wordpress.com/documents/cqrs-and-event-sourcing-synergy/
http://cqrs.wordpress.com/documents/cqrs-introduction/
http://geteventstore.com/
Monday 28 July 2014
PowerShell
Run PowerShell Prompt
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
PowerShell Script File
A PowerShell script is simply a text file with a .ps1 extension that contains a list of commands PowerShell should execute.
Host Version
$host.version
PowerShell Modules
http://technet.microsoft.com/en-us/library/hh847741.aspx
Create App Pool in IIS
# create app pool
if(Test-Path IIS:\AppPools\$websiteName)
{
echo "App pool exists - removing"
Remove-WebAppPool $websiteName
gci IIS:\AppPools
}
$pool = New-Item IIS:\AppPools\$websiteName
$pool.processModel.identityType = 4 #ApplicationPoolIdentity
$pool | set-item
Write-Host "app pool created"
Create Website in IIS
$iisApp = New-Item iis:\Sites\$websiteName -bindings @{protocol="http";bindingInformation=":80:$websiteName"} -physicalPath $destinationFolder -force
$iisApp | Set-ItemProperty -Name "applicationPool" -Value $websiteName
Copy File Contents
Copy-Item ($PSScriptRoot + "\Ext\*") $destinationExtFolder -recurse -force
Add to AppSettings
$webConfig = ($interactCollectionsFolder + "\web.config")
$doc = (Get-Content $webConfig) -as [Xml]
$appSettings = $doc.SelectSingleNode("//appSettings")
if ($appSettings -eq $null)
{
$appSettings = $doc.CreateElement("appSettings")
$doc.configuration.AppendChild($appSettings)
}
$key = $appSettings.SelectSingleNode("//add[@name='CsvFilePath']")
if ($key -eq $null)
{
$key = $doc.CreateElement("add")
$key.SetAttribute("name", "CsvFilePath")
$appSettings.AppendChild($key)
}
$key.SetAttribute("value", $destinationCsvFilePath)
$doc.Save($webConfig)
TransformXml.ps1
#Notes: To transform a web.config or app.config with a Transform Config file:
$XmlTransformAssemblyPath = $PSScriptRoot + "\Lib\Microsoft.Web.XmlTransform.dll"
function TransformXml($xmlPath, $xdtPath)
{
write-host
write-host 'Transforming...' $xmlPath
write-host 'With...' $xdtPath
Add-Type -LiteralPath "$XmlTransformAssemblyPath"
$xmlPathdoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmlPathdoc.PreserveWhitespace = $true
$xmlPathdoc.Load($xmlPath);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdtPath);
if ($transf.Apply($xmlPathdoc) -eq $false)
{
throw "Transformation failed."
}
$xmlPathdoc.Save($xmlPath);
write-host 'Config transformed and saved.'
write-host
}
ExecuteSqlScripts.ps1
#Notes: To execute a script file against a database from web.config or app.config
function ExecuteSqlScripts($connectionString, $sqlScriptsPath)
{
write-host
write-host 'Executing SQL Scripts from ' $sqlScriptsPath
write-host
$sqlScripts = [System.IO.File]::ReadAllLines($sqlScriptsPath)
ExecuteNonQuery $connectionString $sqlScripts
write-host 'SQL Scripts executed successfully.'
write-host
}
function ExecuteNonQuery($connectionString, $sqlScripts)
{
Try{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $connectionString
$SqlConnection.Open()
foreach($sqlScriptLine in $sqlScripts)
{
if($sqlScriptLine -ne "GO" -And $sqlScriptLine -ne "go")
{
#Preparation of SQL packet
$sqlCommandText += $sqlScriptLine + "`n"
}
else
{
$SQLCommand = New-Object System.Data.SqlClient.SqlCommand($sqlCommandText, $SQLConnection)
$result = $SQLCommand.ExecuteNonQuery();
$sqlCommandText = ""
}
}
}
Catch [System.Exception]
{
Write-Host 'An error occurred: ' + $_.Exception
}
Finally{
$SqlConnection.Close()
$SqlConnection.Dispose()
}
}
GetConnectionString.ps1
# Gets the connection string value from app.config or web.config based on the name of the connection string.
function GetConnectionString($configPath, $name)
{
$xml = [xml](Get-Content $configPath)
$connectionString = ($xml.configuration.connectionStrings.add | where {$_.name -eq $name})
return $connectionString.connectionString
}
%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
PowerShell Script File
A PowerShell script is simply a text file with a .ps1 extension that contains a list of commands PowerShell should execute.
Host Version
$host.version
PowerShell Modules
http://technet.microsoft.com/en-us/library/hh847741.aspx
Reusable Functions
Create App Pool in IIS
# create app pool
if(Test-Path IIS:\AppPools\$websiteName)
{
echo "App pool exists - removing"
Remove-WebAppPool $websiteName
gci IIS:\AppPools
}
$pool = New-Item IIS:\AppPools\$websiteName
$pool.processModel.identityType = 4 #ApplicationPoolIdentity
$pool | set-item
Write-Host "app pool created"
Create Website in IIS
$iisApp = New-Item iis:\Sites\$websiteName -bindings @{protocol="http";bindingInformation=":80:$websiteName"} -physicalPath $destinationFolder -force
$iisApp | Set-ItemProperty -Name "applicationPool" -Value $websiteName
Copy File Contents
Copy-Item ($PSScriptRoot + "\Ext\*") $destinationExtFolder -recurse -force
Add to AppSettings
$webConfig = ($interactCollectionsFolder + "\web.config")
$doc = (Get-Content $webConfig) -as [Xml]
$appSettings = $doc.SelectSingleNode("//appSettings")
if ($appSettings -eq $null)
{
$appSettings = $doc.CreateElement("appSettings")
$doc.configuration.AppendChild($appSettings)
}
$key = $appSettings.SelectSingleNode("//add[@name='CsvFilePath']")
if ($key -eq $null)
{
$key = $doc.CreateElement("add")
$key.SetAttribute("name", "CsvFilePath")
$appSettings.AppendChild($key)
}
$key.SetAttribute("value", $destinationCsvFilePath)
$doc.Save($webConfig)
TransformXml.ps1
#Notes: To transform a web.config or app.config with a Transform Config file:
$XmlTransformAssemblyPath = $PSScriptRoot + "\Lib\Microsoft.Web.XmlTransform.dll"
function TransformXml($xmlPath, $xdtPath)
{
write-host
write-host 'Transforming...' $xmlPath
write-host 'With...' $xdtPath
Add-Type -LiteralPath "$XmlTransformAssemblyPath"
$xmlPathdoc = New-Object Microsoft.Web.XmlTransform.XmlTransformableDocument;
$xmlPathdoc.PreserveWhitespace = $true
$xmlPathdoc.Load($xmlPath);
$transf = New-Object Microsoft.Web.XmlTransform.XmlTransformation($xdtPath);
if ($transf.Apply($xmlPathdoc) -eq $false)
{
throw "Transformation failed."
}
$xmlPathdoc.Save($xmlPath);
write-host 'Config transformed and saved.'
write-host
}
ExecuteSqlScripts.ps1
#Notes: To execute a script file against a database from web.config or app.config
function ExecuteSqlScripts($connectionString, $sqlScriptsPath)
{
write-host
write-host 'Executing SQL Scripts from ' $sqlScriptsPath
write-host
$sqlScripts = [System.IO.File]::ReadAllLines($sqlScriptsPath)
ExecuteNonQuery $connectionString $sqlScripts
write-host 'SQL Scripts executed successfully.'
write-host
}
function ExecuteNonQuery($connectionString, $sqlScripts)
{
Try{
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = $connectionString
$SqlConnection.Open()
foreach($sqlScriptLine in $sqlScripts)
{
if($sqlScriptLine -ne "GO" -And $sqlScriptLine -ne "go")
{
#Preparation of SQL packet
$sqlCommandText += $sqlScriptLine + "`n"
}
else
{
$SQLCommand = New-Object System.Data.SqlClient.SqlCommand($sqlCommandText, $SQLConnection)
$result = $SQLCommand.ExecuteNonQuery();
$sqlCommandText = ""
}
}
}
Catch [System.Exception]
{
Write-Host 'An error occurred: ' + $_.Exception
}
Finally{
$SqlConnection.Close()
$SqlConnection.Dispose()
}
}
GetConnectionString.ps1
# Gets the connection string value from app.config or web.config based on the name of the connection string.
function GetConnectionString($configPath, $name)
{
$xml = [xml](Get-Content $configPath)
$connectionString = ($xml.configuration.connectionStrings.add | where {$_.name -eq $name})
return $connectionString.connectionString
}
Monday 7 July 2014
NServiceBus
- NServiceBus focus on Asynchronous One-Way Messaging
- Download from their site or better use NuGet:
Install-Package NServiceBus
- By default NServiceBus uses Log4Net for its logging and you can install it using NuGet again:
Install-Package log4net
- NServiceBus Documentation
- MSMQ: default queueing system
- RavenDB: default persistent store
Thursday 3 July 2014
NuGet
- Download NuGet Package Manager for Visual Studio
- PM Console Powershell Reference
- You can also create and publish your custom NuGet Package to the NuGet Package Gallery as well downloading existing ones.
Reinstall a Package:
Update-Package –reinstall SpecFlow
Install a Specific Version of a Package
Install-Package SpecFlow -Version 1.9
Uninstall a Package
Uninstall-Package SpecFlolw -Force
Uninstall a Package
Uninstall-Package SpecFlolw -Force
Friday 20 June 2014
Gherkin Language and BDD
Gherkin Language
Point:
A feature or user story is comprised of 1 or more scenarios.
Point:
Each Scenario is defined by GIVEN WHEN THEN sections as explained below:
- GIVEN is about
- Preconditions
- Setups
- Arrangements
- Preparations
- All the parameters and preparations needed before the Action can be taken
- Multiple steps can be combined with each other using AND or OR
- Preparations such as GIVEN an existing user with name William enters William in the text box
- WHEN is about
- Action that is taken by the user to expect a certain behavior
- Multiple steps can be combined with each other using AND or OR
- Actions such as Clicking on a Button, Entering a Number, Navigating to a Page
- THEN is about
- Expected behaviour
- How the behavior can be verified
- Multiple steps can be combined with each other using AND or OR
Point:
Each edge case of a feature should be considered as a separate scenario.
Examples
GIVEN user goes to www.google.com
AND enter "Technology" in the search box
WHEN the search button is clicked
THEN a list of latest adverts related to "Technology" should be shown to the use
Monday 12 May 2014
Web API Documentation
ApiExplorer:
- Install it from: http://go.microsoft.com/fwlink/?LinkId=282650
- Enable Xml documentation from the Build tab in the Project Properties section so that the Xml files are writen into an Xml file.
- Add some comments to the Controller or Properties
- When you build the app then the Xml file
You can either read the xml comments from an xml file or via the code XML documentation comments.
Default:
~/App_Data/XmlDocument.xml
- http://www.asp.net/web-api/overview/creating-web-apis/creating-api-help-pages
- http://blogs.msdn.com/b/yaohuang1/archive/2012/09/30/asp-net-web-api-help-page-part-1-basic-help-page-customizations.aspx
- http://blogs.msdn.com/b/yaohuang1/archive/2012/12/10/asp-net-web-api-help-page-part-3-advanced-help-page-customizations.aspx
- http://blogs.msdn.com/b/yaohuang1/archive/2012/05/13/asp-net-web-api-introducing-iapiexplorer-apiexplorer.aspx
- http://blogs.msdn.com/b/yaohuang1/archive/2012/05/21/asp-net-web-api-generating-a-web-api-help-page-using-apiexplorer.aspx
Friday 11 April 2014
Windows Commands
c:\Windows\System32\inetsrv\appcmd list wp
List all processes related to the ASP.NET worker processes
List all processes related to the ASP.NET worker processes
Monday 24 March 2014
Email Delivery Systems
If you have the skills/time/budget available, you could of course create your own bespoke email delivery system tailored to your needs for example when orders received via your e-commerce website.
Alternatively you may want to evaluate the potential of using one of the existing systems other Companies use in the industry:
Alternatively you may want to evaluate the potential of using one of the existing systems other Companies use in the industry:
Wednesday 29 January 2014
TSQL IN clause Generator
The below class, generates TSQL IN Clauses. Basically, you'd need them when you'd have a large list of items and you'd like to pass to a SELECT statement in Oracle, SQL, ODBC or any other database.
For example, Oracle 10g has got a limitation for 1000 items in the IN clause and here is how you can get around it:
For example, if you have a list of 2000 productIds, this will generate something like this:
For example, Oracle 10g has got a limitation for 1000 items in the IN clause and here is how you can get around it:
public interface ISqlInClauseGenerator { string Generate(string[] items, string columnName, int inClauseLimit = 1000); } public class SqlInClauseGenerator : ISqlInClauseGenerator { const string EndClause = ")"; const string StartClausePattern = "{0} IN ("; const string ConnectorClausePattern = ") OR " + StartClausePattern; public string Generate(string[] items, string columnName, int inClauseLimit = 1000) { if (items.IsNullOrEmpty()) { return string.Empty; } string startClause = string.Format(StartClausePattern, columnName); string connectorClause = string.Format(ConnectorClausePattern, columnName); var sb = new StringBuilder(startClause); for (int i = 0; i < items.Length; i++) { if (i == 0) { // start sb.Append(items[i]); } else if (i % inClauseLimit == 0) { // start a new IN clause sb.Append(connectorClause); sb.Append(items[i]); } else { // continue sb.Append("," + items[i]); } if (i == items.Length - 1) { // it's the last item sb.Append(EndClause); } } return sb.ToString(); } }
For example, if you have a list of 2000 productIds, this will generate something like this:
"ProductId IN (1,2,3...1000) OR ProductId IN (1001...2000)"
Monday 20 January 2014
Using Git with TFS
- Download Git for TFS: http://www.microsoft.com/en-gb/download/details.aspx?id=30474
- Getting Started: http://blogs.msdn.com/b/mvpawardprogram/archive/2013/11/13/git-for-tfs-2013.aspx
Subscribe to:
Posts (Atom)