Blogger Widgets
  • Sharing Photos using SignalR
  • TFS Extenstion - allows copy work items between projects
  • Displaying jquery progressbar with ajax call on a modal dialog
  • Managing windows services of a server via a website
  • Exploring technologies available to date. TechCipher is one place that any professional would like to visit, either to get an overview or to have better understanding.

Search This Blog

Tuesday, 4 December 2012

Find if user is member of Active Directory Group C#

Finding out if user is a member of Active Directory Group can be done using following snippet of code

Method 1: using PrincipalContext
public static bool IsGroupMember(string domain, string group, string login)
        {
            bool result = false;
            PrincipalContext context = new PrincipalContext(ContextType.Domain, domain);
            UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(context, login);
            GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(context, group);
            if (userPrincipal != null)
            {
                if (userPrincipal.IsMemberOf(groupPrincipal))
                {
                    result = true;
                }
            }
            return result;
        }
Note: This is easy to use but only works based on specific domain

Method 2:using DirectoryEntry
 public static bool IsGroupMember(Logger logger, string group, string userName)
        {
            string strSid;
            bool result = false;
            clsLookupAccountName.GetAccountSid(userName, out strSid);
            DirectoryEntry rootDSE = new DirectoryEntry("GC://RootDSE");
            string rootDomainNamingContext = rootDSE.Properties["rootDomainNamingContext"].Value.ToString();
            string filter = "(&(objectCategory=user)(objectSid=" + strSid + "))";
            DirectorySearcher searcher = new DirectorySearcher("GC://" + rootDomainNamingContext);
            searcher.Filter = filter;
            searcher.PropertiesToLoad.Clear();
            searcher.PropertiesToLoad.Add("distinguishedName");
            SearchResult sr = searcher.FindOne();
            string userDN = sr.Properties["distinguishedName"][0].ToString();
            DirectoryEntry groupEntry = new DirectoryEntry(group);
            PropertyValueCollection pvc = groupEntry.Properties["member"];

            result = pvc.Contains(userDN);
            return result;
        }   
Note: This requires you to understand AD objects and its properties. Allows you to search universally

It has become appallingly obvious that our technology has exceeded our humanity. Albert Einstein

Wednesday, 28 November 2012

Combining ASP.NET MVC + SignalR + KnockoutJs with WCF Dual HTTP service

Managing windows services for a server via a website seems like a good option instead of having to remote desktop or remote accessing services.

A simple ASP.NET website should suffice this requirement, Is that correct ?
No, here is a simple scenario to prove that.

User wants to start a windows service using the website, now there are many things that can go wrong :
  • Service taking longer time to process the request
  • Service was unable to start due to some failure
  • Users display shows invalid service state

To fix this issue polling every 10(sec) can be done to find the correct state of the service. But what if this clients polling be replaced with service polling only when the state of the service is changed.

Now lets dig deep into and find out how this can be done. First lets look at the architecture of "OnlineServiceManagement"


OnlineServiceManagement has got 2 parts
  • WCF Window service with Dual HTTP binding enabled
  • ASP.NET MVC website with SignalR and KnockoutJS

WCF Window service with Dual HTTP binding enabled

Note - This application uses nlog for logging
First define contracts at least one that has dual binding enabled
 [ServiceContract]
    public interface IWinServiceNotificationHandler
    {
        [OperationContract(IsOneWay = true)]
        void ServiceStatusChanged(String ServiceName);
    }

     [ServiceContract(
        Name = "WinServiceProviderService",
        SessionMode = SessionMode.Required,
        CallbackContract = typeof(IWinServiceNotificationHandler))]
    public interface IWinServiceProvider
    {
        [OperationContract]
        string Ping();

        [OperationContract]
        ServiceControllerStatus GetServiceStatus(String Identification, String ServiceName);

        [OperationContract]
        ServiceControllerStatus StartService(String Identification, String ServiceName);

        [OperationContract]
        ServiceControllerStatus StopService(String Identification, String ServiceName);

        [OperationContract]
        ServiceControllerStatus RestartService(String Identification, String ServiceName);
    }

Now implement contract behaviour
 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Single, InstanceContextMode = InstanceContextMode.PerCall)]
    public class WinServiceProvider : IWinServiceProvider
    {
        private static List _callbackList = new List();
        private static Dictionary _services = new Dictionary();
        public static readonly object _locker_ = new object();

        public string Ping()
        {
            return "I can ping";
        }

        private void RegisterClient(String Identification)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "Identifiction as '" + Identification + "'");
            // Subscribe the guest to the beer inventory
            IWinServiceNotificationHandler client = OperationContext.Current.GetCallbackChannel();
            if (!_callbackList.Contains(client))
            {
                _callbackList.Add(client);
            }
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
        }

        private void RegisterServiceNames(String ServiceName, ServiceControllerStatus Status)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "for Service '" + ServiceName + "'");

            if (!_services.ContainsKey(ServiceName))
            {
                _services.Add(ServiceName, Status);
            }
            else
            {
                _services[ServiceName] = Status;
            }

            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
        }

        public static void ResetStatuses()
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            try
            {
                lock (_locker_)
                {
                    string[] serviceNames = _services.Keys.ToArray();
                    foreach (string serviceName in serviceNames)
                    {
                        ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == serviceName).FirstOrDefault();
                        _services[serviceName] = sc.Status;
                    }
                }
            }
            catch (Exception ex)
            {
                ServiceLogger.Logger.Error(ex);
            }
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
        }

        public static void NotifyClients(String ServiceName)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            ServiceLogger.Logger.Info("Found {0} callback clients", _callbackList.Count);
            try
            {
                _callbackList.ForEach(
                    delegate(IWinServiceNotificationHandler callback)
                    { callback.ServiceStatusChanged(ServiceName); });

                ResetStatuses();
            }
            catch (Exception ex)
            {
                ServiceLogger.Logger.ErrorException("Exception", ex);
            }
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
        }

        public static string HasServiceStatusChanged()
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            string retStatusChanged = string.Empty;
            try
            {
                lock (_locker_)
                {
                    string[] serviceNames = _services.Keys.ToArray();
                    foreach (string serviceName in serviceNames)
                    {
                        ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == serviceName).FirstOrDefault();
                        if (sc != null)
                        {
                            if (_services[serviceName] != sc.Status)
                            {
                                ServiceLogger.Logger.Info("Status changed for '{0}'", serviceName);
                                retStatusChanged = serviceName;
                                break;
                            }
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                ServiceLogger.Logger.Error(ex);
            }
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retStatusChanged;
        }

        public ServiceControllerStatus GetServiceStatus(String Identification, String ServiceName)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "Identifiction as '" + Identification + "'");
            RegisterClient(Identification);
            ServiceControllerStatus retStatus = ServiceControllerStatus.StopPending;
            ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == ServiceName).FirstOrDefault();
            if (sc != null)
            {
                retStatus = sc.Status;
            }
            RegisterServiceNames(ServiceName, sc.Status);
            //NotifyClients(ServiceName);
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retStatus;
        }

        public ServiceControllerStatus StartService(String Identification, String ServiceName)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "Identifiction as '" + Identification + "'");
            RegisterClient(Identification);
            ServiceControllerStatus retStatus = ServiceControllerStatus.StopPending;
            ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == ServiceName).FirstOrDefault();
            if (sc != null)
            {
                sc.Start();
                retStatus = sc.Status;
                //while (retStatus != ServiceControllerStatus.Running)
                //{
                //    System.Threading.Thread.Sleep(1000);
                //}
            }
            RegisterServiceNames(ServiceName, sc.Status);
            //NotifyClients(ServiceName);
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retStatus;
        }

        public ServiceControllerStatus StopService(String Identification, String ServiceName)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "Identifiction as '" + Identification + "'");
            RegisterClient(Identification);
            ServiceControllerStatus retStatus = ServiceControllerStatus.StopPending;
            ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == ServiceName).FirstOrDefault();
            if (sc != null)
            {
                sc.Stop();
                retStatus = sc.Status;
                //while (retStatus != ServiceControllerStatus.Stopped)
                //{
                //    System.Threading.Thread.Sleep(1000);
                //}
            }
            RegisterServiceNames(ServiceName, sc.Status);
            //NotifyClients(ServiceName);
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retStatus;
        }

        public ServiceControllerStatus RestartService(String Identification, String ServiceName)
        {
            ServiceLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name + "Identifiction as '" + Identification + "'");
            RegisterClient(Identification);
            ServiceControllerStatus retStatus = ServiceControllerStatus.StopPending;
            ServiceController sc = ServiceController.GetServices().Where(s => s.ServiceName == ServiceName).FirstOrDefault();
            if (sc != null)
            {
                retStatus = StopService(Identification, ServiceName);
                retStatus = StartService(Identification, ServiceName);
            }
            RegisterServiceNames(ServiceName, sc.Status);
            //NotifyClients(ServiceName);
            ServiceLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retStatus;
        }
    }
