12/31/12

Mobile site development - basic points to remember

A mobile site is a powerful mechanism to reach out to millions and billions of users. Though there are similarities with a desktop site, the development of a mobile site is significantly different from a desktop site and comes with a lot of unique challenges and frustrations. Following are some of the points to keep in mind:
  • mobile site audience
    • The mobile user is most likely on the move and accesses the site via small mobile devices
    • The user's patience is limited by the fact that the devices have a limited real-estate and a slower connection compared to a desktop site.
    • The user is expecting to see a simple and intuitive site with easy access to all the important areas of the site.
    • The user will not appreciate or tolerate any unnecessary complexity or slowness on the site.
    • A lot of companies offer mobile versions of their desktop sites and the user has multiple alternatives if the user is not happy with your mobile site
  • mobile devices
    • The real-estate on the mobile devices is limited
    • The devices are not connected to a local access point but work via cellular networks. 
    • The devices run on different mobile operating systems and each operating system comes with its own browser and associated quirks.
    • The device is also a phone, a music player, a video player and much more than just a browser.
  • mobile site look and feel
    • If you are developing a mobile version of a desktop site, the mobile interface needs to be consistent with the desktop site. Though the colors and themes do not have to be exactly the same, there should be an element of familiarity with the desktop version. The users must feel that they are experiencing a concise version of the desktop site.
    • If you are developing a mobile version of a desktop site, the mobile site should behave the same way as the desktop i.e users must experience similar results when they take similar actions on both versions.  
  • mobile site development and testing
    • Mobile sites need to work on mobile devices that run on different operating systems like ios, android,windows and blackberry. This can lead to behavioral quirks and can cause development and testing headaches. This additional complexity must be kept in mind while scoping the time for mobile tasks. 
    •  If you are developing a mobile version of an existing desktop site , it is very likely that you are sharing class libraries between both the versions. Great caution must be taken to ensure that the common libraries are not tampered with in an undesired manner. We need to pay attention to the versioning of the libraries and regression issues every time we make any changes to the common libraries. If any changes are made, care must be taken to do regression testing on both the mobile and site versions. 
  •  mobile network issues
    •  Since the mobile devices are well - mobile, all the communication is wireless and happens through cellular towers that are provided by the cell providers like verizon and sprint. As a result the network speed is limited and there is bound to be some latency involved. It would be wise to reduce the number of requests between the client and server. 
    • Mvc 4 has a concept called bundling that allows us to bundle multiple javascript/css files required on a page and cuts down the number of requests made to the server. Custom bundling also reduces the size of the js/css files.


11/26/12

Chain of responsibility design pattern


The Chain of Responsibility design pattern states:

"Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it. '

I had an opportunity to implement a slight variation of this pattern on one of my recent coding assignments. The requirements for the task were as follows:

There are two partner sites - Site A and Site B. A user on Site A can become a member of Site B by simply clicking on a link. As soon as the user clicks the link on Site A, the site creates an object that encapsulates all the user's information and passes it on to the code on Site B. The users on both the sites share some common attributes and the code on Site B knows how to retrieve the various attributes from that object and map them to the corresponding attributes on Site B. The end goal is to migrate all the Site A user's information into Site B without the user having to fill out all that information on Site B once again.

Based on the requirements above it felt like a good idea to use the Chain of Responsibility pattern. The incoming object from Site A encapsulates different sets of attributes like the user's personal details, professional details, user's hobbies and interests and other such data. So we had this one big request or object that had to be mapped into multiple different entities on the receiving site. This meant that we had to have multiple handlers(classes) on the receiving side each of which knows how to handle the incoming object and map a certain set of the user's attributes.for e.g. we have a class called PersonalInfoMapper that knows how to map the user's personal details from Site A to Site B. We have a class called ProfessionalInfoMapper that knows how to map the user's professional details and so on.

