Tuesday, September 4, 2012

Creating XML tranformations for all environment configs without deploying application

Edit project file and paste following code at the end of the file.

<Target Name="BeforeBuild">
    <MakeDir Directories="$(OutDir)TransformedConfigs" Condition="!Exists('$(OutDir)TransformedConfigs')"/>
    <TransformXml Source="Web.config" Transform="Web.Dev.config" Destination="$(OutDir)TransformedConfigs\Web.Dev.config" />
    <TransformXml Source="Web.config" Transform="Web.QA.config" Destination="$(OutDir)TransformedConfigs\Web.QA.config" />
    <TransformXml Source="Web.config" Transform="Web.UAT.config" Destination="$(OutDir)TransformedConfigs\Web.UAT.config" />
    <TransformXml Source="Web.config" Transform="Web.Prod.config" Destination="$(OutDir)TransformedConfigs\Web.Prod.config" />
</Target>


This will create TransformedConfigs folder inside bin of the project and will add all specified transformed configs.
 

Saturday, July 7, 2012

Web.Config transformations

Add setting to web.config and then create one configuration file per environment e.g. web.DEV.config,web.Test.Config,web.UAT.config,web.Production.Config

Each of these configuration files will contain environment specific settings which we want to apply to base web.config such as connection strings,service endpoints etc.

To generate final web.config, we need to set xml transformation rules in  these web.config.
e.g.

<add name="Test" connectionString="newConnectionString" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />

<replaceAll>
    <endpointAddresses
       xdt:Locator="XPath(/configuration/system.serviceModel//*@contract='Contract1Name'])"
       xdt:Transform="SetAttributes(address)" address="newEndpointAddress" />      
 </replaceAll>

If we want to replace entire section:

<system.web>
    <compilation targetFramework="4.0" xdt:Transform="Replace">
      <assemblies>
        <add assembly="AssemblyName, Version=VersionInfo, Culture=neutral,       PublicKeyToken=publicToken" />
      </assemblies>
    </compilation>
</system.web>
<add name="Test" connectionString="newConnectionString" xdt:Transform="SetAttributes" xdt:Locator="Match(name)" />

TFS Build Arguments to deploy a build

Build arguments:

/p:Configuration=ConfigurationName
/p:DeployOnBuild=True
/p:DeployTarget=MsDeployPublish
 /p:CreatePackageOnPublish=False
/p:MSDeployPublishMethod=RemoteAgent
  /p:AllowUntrustedCertificate=True
/p:MSDeployServiceUrl=ServerName
/p:DeployIisAppPath=ApplicationName
/p:UserName=UserName /p:Password=Password

Thursday, May 10, 2012

Automapper Ignore All Non Existing Properties

Code Snippet
  1. public static IMappingExpression<TSource, TDestination> IgnoreAllNonExisting<TSource, TDestination>
  2.                                             (this IMappingExpression<TSource, TDestination> expression)
  3.         {
  4.             var sourceType = typeof(TSource);
  5.             var destinationType = typeof(TDestination);
  6.             var existingMaps = Mapper.GetAllTypeMaps().First(x => x.SourceType.Equals(sourceType) && x.DestinationType.Equals(destinationType));
  7.             foreach (var property in existingMaps.GetUnmappedPropertyNames())
  8.             {
  9.                 expression.ForMember(property, opt => opt.Ignore());
  10.             }
  11.             return expression;
  12.         }

Monday, May 7, 2012

Aspect Oriented Programming (AOP)

There are many posts available to add AOP to the appliaction but as a starter it was very difficult to follow some of them. so just trying to make an attempt to make this simpler. Recently I wanted to add logging ,auditing, exception handling to an existing appliaction and going by regular norms to add try / catch/ finally blocks for this could be cumbersome so I was searching for the better approach and came across this concept of AOP. This is used when we want to implement a ceratin functionality across platforms in an application e.g. logging. so with this, we intercept the method callls wrap it with information we need to add and execute this. The application I built is pretty straight forward calculator app.
Calculator
  1. using System;
  2.  
  3. namespace AOP
  4. {
  5.     public interface ICalculator
  6.     {
  7.         int Add(int i, int j);
  8.         int Subtract(int i, int j);
  9.         int Multiply(int i, int j);
  10.         int Divide(int i, int j);
  11.     }
  12.  
  13.     public class Calculator : ICalculator
  14.     {
  15.         public int Add(int i, int j)
  16.         {
  17.             var result = i + j;
  18.             Console.WriteLine("result:{0}", result);
  19.             return result;
  20.         }
  21.  
  22.         public int Subtract(int i, int j)
  23.         {
  24.             var result = i - j;
  25.             Console.WriteLine("result:{0}", result);
  26.             return result;
  27.         }
  28.  
  29.         public int Multiply(int i, int j)
  30.         {
  31.             var result = i * j;
  32.             Console.WriteLine("result:{0}", result);
  33.             return result;
  34.         }
  35.  
  36.         public int Divide(int i, int j)
  37.         {
  38.             var result = i / j;
  39.             Console.WriteLine("result: {0}", result);
  40.             return result;
  41.         }
  42.     }
  43. }