Now define endpoint configuration in app.config for windows service
endpoint address="" binding="wsDualHttpBinding"                  contract="WinServiceManger.Contract.IWinServiceProvider" 

That's it main components of windows service are completed. Windows service exposes some operations for website consumption and also has "IWinServiceNotificationHandler" for implementing call back to clients.

ASP.NET MVC website with SignalR and KnockoutJS

Using the default MVC template for creating the project should be sufficient. Now lets look into the details of website. Include following dependencies :
Dlls
  • SignalR
  • NLog

Scripts
  • JQuery
  • JQuery Templates Plugin
  • KnockoutJS
  • Json

Service references
  • WinServiceManger


We are using KnockoutJS that follows MVVM pattern in which Model comes first. So lets define our Model first
public class WindowsServicesModel
    {
        public List Services { get; set; }
        public WindowsServicesModel(String Identification)
        {
            LoadServices(Identification);
        }

        private void LoadServices(String Identification)
        {
            try
            {
                Services = new List()
                {
                    new WinService
                    {
                        Name = "ASP.NET State Service",
                        ServiceName = "aspnet_state",
                        Description="Provides support for out-of-process session states for ASP.NET. If this service is stopped, out-of-process requests will not be processed. If this service is disabled, any services that explicitly depend on it will fail to start.",
                        CSSClass = "one",
                        Status= ""
                    },
                    new WinService
                    {
                        Name = "Background Intelligent Transfer Service",
                        ServiceName = "BITS",
                        Description="Transfers files in the background using idle network bandwidth. If the service is disabled, then any applications that depend on BITS, such as Windows Update or MSN Explorer, will be unable to automatically download programs and other information.",
                        CSSClass = "two",
                        Status= ""
                    },
                    new WinService
                    {
                        Name = "Bluetooth Support Service",
                        ServiceName = "bthserv",
                        Description="The Bluetooth service supports discovery and association of remote Bluetooth devices.  Stopping or disabling this service may cause already installed Bluetooth devices to fail to operate properly and prevent new devices from being discovered or associated.",
                        CSSClass = "three",
                        Status= ""
                    }
                };

                foreach (WinService winService in Services)
                {
                    WinServiceManger.ServiceControllerStatus status = Global.WinServiceMangerClient.GetServiceStatus(Identification, winService.ServiceName);
                    switch (status)
                    {
                        case WinServiceManger.ServiceControllerStatus.Running:
                            winService.Status = "Running";
                            break;
                        case WinServiceManger.ServiceControllerStatus.ContinuePending:
                            winService.Status = "Continue Pending";
                            break;
                        case WinServiceManger.ServiceControllerStatus.Paused:
                            winService.Status = "Paused";
                            break;
                        case WinServiceManger.ServiceControllerStatus.PausePending:
                            winService.Status = "Pause Pending";
                            break;
                        case WinServiceManger.ServiceControllerStatus.StartPending:
                            winService.Status = "Start Pending";
                            break;
                        case WinServiceManger.ServiceControllerStatus.Stopped:
                            winService.Status = "Stopped";
                            break;
                        default:
                            winService.Status = "Unknown";
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                WebLogger.Logger.ErrorException("WindowsServicesModel.LoadServices Exception : ", ex);
            }
        }
    }
We have our model ready now, so lets define our View to be a KnockoutJS template that display list of services available.
 
Now write javascript code for updating View that is defined earlier
var koHelper = {
    ViewModel: {},
    LoadViewModel: function (resultData) {
        //var strViewModel = document.getElementById(viewModelFieldId).value;
        //var clientViewModel = ko.utils.parseJson(resultData);
        var clientViewModel = resultData;
        this.ViewModel = clientViewModel;
        ko.applyBindings(this.ViewModel);
    },
    getWindowsServices: function () {
        $.ajax({
            url: "/Home/GetWindowsServices/",
            type: 'post',
            //data: "{'customerID':'1' }",
            contentType: 'application/json',
            success: function (result) {
                koHelper.LoadViewModel(result);
                var dt = new Date();
                koHelper.UpdateStatus("Autoupdate service status by Signal-R");
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var errorMessage = '';
                $('#message').html(jqXHR.responseText);
            }
        });
    },
    StartService: function (data, event) {        
        $.ajax({
            url: "/Home/StartService/",
            type: 'post',
            data: JSON.stringify( { 'ServiceName': data.ServiceName } ),
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                if (result != null) {
                    koHelper.LoadViewModel(result);
                    var dt = new Date();
                    koHelper.UpdateStatus("StartService");
                    //$.windowsServiceManager.performedServiceStatusChange(data.ServiceName);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var errorMessage = '';
                $('#message').html(jqXHR.responseText);
            }
        });
    },
    StopService: function (data, event) {
        $.ajax({
            url: "/Home/StopService/",
            type: 'post',
            data: JSON.stringify({ 'ServiceName': data.ServiceName }),
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                if (result != null) {
                    koHelper.LoadViewModel(result);
                    var dt = new Date();
                    koHelper.UpdateStatus("StopService");
                    //$.windowsServiceManager.performedServiceStatusChange(data.ServiceName);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var errorMessage = '';
                $('#message').html(jqXHR.responseText);
            }
        });
    },
    RestartService: function (data, event) {
        $.ajax({
            url: "/Home/RestartService/",
            type: 'post',
            data: JSON.stringify({ 'ServiceName': data.ServiceName }),
            contentType: 'application/json',
            dataType: 'json',
            success: function (result) {
                if (result != null) {
                    koHelper.LoadViewModel(result);
                    var dt = new Date();
                    koHelper.UpdateStatus("RestartService");
                    //$.windowsServiceManager.performedServiceStatusChange(data.ServiceName);
                }
            },
            error: function (jqXHR, textStatus, errorThrown) {
                var errorMessage = '';
                $('#message').html(jqXHR.responseText);
            }
        });
    },
    UpdateStatus: function (statusData) {
        var content = "
" + new Date() + "
" + statusData + "
"; content += $('#statusInfo').html() ; $('#statusInfo').html(content); } }
We have used following controller actions:-
  • /Home/GetWindowsServices/
  • /Home/StartService/
  • /Home/StopService/
  • /Home/RestartService/
Now lets look at implementing these actions
 public JsonResult GetWindowsServices()
        {
            JsonResult retValue = null;
            WebLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            try
            {
                if (Session["Identification"] != null)
                {
                    WindowsServicesModel wsm = new WindowsServicesModel(Session["Identification"].ToString());
                    retValue = new JsonResult()
                    {
                        Data = wsm
                    };
                }
            }
            catch (Exception ex)
            {
                WebLogger.Logger.ErrorException("Error ", ex);
            }
            WebLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retValue;
        }

[AcceptVerbs(HttpVerbs.Post)]
        public JsonResult StartService(string ServiceName)
        {
            JsonResult retValue = null;
            WebLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            try
            {
                if (Session["Identification"] != null)
                {
                    WinServiceManger.ServiceControllerStatus status = Global.WinServiceMangerClient.StartService(Session["Identification"].ToString(), ServiceName);
                    //if (status == WinServiceManger.ServiceControllerStatus.Running)
                    //{
                    WindowsServicesModel wsm = new WindowsServicesModel(Session["Identification"].ToString());
                    retValue = new JsonResult()
                    {
                        Data = wsm
                    };
                    //}
                }
            }
            catch (Exception ex)
            {
                WebLogger.Logger.ErrorException("Error ", ex);
            }
            WebLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retValue;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public JsonResult StopService(string ServiceName)
        {
            JsonResult retValue = null;
            WebLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            try
            {
                WinServiceManger.ServiceControllerStatus status = Global.WinServiceMangerClient.StopService(Session["Identification"].ToString(), ServiceName);
                WindowsServicesModel wsm = new WindowsServicesModel(Session["Identification"].ToString());
                retValue = new JsonResult()
                {
                    Data = wsm
                };
            }
            catch (Exception ex)
            {
                WebLogger.Logger.ErrorException("Error ", ex);
            }
            WebLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retValue;
        }

        [AcceptVerbs(HttpVerbs.Post)]
        public JsonResult RestartService(string ServiceName)
        {
            JsonResult retValue = null;
            WebLogger.Logger.Info("Started " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            try
            {
                WinServiceManger.ServiceControllerStatus status = Global.WinServiceMangerClient.RestartService(Session["Identification"].ToString(), ServiceName);
                //if (status == WinServiceManger.ServiceControllerStatus.Running)
                //{
                WindowsServicesModel wsm = new WindowsServicesModel(Session["Identification"].ToString());
                retValue = new JsonResult()
                {
                    Data = wsm
                };
                //}
            }
            catch (Exception ex)
            {
                WebLogger.Logger.ErrorException("Error ", ex);
            }
            WebLogger.Logger.Info("Completed " + System.Reflection.MethodInfo.GetCurrentMethod().Name);
            return retValue;
        }
Thats it! we are done with main components required for implementing our requirement. Complete solution is available on GitHub at OnlineServiceManagement OnlineServiceManagement

“We have to stop optimizing for programmers and start optimizing for users.” – Jeff Atwood

Tuesday, 20 November 2012

Unable to share user controls as a link between projects in ASP.NET

Sharing user control as a link between project is not advisable as per microsoft article How to: Add Existing Items to a Project. Look at note under "Adding an Existing Item as a Link" as it says

"Visual Basic Web projects, Visual C# Web projects, and other similar projects do not support links to items."

But if you still want to go with this method, then here it is how you can achieve it. Consider you have following projects in your solution
- Web application 1 => csharpbloggerapp.csproj
- Web application 2 => csharpblogtracker.csproj
- a deployment project for web app csharpbloggerapp.deploy.csproj (for csharpbloggerapp.csproj)

Now consider you have a script csharpcomm.js inside csharpblogtracker.csproj under script folder and would like to include this into csharpbloggerapp.csproj not as another file but as a link, so making changes/fixes/enhancements will be easy.

1. First go to "scripts" folder inside csharpbloggerapp.csproj, then right click on "Scripts" folder select "Add Existing Item" , browse to csharpblogtracker->scripts and select the file csharpcomm.js
2. Now from the Open button drop-down list, select Add As Link

After adding the link, compile your deploy project and you shall notice "csharpcomm.js" has not been copied.

3. Now add a "Post Build Event" for csharpbloggerapp.csproj as follows

xcopy /y $(ProjectDir)$(OutDir)..\..\csharpblogtracker\Scripts\csharpcomm.js $(ProjectDir)$(OutDir)..\Scripts
That's it... now compile your deployment project and you should find csharpcomm.js copied. Same procedure can be used for pages, user controls, resource files etc..

But correct method is to create a common assembly and add reference to this common library.

“We have to stop optimizing for programmers and start optimizing for users.” – Jeff Atwood

Wednesday, 3 October 2012

DevExpress Unable to get value of the property 'usercontrol_dxcontrol_event' : object is null or undefined

I am getting "Microsoft JScript runtime error" when running web application that uses DevExpress controls. I have got a user control hierarchy as follows:-
Default.aspx
 |
  -> Site.Master
          |
           -> LoadInvoiceTab
                  |
                   -> LoadInvoiceTabHeader
LoadInvoiceTabHeader has got some javascript code to handle client side events for DevExpress controls. script has been added toward end of the user control definition.
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="LoadInvoiceTabHeader.ascx.cs" Inherits="LoadInvoiceTabHeader" %>
 
Invoice No :
Customer name :
Delivery Address :
After running the website I was getting following error message:-
Microsoft JScript runtime error: Unable to get value of the property 'LoadInvoiceTabHeader_btnSave_Click': object is null or undefined
The reason for the script error is because devexpress controls try to evaluate SaveInvoice & CancelInvoice while rendering the page, but by this time the script written for clientside events were not assigned and hence generates an error. In order to render the script in advance all you need to do is just assign id for script tab with prefix with "dxss_". So script will now become
 
That's it this should solve the issue.

One machine can do the work of fifty ordinary men. No machine can do the work of one extraordinary man. ~Elbert Hubbard, The Roycroft Dictionary and Book of Epigrams, 1923

Tuesday, 25 September 2012

Measuring performance using Fiddler API

Having used Fiddler as one of the most useful tool as a developer, would it not be easy to actually use Fiddler to measure up website performance, throughput etc. Well!! FiddlerCore API can be used to achieve this. Refer to FiddlerCode API for some samples.

Pretty cool. I have been using DevExpress ASP.NET controls for quite sometime now and I wanted to measure the performance and throughput for some of very interesting controls such as aspxcallbackpanel & aspxcallback.

All I want is a small windows app with a single form having a grid that show all of the interactions to and from the website I wanted to test. So here is how it looks when comparing performance against 30 secs max.

Steps 1. Initialize and associate all relevant events and flags for Fiddler API.
public Form1()
        {
            InitializeComponent();

            oAllSessions = new List();
            Fiddler.FiddlerApplication.OnNotification += delegate(object sender, NotificationEventArgs oNEA) { Console.WriteLine("** NotifyUser: " + oNEA.NotifyString); };
            Fiddler.FiddlerApplication.Log.OnLogString += delegate(object sender, LogEventArgs oLEA) { Console.WriteLine("** LogString: " + oLEA.LogString); };
            Fiddler.FiddlerApplication.BeforeRequest += delegate(Fiddler.Session oS)
            {
                oS.bBufferResponse = false;
                Monitor.Enter(oAllSessions);
                if (oS.fullUrl.StartsWith(sSecureEndpointHostname))
                {
                    oAllSessions.Add(oS);
                }
                Monitor.Exit(oAllSessions);
            };
            Fiddler.FiddlerApplication.AfterSessionComplete += delegate(Fiddler.Session oS)
            {
                if (bUpdateTitle)
                {
                    this.Text = ("Session list contains: " + oAllSessions.Count.ToString() + " sessions");
                }
            };
            Fiddler.CONFIG.IgnoreServerCertErrors = false;
            oFCSF = FiddlerCoreStartupFlags.Default;
        }
2. Now write code to handle start/stop monitoring of fiddler sessions
 private void btnStartStop_Click(object sender, EventArgs e)
        {
            test = new Random(120);
            if (btnStartStop.Text == "Start")
            {                
                Uri uri = new Uri(txtWebSite.Text);
                iSecureEndpointPort = uri.Port;                
                btnStartStop.Text = "Stop";
                tmrAnalyse.Enabled = true;
                tmrAnalyse.Interval = 5000;
                sSecureEndpointHostname = uri.AbsoluteUri;

                lstAnalysisData.Items.Clear();
                dgSessions.Rows.Clear();


                Fiddler.FiddlerApplication.Startup(8877, oFCSF);                
            }
            else
            {                
                Fiddler.FiddlerApplication.Shutdown();
                btnStartStop.Text = "Start";
                tmrAnalyse.Enabled = false;
            }
        }
3. code snippets for add/update session data onto grid
private void AddSession(Session oS, Dictionary whoData, int timeTaken)
        {
            DataGridViewRow row = new DataGridViewRow();
            dgSessions.Rows.Add(row);

            DataGridViewCell cell1 = new DataGridViewTextBoxCell();
            cell1.Value = oS.id;
            row.Cells["SessionID"] = cell1;

            DataGridViewCell cell2 = new DataGridViewTextBoxCell();
            cell2.Value = Ellipsize(oS.fullUrl, 60);
            row.Cells["URL"] = cell2;

            DataGridViewCell cell3 = new DataGridViewTextBoxCell();
            cell3.Value = oS.oRequest.headers.HTTPMethod;
            row.Cells["HttpMethod"] = cell3;

            DataGridViewCell cell4 = new DataGridViewTextBoxCell();
            cell4.Value = oS.responseCode;
            row.Cells["RresponseCode"] = cell4;

            DataGridViewCell cell5 = new DataGridViewTextBoxCell();
            cell5.Value = oS.oResponse.MIMEType;
            row.Cells["MIMEType"] = cell5;

            DataGridViewCell cell6 = new DataGridViewTextBoxCell();
            DataGridViewCell cell7 = new DataGridViewTextBoxCell();
            

            if (whoData.ContainsKey(NotFound))
            {
                cell6.Value = "Not found";
                cell7.Value = "Not found";                
            }
            else
            {
                cell6.Value = whoData[DataColumn1];
                cell7.Value = whoData[DataColumn2];
            }

            row.Cells["Data1"] = cell6;
            row.Cells["Data2"] = cell7;

            DataGridViewCell cell8 = new DataGridViewTextBoxCell();
            cell8.Value = timeTaken;
            row.Cells["Data3"] = cell8;

        }

        private int FindRow(Session oS)
        {
            int rowId = -1;
            for (int i = 0; i < dgSessions.Rows.Count; i++)
            {
                DataGridViewRow row = dgSessions.Rows[i];
                if (row.Cells[0].Value != null)
                {
                    if (row.Cells[0].Value.ToString() == oS.id.ToString())
                    {
                        rowId = i;
                        break;
                    }
                }
                else
                {
                    rowId = i;
                    break;
                }
            }
            return rowId;
        }

        private void UpdateSession(int rowId, Session oS, Dictionary whoData, int timeTaken)
        {
            DataGridViewRow row = dgSessions.Rows[rowId];
            row.Cells["SessionID"].Value = oS.id;
            row.Cells["URL"].Value = Ellipsize(oS.fullUrl, 60);
            row.Cells["HttpMethod"].Value = oS.oRequest.headers.HTTPMethod;
            row.Cells["RresponseCode"].Value = oS.responseCode;
            row.Cells["MIMEType"].Value = oS.oResponse.MIMEType;
            row.Cells["Data1"].Value = whoData[DataColumn1];
            row.Cells["Data2"].Value = whoData[DataColumn2];
            row.Cells["Data3"].Value = timeTaken;
        }
4. code snippet for updating grid every 5 secs
private void WriteSessionList()
        {
            try
            {
                Monitor.Enter(oAllSessions);
                foreach (Session oS in oAllSessions)
                {
                    WriteSession(oS);
                }
            }
            catch (Exception ex)
            {
                lstAnalysisData.Items.Add("Exception " + ex.Message);
            }
            finally
            {
                Monitor.Exit(oAllSessions);
            }
        }

        private void tmrAnalyse_Tick(object sender, EventArgs e)
        {           
            WriteSessionList();
        }
That's it all in place now. Some of the tiny bits were missed out in the intention highlight more important bits. Download FidderAPI.rar for more details. This is common code and can be used for any website or web applications. Mostly useful to verify throughput/speed for websites that utilises any of the following controls or JavaScript plugins :-
- asp:UpdatePanel (ASP.NET ajax control)
- $.ajax (JQuery ajax call to webservice/webpage)
- ActionResult (ASP.NET MVC action) etc.

Some people worry that artificial intelligence will make us feel inferior, but then, anybody in his right mind should have an inferiority complex every time he looks at a flower. ~Alan C. Kay

Wednesday, 19 September 2012

DevExpress Input string was not in a correct format

I have started using ASP.NET DevExpress controls quite some time now. In last couple of days I have seen a strange error on pages with the following error message :

"Input string was not in a correct format"

Here is what my page consisted of a list of controls
- ASPxTextBox
- ASPxComboBox
- ASPxButton
- ASPxCallback

I want to pass the input data of ASPxTextBox & ASPxComboBox on button click to server via ASPxCallback and store this information in a database. Not so complicated as it sounds.

I have got some Nlog tracing enabled, got try-catch for ASPxCallback and all wired up. Started testing the page and I got this error ""Input string was not in a correct format"

Started debugging. No server side exceptions and nothing wrong, do not know where the error is coming from after googling and search in DevExpress support tickets I have found how to enable callback errors.

So I have enabled tracing callback errors as mentioned by DevExpress in the article Handling Callback Exceptions on Client.

Now I have got the tracing as:-

at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
at System.Int32.Parse(String s)
at DevExpress.Web.ASPxEditors.ListEditItemsSerializingHelper.ParseItemIndex(String serializedItem, Int32& startPos)
at DevExpress.Web.ASPxEditors.ListBoxItemsSerializingHelper.DeserializeItems(String serializedItems, Boolean sortRequired)
at DevExpress.Web.ASPxEditors.ListBoxProperties.SynchronizeItems(String serializedItems, Boolean isInsertingSyncType)
at DevExpress.Web.ASPxEditors.ASPxComboBox.SynchronizeItems(NameValueCollection postCollection)
at DevExpress.Web.ASPxEditors.ASPxComboBox.LoadPostData(NameValueCollection postCollection)
at DevExpress.Web.ASPxClasses.ASPxWebControl.LoadPostDataInternal(NameValueCollection postCollection, Boolean raisePostDataEvent)

But still do not know where the issue is. So started again looking into code step-by-step and I have found something. The items I am adding to ASPxComboBox is the issue.

aspx

 
        
javascript

var dataItems:
        [
          ["Item1","Available"],
["Item2","Available"],
["Item3","Available"],
["Item4","Available"],
["Item5","NotAvailable"],
["Item6","Available"]];
var itemid = 0;
for (var i = 0; i < dataItems.length; i++) {
 var dataItem = dataItems[i];
 if(dataItem[1] == "Available"){
   ClientCmbData.AddItem(dataItem, itemid++);
}
}


The issue occurs at ClientCmbData.AddItem(dataItem, itemid++), instead of ClientCmbData.AddItem(dataItem[0], itemid++);

So data passed in for ASPxComboBox items text value is invalid and hence parsing fails. That's it problem solved.



“The computer was born to solve problems that did not exist before.” – Bill Gates

Wednesday, 12 September 2012

State management in ASP.NET for high availability of data

ASP.NET session is the correct answer for state management. Yes that's it developers have to just use session to maintain state ie.. any data relavant to a user's session. Ways to store session state can mainly be categorized into InProc and OutProc.

InProc


Session state stored as in-memory on the web server.

Websites running in "Inproc" mode is completely dependent on the resources of the server. Limitation for number of users is dependent on the following factors
- Memory of server
- Amount of data stored per user session

As the memory used starts to exceed available memory application pool gets recycled and hence data stored is lost.

Single Web Server

Easy to configure and setup.
To enable session state as "Inproc" update web.config as follows:-


Advantages
- Easy access to data as stored in-memory

Disadvantages
- Data loss due exceeded memory utilization

Web Farm

Another method of increasing user capacity is by enabling sticky sessions on a web farm. This can achieved by using a Network Load Balancing (NLB). NLB has a feature known as "The Request Forwarder" and can be used to configure a cluster (web farm).

Sticky sessions use a HTTP cookie, which is returned for each client request that contains server instance GUID (ie.. first server that handled the request) and session ID allocated for the user. Subsequent requests will pass back server instance GUID and session ID that load balancer identifies and forwards to respective server. For mode detail explanation of this works look at technet article avalaible at http://technet.microsoft.com/en-us/library/bb734910.aspx.

Advantages
- Increased user capacity
- Easy access to data as stored in-memory

Dis-Advantages
- Partial load balance as user's are tied to specific server that served the request
- Still has possibility of data loss due exceeded memory utilization

OutProc


Session state is stored on a state server. Also this can be located on the same machine as web server or can point to another machine on your network. This mode is reliable as restarting web application does not affect state server and hence no data loss.

This mode can be configured either for a single server instance or for multiple servers on a web farm. In case of multiple web servers in a web farm,
- objects stored in session needs to be serializable
- should be installed on the same path in each of the web server in the Web farm.

1)StateServer

Session state is stored on an ASP.NET state service. Session data stored on a remote machine, no data loss due to application pool recycling. But still has the overhead of data loss if machine that has been configured as state management server is restarted.

Advantages
- No data loss due to application pool recycle

Dis-Advantages
- Is still limited based on the memory
- Reduces performance as data is read from a remote machine

2)SQLServer

session state is stored in an SQL Server database. Session data stored in a database because of which data is never lost. Machine restart will still not loose data as data is stored in a database.

Advantages
- No data loss due to application pool recycle - Data stored permanently in a database which has high reliability

Dis-Advantages
- Reduces performance as data read is from a database - Limited to memory allocated to database

3)Custom

Session state is stored on a custom provider. There are various options available for custom provider are AppFabric, Memcached etc.

AppFabric
- distributed in-memory application cache, refer to AppFabric for windows server for more details.
Memcached
- high-performance, distributed memory object caching system, refer to Memcached for more details.
SharedCache
- distributed and replicated memory object caching system, refer to SharedCache for more details.
“The most likely way for the world to be destroyed, most experts agree, is by accident. That’s where we come in; we’re computer professionals. We cause accidents.” – Nathaniel Borenstein

Monday, 16 July 2012

Various third party .NET Controls available on web

As of today there are many .NET controls developed for various technologies such as ASP.NET, Windows forms, HTML, Jquery, compression etc. Here are the list of controls available in detail.

Developed By Controls for Features Comments
DevExpress
  • WinForms
  • ASP.NET
  • ASP.NET MVC
  • WPF
  • SilverLight
  • Windows 8
  • IOS
  • Touch Enabled Apps
  • Reporting
  • Charting
  • Data Grid & Rich Text Editors
  • Ribbon, Menu, Docking
  • Pivot Grid,Scheduler, Tree List & Gauges
  • Property Grid
  • Layout Manager
  • Navigation Bar
  • Editors & Controls
  • Printing-Exporting
  • Spell Checker
  • Wizard Control
  • Application Skins
  • Themes & Skins
  • MVC Extensions
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Source code available if purchased Universal or Enterprise
  • Documentation provided along with examples
Telerik
  • WinForms
  • ASP.NET
  • ASP.NET MVC
  • WPF
  • SilverLight
  • Windows 8
  • Windows Phone
  • Ready for Touch
  • Reporting
  • Data Management
  • Editors
  • Scheduling
  • Spell Checking
  • Ajax
  • Layout
  • Navigation
  • Visualization
  • Upload
  • Theming
  • Social
  • Performance
  • Interactivity
  • Charting
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Documentation provided along with examples
Disadvantages
  • Source code not provided
Infragistics
  • WinForms
  • ASP.NET
  • ASP.NET MVC
  • WPF
  • SilverLight
  • Windows 8
  • Windows Phone
  • Sharepoint
  • JQuery
  • Editors
  • Frameworks
  • Office Support
  • Grids
  • Interactions
  • Layouts
  • Lists
  • Menus
  • Schedules
  • Charts
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Documentation provided along with examples
  • Source code available if purchased NetAdvantage Ultimate
Xceed
  • WinForms
  • ASP.NET
  • WPF
  • Silverlight
  • Compression
  • Networking
  • Encryption
  • Chart
  • Grid
  • Compression
  • Zipping
  • Encryption
  • FileTransfer
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Documentation provided along with examples
  • Source code available if purchased BluePrint subscription
VIBlend
  • WinForms
  • WPF
  • Silverlight
  • Data grid
  • Navigation bars
  • Ribbon Interface
  • Treeview, calendar, combo box etc
  • Menu
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Documentation provided along with examples
  • Source code available if purchased with VIBlend Premium
9Rays.NET
  • WinForms
  • WPF
  • Silverlight
  • Encryption
  • Obfuscator
  • Decompiler
  • Grid
  • Tree view
  • Obfuscator
  • Decompiler
Advantages
  • Demos available for almost each and every controls
  • Support available
  • Documentation provided along with examples
  • Source code available if purchased with Enterprise License

Monday, 9 July 2012

Alert dialogue with DevExpress controls

Although DevExpress provides various set of ASP.NET control, but still sometimes all controls that are available out of the box might not be suited to what you would like to achieve. One such simple requirement is display customized alert dialog box.

Let look into detail explanation of how this can be achieved. All you need is to add ASPxPopupControl as the last element of your master page

 
  
   
                                 
       
        

Write a common java script function that will display the alert dialogue.


Now all everything is setup just call the function as and when requried

Never trust anything that can think for itself if you can't see where it keeps its brain. ~J.K. Rowling

Display loading panel while page loads

Recently I started using DevExpress controls and am quite suppressed at how easy they are to be used. On one occasion the requirement was to show a loading text/gif until processing is completed on the server.
Here is how this can be achieved.

1. First place a "ASPxLoadingPanel" to show loading text
        
          

2. Add "ASPxCallbackPanel"

  
    
        
    
  
  


3. Add script block to show loading panel and send request for server side processing
 

4. Add server side processing code
protected void callbackPanel_Callback(object sender, CallbackEventArgsBase e)
{
}

That's it all done.

Do you realize if it weren't for Edison we'd be watching TV by candlelight? ~Al Boliska

Wednesday, 30 May 2012

DialogWidth and DialogHeight not working on chrome for showModalDialog

window.showModalDialog is ignoring dialogWidth and dialogHeight on Chrome but works fine on other browsers such as IE, firefox etc. After some tweaking I have found that dialogWidth and dialogHeight should not have "px" in the value ie.. "dialogWidth:100;dialogHeight:200" but other browsers need to have "px" such as "dialogWidth:100px;dialogHeight:200px"

Here is a simple function that can help

 function ModalDialog(sURL, vArguments, ModalDialogHeight, ModalDialogWidth) {
        var sFeatures;

        if (window.showModalDialog) {
            if (!navigator.userAgent.toLowerCase().match('chrome')) {
                ModalDialogWidth += "px";
                ModalDialogHeight += "px";
            }
            sFeatures = "status:no;center:yes;dialogWidth:" + ModalDialogWidth + ";dialogHeight:" + ModalDialogHeight + ";resizable:yes;";
            var returnResult = window.showModalDialog(sURL, vArguments, sFeatures);
            if (returnResult) {
                return returnResult;
            }
        }
        else {
            sFeatures = "status=no,width=" + ModalDialogWidth + ",height=" + ModalDialogHeight + ",menubar=no,scrollbars=no";
            window.margs = vArguments;
            window.open(sURL, "_blank", sFeatures);
        }
    }


After growing wildly for years, the field of computing appears to be reaching its infancy. ~John Pierce

Thursday, 24 May 2012

TFS Helper package extension for Visual Studio 2010

VS2010 is well integrated to TFS and has all the features required on day to day basis. Most common feature any developer use is managing workitems. Creating work items is very easy as is copying work items, but what I need is to copy workitem between projects retaining links and attachments. I am sure this is not Ideal and against sprint projects.

I have created a Visual Studio Package that can achieve this. Here is the step-by-step guide

1. Using VS2010 create a project of type "Visual Studio Package"

2. Select language as "C#" and select "Next"

3. Specify package information and select "Next"
4. Now select "Menu Command" and "Tool Window" and select "Next"
5. Specify command options, tool window options and select "Next"
6. De-select test project options and select "Finish". Now we have completed creating a new package project.
7. Add TFS references to the project
8. Make following code changes
VS2010.TFSHelperPackage.GuidList Class
..
public const string guidVSPackage1CmdSetString2 = "6E282364-7C4B-4E12-868D-AC8572708416";
..
public static readonly Guid guidVSPackage1CmdSet2 = new Guid(guidVSPackage1CmdSetString2);
..

VS2010.TFSHelperPackage.PkgCmdIDList Class
..
public const uint cmdidCopyWorkItemAdvanced = 0x100;
..
TFSHelperPackage Class -> Initialize()
protected override void Initialize()
        {
....
 // Create the command for the menu item.
CommandID menuCommandID2 = new CommandID(GuidList.guidVSPackage1CmdSet2, (int)PkgCmdIDList.cmdidCopyWorkItemAdvanced);
MenuCommand menuItem2 = new MenuCommand(CopyWorkItemAdvancedCallback, menuCommandID2);
mcs.AddCommand(menuItem2);
..
}
private void CopyWorkItemAdvancedCallback(object sender, EventArgs e)
{}


Update "TFSHelperPackage.vsct"

 
  
     ....
      
        
      

    
 
....



..



...

    

      
      
    
...

      
    
...


Now GuidSymbol name="guidTFSContextMenu" is very important as value "517" is the id for "Results List" menu item. Refer to Using EnableVSIPLogging to identify menus and commands with VS 2005 + SP1 to find out Menu command Id/GUIDs.
9. Add a new windows form as follows

10. Now update CopyWorkItemAdvancedCallback with following code
private void CopyWorkItemAdvancedCallback(object sender, EventArgs e)
        { using(CopyWorkItemAdvancedForm cw = new CopyWorkItemAdvancedForm(this))
           {
               if(cw.ShowDialog() == System.Windows.Forms.DialogResult.OK)
               {
                   cw.Close();
               }
           }
        }

11. Update CopyWorkItemAdvancedForm code behind as follows
public partial class CopyWorkItemAdvancedForm : Form
    {
        private IServiceProvider _serviceProvider;
        private IWorkItemTrackingDocument _currentDocument;
        private WorkItem _currentWorkItem;
        private WorkItem _newWorkItem;
        private WorkItemStore _workItemStore;

        public CopyWorkItemAdvancedForm(IServiceProvider serviceProvider)
        {
            InitializeComponent();
            _serviceProvider = serviceProvider;
            LoadControls();
        }

        private void LoadControls()
        {
            this.cmbProjects.Items.Clear();
            this.cmbWorkItemTypes.Items.Clear();

            //Load source workitem 
            _currentDocument = WitDocumentHelper.GetCurrentWitDocument(_serviceProvider);
            string selectedItemId = string.Empty;
            if (_currentDocument is IResultsDocument)
            {
                int cnt = ((IResultsDocument)_currentDocument).SelectedItemIds.Length;
                if (cnt > 0)
                {
                    IResultsDocument resultDocument = (IResultsDocument)_currentDocument;
                    selectedItemId = resultDocument.SelectedItemIds[0].ToString();
                    _currentWorkItem = resultDocument.ResultListDataProvider.GetItem(0);
                }
            }
            else if (_currentDocument is IWorkItemDocument)
            {
                // To be completed
            }
            else if (_currentDocument is IQueryDocument)
            {
                // To be completed
            }
            else
            {
                // To be completed
            }

            this.Text = "Create Copy of Work Item with options ... [ " + selectedItemId + "]";

            //Load dropdowns
            var dte = Package.GetGlobalService(typeof(EnvDTE.DTE)) as EnvDTE.DTE;
            TeamFoundationServerExt ext = dte.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt") as TeamFoundationServerExt;
            TfsTeamProjectCollection teamProjectCollection = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(ext.ActiveProjectContext.DomainUri));

            // Refer to http://msdn.microsoft.com/en-us/library/bb286958.aspx for list of types available with GetService
            _workItemStore = teamProjectCollection.GetService();

            if (_workItemStore != null)
            {
                if (_workItemStore.Projects.Count > 0)
                {
                    foreach (Project prj in _workItemStore.Projects)
                    {
                        this.cmbProjects.Items.Add(prj.Name);

                        if (this.cmbWorkItemTypes.Items.Count == 0)
                        {
                            foreach (WorkItemType wtype in prj.WorkItemTypes)
                            {
                                string wtypeName = wtype.Name;
                                if (!this.cmbWorkItemTypes.Items.Contains(wtypeName))
                                    this.cmbWorkItemTypes.Items.Add(wtypeName);
                            }
                        }

                    }
                }
            }


            this.cmbWorkItemTypes.SelectedIndex = this.cmbWorkItemTypes.Items.IndexOf(_currentWorkItem.Type.Name);
        }

        private void btnOk_Click(object sender, EventArgs e)
        {
            if (_currentWorkItem != null)
            {
                CreateNewWorkItem();
                string message = string.Format("Copied Item Successfully !!! \r\n Source Item ID {0} has {1}  Attachments and {2} Links \r\n\r\n Target Item ID {3} has {4} Attachments and {5} Links",
                    _currentWorkItem.Id,
                    _currentWorkItem.Attachments.Count,
                    _currentWorkItem.Links.Count,
                    _newWorkItem.Id,
                    _newWorkItem.Attachments.Count,
                    _newWorkItem.Links.Count);
                MessageBox.Show(message, this.Text, MessageBoxButtons.OK);
            }

            this.DialogResult = System.Windows.Forms.DialogResult.OK;
        }

        private void CreateNewWorkItem()
        {

            Project targetProject = _workItemStore.Projects[this.cmbProjects.SelectedItem.ToString()];

            WorkItemType wit = targetProject.WorkItemTypes[this.cmbWorkItemTypes.SelectedItem.ToString()];

            _newWorkItem = _currentWorkItem.Copy(wit);

            RelatedLink source2Target = new RelatedLink(targetProject.Id);
            _newWorkItem.Links.Add(source2Target);

            System.Net.WebClient request = new System.Net.WebClient();
            request.Credentials = System.Net.CredentialCache.DefaultCredentials;
            string tempPath = System.IO.Path.GetTempPath();
            if (_currentWorkItem.Attachments.Count > 0)
            {
                foreach (Attachment attach in _currentWorkItem.Attachments)
                {
                    string attachmentPath = Path.Combine(tempPath, attach.Name);
                    request.DownloadFile(attach.Uri, attachmentPath);
                    _newWorkItem.Attachments.Add(new Attachment(attachmentPath));

                }
            }
            _newWorkItem.Save(SaveFlags.MergeLinks);

        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            this.DialogResult = System.Windows.Forms.DialogResult.Cancel;
        }
    }

12. Also add a new helper class WitDocumentHelper
 class WitDocumentHelper
    {

        public static IWorkItemTrackingDocument GetCurrentWitDocument(IServiceProvider serviceProvider)
        {
            Debug.Assert(serviceProvider != null);

            EnvDTE.DTE dte = (EnvDTE.DTE)serviceProvider.GetService(typeof(EnvDTE.DTE));
            if (dte.ActiveDocument == null)
                return null; // No active document

            DocumentService docService = (DocumentService)serviceProvider.GetService(typeof(DocumentService));
            if (docService == null)
                return null; // Possibly VSTS WIT is not installed or instantiated yet.

            IWorkItemTrackingDocument doc = docService.FindDocument(dte.ActiveDocument.FullName, serviceProvider);
            return doc; // Caller must release the document after use
        }

    }

This completes the task of creating a package to copy workitem between projects. Complete source code is available on Git via codeplex at tfshelperforvs2010.codeplex.com.

All of the biggest technological inventions created by man - the airplane, the automobile, the computer - says little about his intelligence, but speaks volumes about his laziness. ~Mark Kennedy

Thursday, 3 May 2012

ASP.NET MVC login page throwing error "The resource cannot be found"


As per ASP.NET MVC getting the error message "The resource cannot be found" is as simple as verifying if the view/user control does actually exist or name of the view/user control is misspelled.

But in this case that is not the issue because the controller "AccountController" does exist and the view "Login.aspx" also does exist. So have started using google search and tried various suggestions but nothing did work.

Also I have created another sample ASP.NET MVC standard project and have modified web.config to use forms authentication and that works, so the issue is not the environment.

Actually I have missed out a point about some configuration changes I have made to project. The requirement was actually to support "IIS 7" & "IIS 6" as well. The changes I have actually made are

1. Added extra routing in global.asax.cs
public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Default.aspx", // Route name
                "{controller}.aspx/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Default", id = UrlParameter.Optional } // Parameter defaults
            );

            routes.MapRoute(
                "Root",
                "",
                new { controller = "Home", action = "Default", id = UrlParameter.Optional });
        }