So we implemented the pattern by developing a set of classes that know how to handle the incoming object. The first class in the flow is provided with the incoming object. It maps the data that it can and passes it on to the next class in line. By the end of the chain of classes, all the data for the user from Site A will have been mapped to the corresponding data on Site B. The code stubs for the pattern are as follows:



//The base classes of all the handlers in the Chain of Responsibility

public abstract class MapperBase
{
 protected MapperBase NextHandler;
 public abstract void Execute(MyType siteAObject);
}

public abstract class MapperBase<T>:MapperBase
{  
 public abstract T MapToModel(MyType siteAObject);
 public abstract void Save(T siteBObject);
 public override void Execute(MyType siteAObject)
        {
   //map the incoming data into a custom object
   var siteBModel = MapToModel(siteAObject);
 
          //save the mapped data
            Save(siteBModel);
 
          //if there is a next handler,continue processing
            if (NextHandler != null)
               NextHandler.Execute(siteAObject);            
        }
}


//The first handler in the Chain
public class PersonalInfoMapper : MapperBase<PersonalInfoModel>
{
 public PersonalInfoMapper(ProfessionalInfoMapper nextHandler)
        {
            NextHandler = nextHandler;
 }
  
       public override PersonalInfoModel MapToModel(MyType siteAObject)
        {
   //map data and return mapped object of type PersonalInfoModel   
 }
  
 public override void Save(PersonalInfoModel model)
        {
  //save data
 }
}


//The Next handler in the Chain
public class ProfessionalInfoMapper : MapperBase<ProfessionalInfoModel>
{
 public ProfessionalInfoMapper(InterestsInfoMapper nextHandler)
        {
            NextHandler = nextHandler;
 }
  
 public override ProfessionalInfoModel MapToModel(MyType siteAObject)
        {
  //map data and return mapped object of type ProfessionalInfoModel   
 }
  
 public override void Save(ProfessionalInfoModel model)
        {
   //save data
 }
}


//The Last handler in the Chain
public class InterestsInfoMapper : MapperBase<InterestsInfoModel>
{
 public InterestsInfoMapper()
        {
            NextHandler = null; //no more handlers in the chain
 }
  
 public override InterestsInfoModel MapToModel(MyType siteAObject)
        {
   //map data and return mapped object of type InterestsInfoModel   
 }
  
 public override void Save(InterestsInfoModel model)
        {
   //save data
 }
}

//Calling Code. The types are being instantiated via unity dependency injection
/* 
   The first handler executes, and if it has a next handler specified it triggers the next handler passing the incoming object to it. This process
   continues until there are no more handlers in the chain
*/
public class CallingCodeClass
{
  [Dependency]
  public PersonalInfoHandler FirstHandler {get;set;}

  public void CallingMethod()
  {
 FirstHandler.Execute();
  }
}

10/5/12

Scrum Process - One Week Sprint