We need to log information like //Time : Method {MethodName} execution started //Input parameters : {ParamterName} {ParameterValue} // Output value : {result} //Time taken for execution To add this much information to each method, will make the code with difficult to read / manage and violate Single responsibility and DRY pronciples. so to fix all this, we can intercept each method call of interface and let Castle Windsor create a proxy of this class to help with interception. As I prefer StructureMap as IoC container, I am using EnrichWith feature of StrutureMap to link proxy from Castle Windsor to enrich Calculator functions with logging functionality.
Program.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using Castle.DynamicProxy;
  6. using StructureMap;
  7. using log4net;
  8.  
  9. namespace AOP
  10. {
  11.     class Program
  12.     {
  13.         static void Main(string[] args)
  14.         {
  15.             log4net.Config.XmlConfigurator.Configure();
  16.             ObjectFactory.Initialize(x =>
  17.                                          {
  18.                                              x.Scan(y =>
  19.                                                         {
  20.                                                             y.TheCallingAssembly();
  21.                                                             y.WithDefaultConventions();
  22.                                                         });
  23.                                              var proxy = new ProxyGenerator();
  24.                                              x.For<ICalculator>().EnrichAllWith(
  25.                                                  p =>
  26.                                                  proxy.CreateInterfaceProxyWithTarget<ICalculator>(p,
  27.                                                                                                    new LogInterceptor(
  28.                                                                                                        LogManager.GetLogger(typeof(Program))
  29.                                                                                                        )));
  30.                                          });
  31.  
  32.             
  33.  
  34.             ObjectFactory.GetInstance<ICalculator>().Add(2, 3);
  35.  
  36.             ObjectFactory.GetInstance<ICalculator>().Subtract(3,2);
  37.  
  38.             ObjectFactory.GetInstance<ICalculator>().Multiply(2,3);
  39.  
  40.             ObjectFactory.GetInstance<ICalculator>().Divide(4,2);
  41.  
  42.             Console.ReadLine();
  43.         }
  44.     }
  45.  
  46.     
  47.  
  48.     
  49. }
and finally the LoggingInterceptor which implements IInterceptor from Catsle.DynamicProxy namespace.
LogInterceptor
  1. using System;
  2. using System.Linq;
  3. using Castle.DynamicProxy;
  4. using log4net;
  5.  
  6. namespace AOP
  7. {
  8.     public class LogInterceptor : IInterceptor
  9.     {
  10.         private readonly ILog _logger;
  11.         public LogInterceptor(ILog logger)
  12.         {
  13.             _logger = logger;
  14.         }
  15.  
  16.         public void Intercept(IInvocation invocation)
  17.         {
  18.             try
  19.             {
  20.                 var parameters = invocation.Method.GetParameters().ToList();
  21.                 _logger.InfoFormat("Started Logging method: {0}", invocation.Method.Name);
  22.                 for (int i = 0; i < parameters.Count; i++)
  23.                 {
  24.                     _logger.InfoFormat(" Parameter[{2}] Name: {0} Value: {1}", parameters[i].Name, invocation.Arguments[i], i);
  25.                 }
  26.  
  27.                 invocation.Proceed();
  28.                 _logger.InfoFormat("Logged Successfully return value: {0}", invocation.ReturnValue);
  29.                 _logger.Info("------------------------------------------------------------------------");
  30.                 
  31.             }
  32.             catch (Exception ex)
  33.             {
  34.                _logger.ErrorFormat("Exception occurred: {0}", ex.Message);
  35.             }
  36.             finally
  37.             {
  38.                 _logger.Info("Logging Completed");
  39.             }
  40.  
  41.         }
  42.     }
  43. }