2. Added "default.aspx" to project at the root
3. Now add "Page_Load" event to code behind
public partial class _default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            HttpContext.Current.RewritePath(Request.ApplicationPath);
            IHttpHandler httpHandler = new MvcHttpHandler();
            httpHandler.ProcessRequest(HttpContext.Current); 
        }
    }

All these changes allows running ASP.NET MVC application on IIS6. All this said I am still unable to find out the fix for this issue. Started looking at the error message again to see if I have missed out any thing, Aha.... I found it. Look at the url on the address bar
http://localhost:49668/Account/Logon?ReturnUrl=%2fdefault.aspx

Lets look at first route map
 routes.MapRoute(
                "Default.aspx", // Route name
                "{controller}.aspx/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Default", id = UrlParameter.Optional } // Parameter defaults
            );

ie.. request for "default.aspx" will use "Home" controller with action as "Default"

Second route map
 routes.MapRoute(
                "Root",
                "",
                new { controller = "Home", action = "Default", id = UrlParameter.Optional });

ie.. request to root of the website to be redirected to "default.aspx", use "Home" controller with action as "Default"

Both are fine but I have missed out default ASP.NET MVC routing which is (ie.. "{controller}.aspx" modified to "{controller}"
 routes.MapRoute(
                "Default", // Route name
               "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Default", id = UrlParameter.Optional } // Parameter defaults
            );