Scrum is a framework for developing software in an agile manner. The tasks are broken down into manageable chunks, the teams are small and self-managed and a great deal of collaboration and communication among team members is necessary to complete the tasks. A typical implementation of the framework involves certain steps, some of which are optional. It is upto the team to decide which steps they wish to implement. A typical iteration(known as a sprint) usually lasts two weeks, but the timeframe is entirely dependent on the team's requirements and goals. In my team we have a one week scrum and following are the steps involved:
  • Monday
    • Backlog grooming Meeting. This is an hour long meeting between the Product leads and the technical leads.The product team comes to the meeting with a prioritized list of tasks(also referred to as Stories) that are a part of the product road map for the near future.The technical leads analyze the requirements associated with each Story and estimate the size of each Story by associating a numeric value for each. for e.g. a small Story would be a 2, a medium size Story would be a 5 and a large size Story would be an 8 and so on. We tend to use the Fibonacci series as a guideline for our numerical estimates. If a story is large, it can be broken down into smaller Stories and implemented across multiple Sprints.
    • From the list above, the Product Manager selects a list of Stories for the week and sends it out to the technical team for review. The technical team members study these Stories prepare for the sprint meeting that happens on Tuesday.
  • Tuesday
    • Sprint Meeting. This meeting is attended by the entire technical/QA team and the product team. The Product Manager explains the requirements for each Story. For every Story, the technical team members are asked to provide a numerical estimate based on their understanding of the Story. The Story size usually ends up being the value that the majority of the team agree upon.Team members who provide higher/lower estimates than the average are asked to provide an explanation behind their estimates. If they are able to convince the team with their reasoning, there is a good chance of the Story size ending up higher/lower than the previous estimate.
    • The technical/QA team breaks down each story into UI/Code/DB/QA components by creating visual cards for each piece. for e.g. a story can have three UI cards, two code cards, one DB card and four QA cards. It is also possible that some stories are purely DB related or purely Code related and do not have UI cards.
  • Wednesday
    • The technical/QA team starts working on the Stories for the Sprint. The developers start coding and the qa people start writing test cases. The code is pushed into QA as soon as the developers complete coding/unit testing.So while QA tests the features in the QA environment, the developers continue to work on the next items in the prioritized list of stories for the Sprint.
  • Thursday, friday
    • Team continues development/testing
  • Next Monday
    • A repeat of the previous Monday but targeting the the next sprint
    • Work continues on the current sprint
  • Next Tuesday
    • A repeat of the previous Tuesday but for the next sprint
    • Work continues on the current sprint
  • Next Wednesday
    • The code from the Current Sprint is pushed into production. This usually involves more work on the QA side.
    • The developers begin working on the next Sprint
  • Next Thursday
    • Sprint Retrospective. This meeting is attended by the product and the technical/QA teams. The pros and cons associated with the Previous Sprint are discussed. The discussions revolve around what was done well, what can be improved and how to streamline the process in the future. The suggestions for improvement are duly noted and applied to the future Sprints.
  • The process continues

7/8/12

Asynchronous Programming in .NET - Part 2

As I mentioned in my previous article Asynchronous Programming in .NET - Part 1, delegates can be used to facilitate asynchronous calls. The Client creates an instance of the delegate class, specifies the method that is being delegated, and then invokes the delegate which handles the execution of the specified method on a separate thread pool thread.

The drawback to this is that the calling code needs to do all of the following:
  • Be aware of the Delegate and its signature
  • Create a method with the same signature as the delegate
  • Create an instance of the delegate and assign the method above to it
  • Call BeginInvoke on the delegate to begin the task
  • Call EndInvoke on the delegate to capture the results

In the case of long running tasks like Web Service calls, Web Requests and network access calls, it is obvious that the Client would prefer to invoke the methods asynchronously. In such cases it makes sense to expose asynchronous methods to the Client. The Client can then call these asynchronous methods instead of having to do all the work above involving delegate calls.

Following is an example of such a class.


public class SportsDelegate
    {
        
        private delegate void TeamOwnerDelegate(string team,out string owner);
        
        //the method that is called by the Client to invoke the delegate
        public IAsyncResult FindOwnerName(string team,out string owner,AsyncCallback callback,object state)
        {
            //specify the method that needs to be delated
            TeamOwnerDelegate objdel = TeamOwnerBegin; 
            return objdel.BeginInvoke(team, out owner, callback, null);
        }       

        //the method that is delegated to the thread pool thread
        private void TeamOwnerBegin(string team, out string owner)
        {
            //this method sets the value for the ouput variable "owner"
            //we are keeping it simple - this could have been a call to 
            //the DB or some external datasource if necessary
            switch (team.ToUpper())
            {
                case "DALLASCOWBOYS":
                owner = "Jerry Jones";
                break;
                case "DALLASMAVERICKS":
                owner = "Mark Cuban";
                break;
                default:
                owner = "Nolan Ryan"; //texas rangers owner is the default
                break;
            }
            
        }

        //this is the method called by the Client to get the results
        public string GetOwnerName(IAsyncResult result)
        {
            AsyncResult objreturn = (AsyncResult)result;
            TeamOwnerDelegate objdel = (TeamOwnerDelegate)objreturn.AsyncDelegate;
            string owner = null;
            
            try
            {
                objdel.EndInvoke(out owner, result);
                return owner;
            }
            catch (Exception ex)
            {
                return null;
            }
        }       
    }