Log4Net Configuration:
  1. <? xml version= "1.0" ?>
  2. < configuration >
  3.   < configSections >
  4.     < section name= "log4net" type= "log4net.Config.Log4NetConfigurationSectionHandler,Log4net" />
  5.   </ configSections >
  6.   < startup >
  7.     < supportedRuntime version= "v4.0" sku= ".NETFramework,Version=v4.0" />
  8.   </ startup >
  9.   < log4net >
  10. < root >
  11. < level value= "DEBUG" />
  12. < appender-ref ref= "LogFileAppender" />
  13. </ root >
  14. < appender name= "LogFileAppender" type= "log4net.Appender.RollingFileAppender" >
  15. < param name= "File" value= "C:\logs\test\log.txt" />
  16. < param name= "AppendToFile" value= "true" />
  17. < maximumFileSize value= "10MB" />
  18. < staticLogFileName value= "true" />
  19. < layout type= "log4net.Layout.PatternLayout" >
  20. < param name= "ConversionPattern" value= "%-5p%d{yyyy-MM-dd hh:mm:ss} – %m%n" />
  21. </ layout >
  22. </ appender >
  23. </ log4net >
  24. </ configuration >

Monday, February 20, 2012

MVC ListBox using EditorTemplates and KnockoutJS

Editor templates are really handy tool when we want to create controls for a specific type. Recently I had a requiremnt to show winform styled ListBox control with lists for Available/Selected and allowing user to move items from one collection to other and move items up/down in selected collection. It was similar to this:
Step 1: Considering this as a pretty common functionality in our application,I created a ListSource class to support this UI.
MvcLists\Models\ListSource.cs
  1. using System.Collections.Generic;
  2.  
  3. namespace MvcLists.Models
  4. {
  5.     public class ListSource
  6.     {
  7.         public List<Item> Available { get; set; }
  8.         public List<Item> Selected { get; set; }
  9.     }
  10.  
  11.     public class Item
  12.     {
  13.         public int Value { get; set; }
  14.         public string Text { get; set; }
  15.     }
  16. }
Step 2: Add a property of type ListSource to Model.
MvcLists\Models\Person.cs
  1. public class Person
  2.     {
  3.         [Tooltip("Enter First Name")]
  4.         public string FirstName { get; set; }
  5.         [Tooltip("Enter Last Name")]
  6.         public string LastName { get; set; }
  7.         [Tooltip("Enter SSN")]
  8.         [Mask("999-99-9999")]
  9.         public string SSN { get; set; }
  10.         [Tooltip("Enter Age")]
  11.         [Mask("99")]
  12.         public string Age { get; set; }
  13.         [Mask("(999)-999-9999")]
  14.         [Tooltip("Enter Phone")]
  15.         public string Phone { get; set; }
  16.         [Mask("99999?-9999")]
  17.         [Tooltip("Enter Zip Code")]
  18.         public string ZipCode { get; set; }
  19.         [Mask("9999-9999-9999-9999")]
  20.         [Tooltip("Enter Credit Card")]
  21.         public string CreaditCard { get; set; }
  22.         [AutoComplete("Person", "GetStates", "state")]
  23.         public string State { get; set; }
  24.         [AutoComplete("Person", "GetStates", "state")]
  25.         public string USState { get; set; }
  26.         public ListSource Country { get; set; }
  27.     }