After adding this application started working and I have got the login page.

Treat your password like your toothbrush. Don't let anybody else use it, and get a new one every six months.
~Clifford Stoll

Tuesday, 1 May 2012

Unable to debug Visual Studio 2010 addin or suddenly stopped working

I have created a new addin for Visual Studio 2010 using standard addin template. The sample works fine, then I start making some changes and adding more dependencies. Yes got some compilation errors and have fixed them. Now after starting debugging a runtime error is thrown, so fixed that.

Now If I start debugging, the addin no longer gets loaded and also won't show in Addin Manager (VS2010 -> Tools -> Add-in Manager). Now this is really getting me upset.

Used our friend google to find a solution but no luck. So started looking at places where addins were loaded from, aha.. I found the issue.



1. Looking at "C:\Users\Saif\Documents\Visual Studio 2010\Addins" I have found the addin file was renamed from "MyAddin2 - For Testing.AddIn" to "MyAddin2 - For Testing.AddIn_" ie.. an "_" in the end. I think this might have done by visual studio, ie.. since visual studio is unable to load the addin it has renamed by adding "_"

So renaming back from "MyAddin2 - For Testing.AddIn_" to "MyAddin2 - For Testing.AddIn" started loading the addin.

2. Also verify Project Properties -> Debug



1. "Start external program" : "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\devenv.exe"
2. "Command line arguments" : "/resetaddin MyAddin2.Connect"
3. "Working directory" : "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\"