The class above exposes two public asynchronous methods to the client, one called "FindOwnerName" and the other is called "GetOwnerName". All the client needs to do is call these public methods as needed. The Client does not need to be aware of the delegate and does not have to do any extra work to make asynchronous calls. The SportsDelegate class handles all the work related to creating/instantiating the delegate and calling the BeginInvoke and EndInvoke methods as needed.

Following is how the client code looks:

public class HomeController : Controller
    {
        
        public ActionResult Index()
        {           
            string owner;
            SportsDelegate obj = new SportsDelegate();
            obj.FindOwnerName("dallascowboys", out owner, MyCallBack, null);       
            return View();
        }

         private void MyCallBack(IAsyncResult result)
        {
            //this needs to be thread safe since this will be 
            //called by the thread pool thread
            SportsDelegate obj = new SportsDelegate();
            string owner = obj.GetOwnerName(result);
            ViewBag.Message = string.Format("My owner name is is {0}", owner);
        }
}

The code above calls the FindOwnerName method to start processing. Once that asynchronous method completes, it invokes the Callback method specified by the Client. In the callback method, the Client makes a call to the GetOwnerName method to get the results.

NOTE:
A certain amount of thread synchronization will be necessary to handle the interaction between the Client and the SportsDelegate class


Examples of .NET framework classes that provide asynchronous methods are Stream and Web Service Proxy classes.(reference: programming .NET components by Juval Lowy)

Asynchronous programming in .NET - Part 1

Asynchronous programming in .NET is facilitated via Delegates. A delegate is a mechanism that is used to delegate a method call as shown in the code below.



//my custom class in the class library where i have defined the delegate
public class MyCustomDelegates
{
 public delegate string MyFootballDelegate(string team);
}

public class Client
{
 public void ProcessDelegates()
 {
   MyFootballDelegate objDelegate = Dallas;
   objDelegate("cowboys");
 }
 
 private string Dallas(string team)
 {
  //do something here
  return string.format("{0} - {1}","Dallas", team);
 }
}


In the code above, the Client creates an instance of the Delegate called MyFootballDelegate and assigns a method Dallas to it. The Client then invokes the delegate passing in an input value called "cowboys".So what the client is doing is delegating the act of calling that method Dallas to an instance of the MyFootballDelegate class(the compiler internally converts a delegate declaration into a class).

BeginInvoke() and EndInvoke()

In the code above the Client blocks until the method Dallas completes, so this use of delegates is not really asynchronous. To make the call asynchronous the Client needs to invoke BeginInvoke and EndInvoke methods on the delegate as follows:


public class Client
{
 public void ProcessDelegates()
 {
   MyFootballDelegate objDelegate = Dallas;
   iAsyncResult objAsyncresult = objDelegate.BeginInvoke("cowboys",null,null);
   string result = objDelegate.EndInvoke(objAsyncresult);
 }
 
 private string Dallas(string team)
 {
    //do something here
           return string.format("{0} - {1}","Dallas", team);
 }
}


The call to BeginInvoke uses a thread from the .NET Thread pool and queues up the delegate call. So it blocks the calling code for only a brief moment.The Client then calls the EndInvoke to get the result from the method call.

Completion Callback Methods

The Client, instead of calling EndInvoke explicitly, can pass a callback method to the BeginInvoke method that is invoked as soon as the method Dallas ends. Code is as follows:

public class Client
{
       public void ProcessDelegates()
       {
   MyFootballDelegate del= Dallas;
          iAsyncResult obj = del.BeginInvoke("cowboys",DallasCallback,null);   
 }
 
 private string Dallas(string team)
 {
          //do something here
          return string.format("{0} - {1}","Dallas", team);
        }
 