Step 3: Created an EditorTemplate for this type and added knockoutJS functions for move items left/right/up/down.
MvcLists\Views\Shared\EditorTemplates\ListSource.cshtml
  1. @model MvcLists.Models.ListSource
  2. <style type="text/css">
  3.     .divItem
  4.     {
  5.         float: none;
  6.         border-bottom-width: .2em;
  7.         border-bottom-style: solid;
  8.         border-bottom-color: #000000;
  9.         padding: 5px;
  10.         cursor: pointer;
  11.     }
  12.     .rightBoxItem
  13.     {
  14.         padding-left: 10px;
  15.     }
  16.     .indexCell
  17.     {
  18.         /*border-right-width: .2em;
  19.             border-right-style: solid;
  20.             border-right-color: #900;*/
  21.         padding: 5px;
  22.         padding-right: 10px;
  23.     }
  24.     .selectedItem
  25.     {
  26.         background: gold;
  27.     }
  28.     .header
  29.     {
  30.         font-family: arial;
  31.         color: #003469;
  32.         background-color: #dcdcdc;
  33.         margin: 0 0 10px 0;
  34.         padding: 2px 5px 2px 5px;
  35.     }
  36. </style>
  37. <script src="../../../Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
  38. <script src="../../../Scripts/knockout-2.0.0.js" type="text/javascript"></script>
  39. <script>
  40.         
  41.         function ListViewModel() {
  42.             var listItem = function(text,id,itemIndex) {
  43.                 this.Text = text;
  44.                 this.Id = id;
  45.             };
  46.             var self = this;
  47.             var listA = @Html.Raw(Json.Encode(Model.Available.ToList()));
  48.             var listB = @Html.Raw(Json.Encode(Model.Selected.ToList()));
  49.             self.listAArray= ko.observableArray(ko.utils.arrayMap(listA,function(list) {
  50.                 return new listItem(list.Text, list.Value,index);
  51.             }));
  52.             var index = 0;
  53.             self.listBArray= ko.observableArray(ko.utils.arrayMap(listB,function(list) {
  54.                 index++;
  55.                 return new listItem(list.Text, list.Value,index);
  56.             }));
  57.             self.changeClass = function(item) {
  58.                 $(item).closest("divItem").toggleClass("selectedItem");
  59.             };
  60.             self.moveRight = function() {
  61.                 $(".leftBox .selectedItem").each(function() {
  62.                     var item=ko.dataFor(this);
  63.                     self.listBArray.push(item);
  64.                     self.listAArray.remove(item);
  65.                 });
  66.             };
  67.             self.moveLeft = function() {
  68.                 $(".rightBox .selectedItem").each(function() {
  69.                     var item = ko.dataFor(this);
  70.                     self.listAArray.push(item);
  71.                     self.listBArray.remove(item);
  72.                     
  73.                 });
  74.             };
  75.             self.moveUp = function() {
  76.                 $(".rightBox .selectedItem").each(function() {
  77.                     var item = ko.dataFor(this);
  78.                     var index = self.listBArray.indexOf(item);
  79.                     if(index>0) {
  80.                         self.listBArray.remove(item);
  81.                         self.listBArray.splice(index - 1, 0, item);
  82.                         $(".rightBox .divItem:eq(" + (index -1) + ")").toggleClass("selectedItem");
  83.                     } else {
  84.                         return false;  
  85.                     }
  86.  
  87.                 });
  88.             };
  89.             self.moveDown = function() {
  90.                 $(".rightBox .selectedItem").each(function() {
  91.                     var item = ko.dataFor(this);
  92.                     var index = self.listBArray.indexOf(item);
  93.                     if(index<self.listBArray.length-1) {
  94.                         self.listBArray.remove(item);
  95.                         self.listBArray.splice(index + 1, 0, item);
  96.                         $(".rightBox .divItem:eq(" + (index +1) + ")").toggleClass("selectedItem");
  97.                     } else {
  98.                         return false;  
  99.                     }
  100.  
  101.                 });
  102.             };
  103.             
  104.             self.afterRender = function() {
  105.                 var i = 0;
  106.                 $(".rightBox .divItem").each(function() {
  107.                     i++;
  108.                     $(this).find(".indexCell")[0].text(i);
  109.                 });
  110.             };
  111.             ko.bindingHandlers.Index = {
  112.                 update:function (element,valueAccessor) {
  113.                     var i = 0;
  114.                     $(".rightBox .indexCell").each(function() {
  115.                         i++;
  116.                         $(this).text(i);
  117.                     });
  118.                     $(".divItem").unbind("click").bind("click", function() {
  119.                         $(this).toggleClass("selectedItem");
  120.                     });
  121.                 }
  122.             };
  123.         }
  124.  
  125.         $(document).ready(function () {
  126.             ko.applyBindings(new ListViewModel());
  127.         });
  128. </script>
  129. @Html.LabelForModel()
  130. <div style="margin-left: 5px; width: 100%;">
  131.     <div style="margin: auto; width: 90%;">
  132.         <div>
  133.             <div style="float: left">
  134.                 <div>
  135.                     <span>Available</span>
  136.                 </div>
  137.                 <div data-bind="foreach:listAArray" style="color: black; background-color: #dcdcdc;
  138.                     display: inline-block; border-style: solid; border-width: 2px; border-bottom-width: 0px;
  139.                     border-color: #000000" class="leftBox">
  140.                     <div class="divItem">
  141.                         <span data-bind="text:Text"></span>
  142.                     </div>
  143.                 </div>
  144.             </div>
  145.             <div style="float: left; vertical-align: middle; padding: 5px; display: inline-block;
  146.                 margin-top: 50px; width: 75px;">
  147.                 <div>
  148.                     <div>
  149.                         <input type="button" data-bind="click:moveRight" value=">" /></div>
  150.                     <div>
  151.                         <input type="button" data-bind="click:moveLeft" value="<" /></div>
  152.                 </div>
  153.             </div>
  154.             <div style="float: left">
  155.                 <div>
  156.                     <span>Selected</span>
  157.                 </div>
  158.                 <div class="rightBox" data-bind="foreach:listBArray,Index:listBArray" style="
  159.                     background-color: #FFFFAA; display: inline-block; border-style: solid; border-width: 2px;
  160.                     border-color: #000000; border-bottom-width: 0px">
  161.                     <span class="indexCell" style="float: left;"></span>
  162.                     <div class="divItem rightBoxItem">
  163.                         <span data-bind="text:Text"></span>
  164.                     </div>
  165.                 </div>
  166.             </div>
  167.             <div style="float: left; vertical-align: middle; padding: 5px; display: inline-block;
  168.                 margin-top: 50px; width: 75px;">
  169.                 <div style="background-color: bisque;">
  170.                     <div>
  171.                         <input type="button" data-bind="click:moveUp" value="Move Up" /></div>
  172.                     <div>
  173.                         <input type="button" data-bind="click:moveDown" value="Move Down" /></div>
  174.                 </div>
  175.             </div>
  176.             <div style="clear: both">
  177.             </div>
  178.         </div>
  179.     </div>
  180. </div>