The inside of a computer is as dumb as hell but it goes like mad! ~Richard Feynman

Sunday, 29 April 2012

Storing TFS Credentials in VS2010

Visual Studio 2010 have not got an option to store credentials of TFS login which make you really cranky at times. So to store the credentials and avoid the prompt when connecting to external TFS server please follow the steps below:-

Using windows 7

1. Go to Control Panel -> User Accounts and Family Safety -> User Accounts
2. Select "Manage your credentials"
3. Select "Add a Windows credential"
4. Specify the network address (for eg:- tfs.codeplex.com)
5. Now provide username and password, select "Ok" to save your credentials.

Now when you try to connect to external TFS servers you will not see login prompt, but remember to update your password if its changed.

There are three kinds of death in this world. There's heart death, there's brain death, and there's being off the network. ~Guy Almes

Thursday, 26 April 2012

Setting up FileZilla Server and Client for transferring files with FTP

FileZilla is a free FTP solution that allows you to setup an FTP site with in minutes. Refer to filezilla site for more details

Setting up the FileZilla Server


Installing FileZilla Server


1. Goto FileZilla Server and download the "FileZilla_Server-0_9_41.exe"
2. Run "FileZilla_Server-0_9_41.exe" and select Next
3. Choose components to install
4. Choose Install location (use default location)
5. Select service start-up settings
6. Select FileZilla interface start-up settings
This should complete the installation