 //the callback method must have the following signature
 private void DallasCallback(IAsyncResult result)
 {
  //call to EndInvoke happens here and the result is obtained here
 }
}


NOTE:
In the code above, the Client specifies the method DallasCallback as the callback in the BeginInvoke call.So the thread from the thread pool that executes the Method Dallas,will also call the callback method as soon as the Dallas method completes. So the code in the DallasCallback method needs to be thread-safe.Besides, a certain amount of thread synchronization will be necessary to handle the interaction between the calling code and the delegate call/callback methods related code

The code in the callback method needs to call EndInvoke on the delegate as follows:


private void DallasCallback(IAsyncResult result)
{
 //call to EndInvoke happens here
 AsyncResult objreturn = (AsyncResult)result;
 MyFootballDelegate objDelegate = (MyFootballDelegate)objreturn.AsyncDelegate;

        //the value returned by method Dallas
 string result = objDelegate.EndInvoke(result); 
}

4/7/12

extending System.Linq.IOrderedEnumerable

Recently I was writing code to develop a web page that displayed a list of users. The page also had a drop down list containing the following sort
options:

Sort by last Name Descending
Sort by last Name ascending
Sort by Age descending
Sort by Age ascending
Sort by Activity Date desc
Sort by Activity Date asc
Sort by Login Date desc

The users have to be grouped by Location by default and then the selected sort was to be applied within each group.
The tricky business requirement was that if there is a tie while sorting by age or Last Name, the tied users had to be further sorted by Activity Date
descending and if there was still a tie, the users had to be sorted by Login Date descending.

Assume that the user decided to sort the default list using one of the options above. Let us call this variable "UserSort".
if the UserSort was "LastNameDesc" then we need to sort by the DB field called LastName.
if the UserSort was "LastNameDesc" then we need to sort by the DB field called LastName in descending order
if the UserSort was "Age" then we need to sort by the DB field called Age

So we need to determine the DB field to sort by, based on the user selection. We cannot do that using the existing OrderBy methods on IEnumerable
as shown below,since we do not know what field we will be sorting by.



IEnumerable lstUsers = GetUsers();
lstUsers = lstUsers.OrderBy(x=>x.Location) //default ordering
           .ThenOrderBy(WHAT FIELD DO WE SPECIFY HERE?)


This is where Extension methods come into play. following is the extension method on IOrderedEnumerable that enables us to add the required order
to the list based on the user's selected sort option.


public static IOrderedEnumerable ThenByCustomSort(this IOrderedEnumerable defaultList,string sortOrder)
{
switch(sortOrder)
{
case "LastNameDesc":
return defaultList.ThenByDescending(x=>x.LastName);
case "LastNameAsc":
return defaultList.ThenBy(x=>x.LastName);
case "AgeDesc":
return defaultList.ThenByDescending(x=>x.Age);
case "AgeAsc":
return defaultList.ThenBy(x=>x.Age);
case "ActivityDateDesc":
return defaultList.ThenByDescending(x=>x.ActivityDate);
case "ActivityDateAsc":
return defaultList.ThenBy(x=>x.ActivityDate);
case "LoginDateDesc":
return defaultList.ThenByDescending(x=>x.LoginDate);
default:
return defaultList;
}

}


This is how we add call this method:


IEnumerable lstUsers = GetUsers();
lstUsers = lstUsers.OrderBy(x=>x.Location)
           .ThenByCustomSort(UserSort);


Now coming to the tie in the results.We do something similar and create an extension method as shown below:


public static IOrderedEnumerable ThenByTieBreakSort(this IOrderedEnumerable defaultList, string sortOrder)
{ 
switch(sortOrder)
{
  case "LastNameDesc": 
  case "LastNameAsc":
  case "AgeDesc":
  case "AgeAsc":
   return defaultList.ThenByCustomSort("ActivityDateDesc").ThenByCustomSort("LoginDateDesc");
 case "ActivityDateDesc": 
  return defaultList.ThenByCustomSort("LoginDateDesc");
 default:
  return defaultList;
}
}