Step 4: In controller/viewModel set DataSource for list box.
MvcLists\Controllers\PersonController.cs
  1. public ListSource Countries
  2.         {
  3.             get
  4.             {
  5.                 return new ListSource
  6.                            {
  7.                                Available = new List<Item>
  8.                                                {
  9.                                                    new Item {Text = "US", Value = 1},
  10.                                                    new Item {Text = "UK", Value = 2},
  11.                                                    new Item {Text = "Canada", Value = 3},
  12.                                                    new Item {Text = "France", Value = 4}
  13.                                                },
  14.                                Selected = new List<Item> {new Item {Text = "India", Value = 5}}
  15.                            };
  16.             }
  17.         }
Step 5: Render this listbox(Country)
MvcLists\Views\Person\Index.cshtml
  1. @using MvcLists.Common.HtmlHelpers
  2. @model MvcLists.Models.Person
  3. @{
  4.     ViewBag.Title = "Index";
  5.     Layout = "~/Views/Shared/_Layout.cshtml";
  6. }
  7. <h2>
  8.     Index</h2>
  9. <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
  10. <script src="../../Scripts/jquery.maskedinput.js" type="text/javascript"></script>
  11. @using (Html.BeginForm("Index","Person"))
  12. {
  13.     <fieldset>
  14.         <legend>Person</legend>
  15.         <div class="editor-label">
  16.             @Html.LabelFor(model => model.FirstName)
  17.         </div>
  18.         <div class="editor-field">
  19.             @Html.TextBoxFor(model => model.FirstName,new{title=@Html.TooltipFor(x=>x.FirstName)})
  20.         </div>
  21.         <div class="editor-label">
  22.             @Html.LabelFor(model => model.LastName)
  23.         </div>
  24.         <div class="editor-field">
  25.             @Html.TextBoxFor(model => model.LastName,new{title=Html.TooltipFor(x=>x.LastName)})
  26.         </div>
  27.         @Html.EditorFor(x => x.SSN)
  28.         @Html.EditorFor(x => x.Age)
  29.         @Html.EditorFor(x => x.Phone)
  30.         @Html.EditorFor(x => x.CreaditCard)
  31.         @Html.EditorFor(x => x.ZipCode)
  32.         @Html.EditorFor(x=>x.State)
  33.         @Html.EditorFor(x=>x.USState)
  34.         @Html.EditorFor(x=>x.Country)
  35.  
  36.         <p>
  37.             <input type="submit" value="Create" />
  38.         </p>
  39.     </fieldset>
  40. }
  41. <div>
  42.     @Html.ActionLink("Back to List", "Index")
  43. </div>