Configuring FileZilla Server


Configure Group


1. Start FileZilla service (Start -> All Programs -> FileZilla Server -> Start FileZilla Server)
2. Now open FileZilla Interface (Start -> All Programs -> FileZilla Server -> FileZilla Server Interface)
3. Use default settings on the connect to server dialog
4. Connection should succeed and display FileZilla Interface
5. Select Edit -> Groups
6. Select "Add" and specify group name
7. Now select "Shared folders" and add a directory (eg: D:\MyFTPShare\csharptechies)


Configure Users

8. Select Edit -> Users and add a user account
9. Select "Password" and assign a password 10. Select "Shared folders" and add a directory (eg: D:\MyFTPShare\csharptechies)
Note: Assuming this is admin account assign all permissions for the directory 11. Add another user (like a friend or colleague who belong to same group)
12. Select "Password" and assign a password 13. Select "Shared folders" and add a directory (eg: D:\MyFTPShare\csharptechies\saif)
Note : Instead of giving permissions for the directory that belongs to the admin, create a sub directory under that for each user. Repeat steps 11,12 & 13 for all users in the group.

Installing FileZilla Client


1. Goto FileZilla Client and download the "FileZilla_3.5.3_win32-setup.exe"
2. Run "FileZilla_3.5.3_win32-setup.exe" and select Next
3. Choose components to install
4. Run to completion