After adding the tiebreak the code looks now looks as shown below:


IEnumerable lstUsers = GetUsers();
lstUsers = lstUsers.OrderBy(x=>x.Location)
           .ThenByCustomSort(UserSort)
           .ThenByTieBreakSort(UserSort);

IMPORTANT:
Since LINQ queries are executed by means of deferred execution, we need to ensure that we are adding additional sort options well before the
query gets executed, which is exactly what the use of the extension methods above does.

NOTE:
I have used string data type for the sortOrder just for the purposes of blogging. It is better to use some strongly typed data type, like enums,
for the purpose. I have also not taken string casing into consideration.

Peace out.

2/13/12

Some more useful MVC grub

Assigning values to Action method parameters via OnActionExecuting handler

Let us say there is an action method as shown below:


[SetParameterValueFilter]
public ActionResult GetCityDetails([Bind(Prefix="MyCity")]string cityName)
{

 return View();

}


This method takes one string input parameter called "cityName" and returns a view.As you can see, the method is also decorated with a custom filter called "SetParameterValueFilter".

The purpose of this filter is to assign a value to the input parameter "cityName" of the action method GetCityDetails based on a certain condition X. So if the condition X is satisfied we will set the parameter value to "Dallas" else we will set it to "Houston".

We achieve this by overriding the OnActionExecuting method of the MVC framework that gets called before the GetCityDetails method gets called.

The code is as follows:


public class SetParameterValueFilterAttribute : ActionFilterAttribute
{  
   public override void OnActionExecuting(ActionExecutingContext context)
   {
     ParameterDescriptor[] ActionMethodParams = context.ActionDescriptor.GetParameters();

    //get the parameter that has a prefix 
    //of "MyCity" and set the value
     foreach (var param in ActionMethodParams)
     {
      if (param.BindingInfo.Prefix.ToUpper() == "MYCITY")
       {
          //set the parameter value
        if(ConditionX)
          context.ActionParameters[param.ParameterName] = "Dallas";
        else
          context.ActionParameters[param.ParameterName] = "Houston";
        break;
       }
     }
  }   
}

Some useful MVC grub

Changing the view name via the OnActionExecuted handler

Let us say there is an action method as shown below:


[ChangeViewFilter]
public ActionResult GetTeamDetails(string teamName)
{

 return View("DallasCowboys");

}

This method takes one input parameter called "teamName" and returns a view called "DallasCowboys".As you can see, the method is also decorated with a custom filter called "ChangeViewFilter".

The purpose of this filter is to change the View Name in the ActionResult of the GetTeamDetails method,if a certain condition X is satisfied. So if the condition X is satisfied we will change the View Name to "HoustonTexans" else we do nothing(the name remains "DallasCowboys").

We achieve this by overriding the OnActionExecuted method of the MVC framework that gets called after the GetTeamDetails gets called and before the View Engine is invoked. The code is as follows:


public class ChangeViewFilterAttribute : ActionFilterAttribute
 {
  public override void OnActionExecuted(ActionExecutedContext context)
    {
        //get the current view name
        string ViewName = ((ViewResultBase)(context.Result)).ViewName;

        //if the view name is not specified
     //it means the view name is the same as the action method name
        if (string.IsNullOrEmpty(ViewName))
            ViewName = context.ActionDescriptor.ActionName;

       if(ConditionX)
        ((ViewResultBase)(context.Result)).ViewName = "HoustonTexans";
    }
 }

2/11/12

Custom Model Binder in MVC

During postbacks, the MVC framework automatically binds the incoming data to the specified model. Let us say, you have a postback handler as show below:
 

  [HttpPost]
  public ActionResult MyPostbackHandler(Person person)
  {

  }
  
Assuming that your MVC view was bound to the Person object, when you postback to this method, the framework will automatically create an instance of Person and populate it with the values in the incoming form fields.

So if the Person object has a property called 'Location', the framework will look for a form field with the same name(Remember - "name" not "Id"). If it finds it, it will get the value from that form field and map it to the property. Same is the case with all the other properties and associated form fields. This is the Default MVC Model binding functionality.

 But what if our postback handler was as follows:

[HttpPost]
public ActionResult MyPostbackHandler(Dictionary<string,string> customObject)
{

}
In this case, default model binding will not work, since the method expects a dictionary object. We will have to explicitly extract the values from the incoming form fields and populate the dictionary object.

To do this we will need to create a custom model binder class as shown below.
Let us assume that we are going to only map fields whose names are prefixed with "Custom:"


public class CustomModelBinder : IModelBinder
{
    public object BindModel(ControllerContext cContext, ModelBindingContext bContext)
    {
        const string Prefix = "Custom:";
        string[] AllKeys = cContext.HttpContext.Request.Form.AllKeys;

        //1.get all the form fields with the specified prefix
        List CustomKeys = AllKeys.Where(x => x.StartsWith(Prefix)).ToList();

        var KeyValuePairs = new Dictionary();
        foreach (var key in CustomKeys)
        {
            ValueProviderResult objResult = bContext.ValueProvider.GetValue(key);
            //get the key's value
            string Value = objResult.AttemptedValue;

            //*Refer NOTE 1
            bContext.ModelState.SetModelValue(key, objResult);

            //*Refer NOTE 2
            if (!CusomValidator(Value))
                bContext.ModelState.AddModelError(key, "ErrorMessage");

            //add key and Value to dictionary
            KeyValuePairs.Add(key, Value);
        }
        return KeyValuePairs;
    }
}

NOTE 1
Before you add an error message for a key in modelstate, we must add it's ValueProviderResult(that contains the attempted value) to ModelState by calling SetModelValue. If we do not do that, the key has an associated error message, but does not have an attempted value to display in the front end. So if you use HtmlHelpers and the framework tries to set the attempted value when validation fails(by implicitly calling ModelState["key"].Value.AttemptedValue), it will throw a null exception since the Value is missing.

NOTE 2
Since we are not using default model binding, we cannot use DataAnnotations for Validation purposes, which means if the fields require some validation we will have to explicitly call the validation code and, if there are any errors, add them to ModelState.

Now that we have a custom model binder called CustomModelBinder, we need to tell the framework to use this custom model binder instead of the default one.We do it by adding the following attribute to the postback handler:


[HttpPost]
public ActionResult MyPostbackHandler([ModelBinder(typeof(CustomModelBinder))]Dictionary<string,string> customObject)
{

}

1/22/12

Good Application Development Practices

  • The core components of the application must be identified early and a significant amount of time and effort must be devoted to their design, development and testing. A perfect example of a core component is the Subscription functionality.
  • If possible, the smartest people must be assigned to these tasks.
  • Logging must be enforced in all important areas of the application. This ensures that we have enough diagnostic information to troubleshoot potential issues in production. Logging is also necessary to troubleshoot issues where the application might not be blowing up, but is not performing as intended.
  • The first page in the application that the user lands, after login, must not contain any time-consuming calls that can lead to page timeouts. This will prevent the user from logging into the application and accessing any other areas of the application.
  • Avoid Single Point of Failures. e.g. Do not use a single large object to share data across the whole application. e.g a cache object that stores a huge amount of data that might not be required by all areas of the application. Serialization and deserialization of a large object is a costly process and can slow down the entire application and may even bring the whole application to a halt.  
  • There should be a single point of access to all common objects used across the application. This ensures that the application behaves consistently. e.g. When trying to extract the one and only element from a common list, one part of the code must not call SingleOrDefault while another calls FirstOrDefault.
  • Be extremely cautious if your application uses a memory cache to store objects. When returning values from the cache, always return a deep copy of the object and not a shallow copy. This ensures that the calling code gets it's own copy of the cached data including all reference types. More importantly, this ensures that the calling code does not tamper with the original object in cache.
  • If  the application utilizes separate Read and Write databases, ensure that the database objects(e.g stored procedures) in either case return consistent results.