Connecting FileZilla Client to Server


1. Open FileZilla Client (Start -> All Programs -> FileZilla FTP Client -> FileZilla)
2. select File -> Site Manager
3. select "New Site" and specify details (port number is not required if firewall is not enabled)
4. Now select "connect"
Now looking at FileZilla Server interface will show the list of users (clients) connected
All done !!!!. Now you can transfer (upload/download) files between server and your clients.

Other ways of connecting clients to FileZilla Server


- Open windows explorer and specify ftp location ftp://129.86.76.32/, then provide the user credentials
- Open firefox browser and provide the url as ftp://saif@129.86.76.32/ (needs firefox plugin fireftp)

“We have to stop optimizing for programmers and start optimizing for users.”
– Jeff Atwood

Sunday, 25 March 2012

Sharing photos using SignalR

SignalR is the latest .NET library available for broadcasting data from a hub to its clients (similar to polling methods used for various sites such as facebook, twitter etc). More information about SignalR is available at signalr.net

I have tried a simple mvc application that can be used to share photos between friends which gets updated instantaneously. An user connected to the website can upload a photo which will be automatically broadcasted to all clients connected at that point.

Here is how it looks:-



Latest version of source is available at photowebpro.codeplex.com

SignalR is an asynchronous signaling library for ASP.NET that can be used to build real-time multi-user web application. There is a simple and interesting video available on Channel 9 about SignalR, which will give you a heads-up.

Technology presumes there's just one right way to do things and there never is. ~Robert M. Pirsig

Thursday, 8 March 2012

Using join on a subquery with NHibernate

NHibernate is one of the best ORM solution available. That said sometimes its not easy to find a way around your problem. I have been trying to create a join on a subquery and want to uses "EXISTS" on a table to be more efficient.

Here is my class design


All I want is to get list of flytoys for a purchase order
- filter on customer name
- get the oldest purchase order

After trying many various methods, here is the code snippet that worked for me:

  public FlyToy[] GetPendingToys(int Count)
        {
            using (var session = OpenSession())
            {
                PurchaseOrder po = null;
                FlyToy toy = null;
                QueryOver subQuery = 
                    QueryOver.Of(() => po)
                        .SelectList(list => list
                            .SelectGroup(() => po.Toy.ID)
                            .SelectMin(() => po.OrderDate))
                        .Where(Restrictions.EqProperty(
                            Projections.Property(() => po.Toy.ID),
                            Projections.Property(() => toy.ID)))
                        .Where(p => p.CustomerName == "Saif");


                var mainQuery = QueryOver.Of(() => toy)
                    .Fetch(t => t.Discount).Eager
                    .WithSubquery.WhereExists(subQuery).Take(Count);

                IList results = mainQuery.GetExecutableQueryOver(session)
                    .List();

                FlyToy[] FlyToys = results.ToArray();
                return FlyToys;
            }
        }


Be nice to nerds. Chances are you'll end up working for one.
- Charles Sykes

Friday, 2 March 2012

Website giving an error Retrieving the COM class factory for remote component with CLSID

I have got a website which was working fine until today and all of sudden I am getting following error message when tried to access the website.

Retrieving the COM class factory for remote component with CLSID {xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} from machine MMMMMMMM failed due to the following error: 80070005.

There's has been no changes to the code base,no changes to its dependencies and nothing noticeable. So remember the word noticeable, simple to say but very hard to point out. The error code 80070005 usually means that you do not have enough permission.

That does not help at all why would I get an error message as not enough permission if I am using windows authentication for the website. After digging some more the situation is this website is making a call to another webservice which is giving this error message.

Fine now both of them are running under the same application pool then it should work, but its not. Finally working through all the odd methods I have found impersonation is set to true for the website that's hosting the web service. I have just made

impersonate=false 

and yes that started working.

All in all the point I have missed out in my investigation is checking web.config. Anyway lesson learned for next time.

Information technology and business are becoming inextricably interwoven. I don't think anybody can talk meaningfully about one without the talking about the other. ~Bill Gates

Monday, 27 February 2012

Assigning default value for fields of type string using Fluent NHibernate

Fluent hibernate provides various decent methods that allow you to map class members with table fields. I have tried using the .Default() method while mapping which works fine for numbers but for string datatype this is not working.

So have looked into the actual execution of sql which looks like (ie.. I have added a new member to the class and want all exists rows to have a default value)

update dept
set location = Manchester

Then I have realised single quote(') were missing for the value which should look like

update dept
set location = 'Manchester'

Now I have updated my mapping as follows

Map(x => x.location).Default("'Manchester'").Not.Nullable();

Never trust anything that can think for itself if you can't see where it keeps its brain.
~J.K. Rowling

Wednesday, 15 February 2012

Guidelines for Optimising ASP.NET Websites

Optimisation is one of the most challenging task for any website. Optimisation should be planned just like any development task so as to avoid spending more time towards the end of project. There are various elements that needs to be considered during this process, here is the list below:-

1. Reduce number of requests made to the server by using minification of stylesheets(.css) and javascript code(.js)

2. Combining all resources and deliver zipped verion (using GZIP)

3. Prefer GET than POST for ajax calls

4. Prioratise loading of resources and use lazy loading

5. Be cautious about references to resources and remove unwanted/unavailable references (No 404)

6. Use image maps as opposed to independent images(.jpeg,.gif etc)

7. Use caching for static components such as images

8. Make Ajax calls cachebale

9. Try using external scripts & css whereever possible (use CDN)

10. Reduce cookie size and also make cookieless request for resources such as images

There are various tools/plugins/extensions that are freely available, these can help you point out optimisation issues relating to your website. But each of these tools use different sets of rules and provides different types of statistics. Here is the short list:-

All of the biggest technological inventions created by man - the airplane, the automobile, the computer - says little about his intelligence, but speaks volumes about his laziness.
Mark Kennedy

Copyright © 2013 Template Doctor . Designed by Malith Madushanka - Cool Blogger Tutorials | Code by CBT | Images by by HQ Wallpapers