Asp.net with Muhanad YOUNIS

Call a Function With Retry Using Generics

What if you like to call a web service and retry the call again until response? let me show you a nice way to call a function with retry until you retrieve what ever is needed from the function. This could be achieved by using generics especially by extending the Func<T> delegate; check the code below;

   1: public static class MyExtensions
   2:     {
   3:         public static T WithRetry<T>(this Func<T> action)
   4:         {
   5:             var result = default(T);
   6:             int retryCount = 0;
   7:             var succesful = false;
   8:             do
   9:             {
  10:                 try
  11:                 {
  12:                     result = action();
  13:                     succesful = true;
  14:                 }
  15:                 catch (Exception ex)
  16:                 {
  17:                     retryCount++;
  18:                 }
  19:             } while (retryCount < 3 && !succesful);
  20:             return result;
  21:         }
  22:     }

In the code you can see that we extended the Func that will return an object with type T. This function will keep trying for 3 times but you might change it to keep it trying until it achieve the goal. and here is how to use it


   1: MyService ser = new MyService();
   2: Func<MyService.contentSetList> fCon = () => ser.get(testlist.ToArray<string>());
   3: var con = fCon.WithRetry();
   4: return con;


hope this helps.

References: the original code belongs to Scott Allen at his course C# Fundamentals - Part 2 @ http://www.pluralsight-training.net. thanks Scott.
My Google+ Profile Page
You may follow me from Google+ too https://plus.google.com/u/0/107926756771775811805/posts?hl=en
Posted: Oct 17 2011, 10:12 AM by mohi88 | with no comments
Filed under:
AppFabric

A nice Microsoft Windows Server AppFabric introducing slide show http://bit.ly/afNVHi . do not hesitate to ask me about appfabric and i’ll try to help you as i can to install and operate it.

Posted: Jul 02 2010, 02:17 PM by mohi88 | with 2 comment(s)
Filed under: , ,
C# 4.0 IN NUTSHELL

I found this book very useful and a must-read. The book is really a good reference for C# in general and C# 4.0. Thanks Albahari

C# 4.0 IN NUTSHELL

Posted: Apr 02 2010, 11:54 AM by mohi88 | with 3 comment(s)
Filed under: ,
How to Count Online Users While Using Session State Server (tutorial)
Share |

Here in this post I’ll show you how you to count online users while using state server or SQL server for session state. When you use state server you are not able to catch the session_end event on the global.asax, there for you may not be able to drop the user from you count!. I’ll show you a way to count users. the tutorial will be split  into 3 parts;

  1. Class creation.
  2. Web page side
  3. side

Part 1:

Create a Class named SessionChecker as below;

 

Code Snippet
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Diagnostics;
  5. using System.Web;
  6.  
  7. public class SessionChecker
  8. {
  9.     private static Dictionary<int, DateTime> dictSession;
  10.  
  11.     public static Dictionary<int, DateTime> CreatSessionDictionary()
  12.     {
  13.         var objToLock = new Object();
  14.         var dictControl = HttpRuntime.Cache["UsersCountSession"] as Dictionary<int, DateTime>;
  15.         try
  16.         {
  17.             if (dictControl == null)
  18.             {
  19.                 lock (objToLock)
  20.                 {
  21.                     dictSession = new Dictionary<int, DateTime>();
  22.                     HttpRuntime.Cache.Insert("UsersCountSession", dictSession, null, DateTime.Now.AddMinutes(10100),
  23.                     System.Web.Caching.Cache.NoSlidingExpiration,
  24.                     System.Web.Caching.CacheItemPriority.NotRemovable, null);
  25.                    
  26.                 }
  27.             }
  28.         }
  29.         catch (Exception ex)
  30.         {
  31.             EventLog.WriteEntry("Application", "exception at CreatSessionDictionary: " + ex.Message, EventLogEntryType.Error);
  32.         }
  33.         return HttpRuntime.Cache["UsersCountSession"] as Dictionary<int, DateTime>;
  34.     }
  35.     public static void UpadteInsertSessionDictionary(int pUserId)
  36.     {
  37.         try
  38.         {
  39.             var objElseLock = new object();
  40.             var dic = HttpRuntime.Cache["UsersCountSession"] as Dictionary<int, DateTime>;
  41.             if (dic != null)
  42.             {
  43.  
  44.                 if (dic.ContainsKey(pUserId))
  45.                 {
  46.                     if ((DateTime.Now - dic[pUserId]).Minutes > 2) // to reduce the lock load
  47.                         lock (((IDictionary)dic).SyncRoot)
  48.                         {
  49.                             dic[pUserId] = DateTime.Now.AddMinutes(1);
  50.                         }
  51.                 }
  52.                 else // insert
  53.                 {
  54.                     lock (objElseLock)
  55.                     {
  56.                         dic.Add(pUserId, DateTime.Now.AddMinutes(1));
  57.                         HttpRuntime.Cache["UsersCountSession"] = dic;
  58.                     }
  59.                 }
  60.             }
  61.             else
  62.                 CreatSessionDictionary();
  63.         }
  64.         catch (Exception ex)
  65.         {
  66.             EventLog.WriteEntry("Application", "exception at UpadteInsertSessionDictionary: " + ex.Message, EventLogEntryType.Error);
  67.         }
  68.     }
  69.  
  70.     public static int GetOnlineUsersCount()
  71.     {
  72.         if (null != HttpRuntime.Cache["UsersCountSession"])
  73.         {
  74.             return (HttpRuntime.Cache["UsersCountSession"] as Dictionary<int, DateTime>).Count;
  75.         }
  76.         return 0;
  77.     }
  78. }

Here is the explanation of the class;

  • all methods in the class must be Static.
  • at line 9 create a dictionary that will hold the client Id and the login time of that client. ( here in my case i know that each user is registered in my Db and have got an ID, but you may use session ID for registered and anonymous users.)
  • at line 11 here is the method that will be entered once when the application started .
  • line 14 check if the dictionary object is available in the cache object or not. if its not available, a dictionary object is created and added to cache.( the cache here is 1 week cache, you may use unlimited cache).  You can see that there is a lock on dictionary create, that is to create just one instance of the dictionary if dictControl is null.
  • the second method UpadteInsertSessionDictionary is used to insert and update user. This method can be divided in to two parts;
        1- Update Part : this part starts from line 44. this part check if the dictionary contains the user id or not, if its true then the next step is  check the datetime of the user, i use this step to reduce the lock over head, because when the object is locked one user at the time can enter it. you may ask “why we should lock the dictionary object?” this is because dictionary is unsafe object in threading. So if DateTime.now - user time > 2 min the process enters the lock and updates the user time; which means that user is still online and navigating.(I’ll show you later how and where to implement and call this class on web page part) .
          2- Insert Part: if the dictionary does not contain the user id; the user id inserted into the dictionary the cache must be updated after that.
  • the methods GetOnlineUsersCount will return the user count any time you call it if the cache object is not null, otherwise user count will be 0;

Part 2:

       Web site part;

  • Inherit your web pages from one base page class like below;

 

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Web;
  5. using System.Web.UI;
  6.  
  7. /// <summary>
  8. /// Summary description for WebBasepage
  9. /// </summary>
  10. public class WebBasepage : Page
  11. {
  12.     protected override void OnPreInit(EventArgs e)
  13.     {
  14.         base.OnPreInit(e);
  15.     }
  16.     protected override void OnLoad(EventArgs e)
  17.     {
  18.         SessionChecker.UpadteInsertSessionDictionary(1234);
  19.         base.OnLoad(e);
  20.     }
  21. }

 

  • in line 18 call you static method UpadteInsertSessionDictionary and pass the user id as parameter.
  • in this way you registered your user to the dictionary in cache.

Part 3;

      part is the most important part in this operation; you may check how to create the time from here, but here I’ll show you how to use the timer methods to continue the user count process.

the time class should be like this;

Code Snippet
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Configuration;
  4. using System.Diagnostics;
  5. using System.Linq;
  6. using System.Threading;
  7. using System.Web;
  8.  
  9.  
  10. public class GlobalTimer : IDisposable
  11. {
  12.     private static Timer timer;
  13.     private static int interval = 5 * 60000;
  14.     

  15.     public static void StartGlobalTimer()
  16.     {
  17.             if (null == timer)
  18.             {
  19.                 SessionChecker.CreatSessionDictionary();
  20.                 timer = new Timer(new TimerCallback(DropUsers), HttpContext.Current, 0, interval);
  21.  
  22.             }
  23.     }
  24.    
  25.     private static void DropUsers(object sender)
  26.     {
  27.         HttpContext context = (HttpContext)sender;
  28.         var dict = HttpRuntime.Cache["UsersCountSession"] as Dictionary<int, DateTime>;
  29.         if (dict != null)
  30.         {
  31.             if (dict.Count > 0)
  32.             {
  33.  
  34.                 try
  35.                 {
  36.                     var q = (from p in dict.AsQueryable()
  37.                              where (DateTime.Now - p.Value).Minutes >= 25
  38.                              select p).ToList();
  39.                     if (q.Count > 20)
  40.                     {
  41.                         q.ForEach(p => dict.Remove(p.Key));
  42.                         HttpRuntime.Cache["UsersCountSession"] = dict;
  43.                     }
  44.                 }
  45.                 catch (Exception ex)
  46.                 {
  47.                     EventLog.WriteEntry("Application", "exception at DropUsers: " + ex.Message, EventLogEntryType.Error);
  48.                 }
  49.             }
  50.         }
  51.         else
  52.             SessionChecker.CreatSessionDictionary(); // for some resone if the cache is not filled.
  53.     }
  54.  
  55.     #region IDisposable Members
  56.  
  57.     public void Dispose()
  58.     {
  59.         timer = null;
  60.     }
  61.  
  62.     #endregion
  63.  
  64. }

 

 

 

 

  • add this line to your global.asax at the application_start method
    Code Snippet
    1. void Application_Start(object sender, EventArgs e)
    2. {
    3.     GlobalTimer.StartGlobalTimer();
    4.  
    5. }

    in is way the timer will be started once as soon as the application start to work and well never stop!. Please read for more information about timer exceptions and IIS recycle.
  • Now the DropUsers method that is hooked with the timer tick event do this;
    checks if the cache is not null and the dictionary user count is bigger then 0, after that make a select statement to collect the users that datetime period is bigger then 25 minutes (which means that user did not navigate any page for more then 25 minutes).
  • after collecting inactive users; we drop them from the dictionary and reinsert dictionary to cache.
  • any exception could happen inside this process will be logged to event log.
  • call sessionchecker.GetOnlineUsersCount() to get the online user count any time you like.

 

Hereby this tutorial i tried to explain how to count users if you are using Session state server. I know that there is many ways to do that. This example is working very fine on an enterprise website which has more then 23000 users and more then 65000 daily logins.

Hope this helps

my twitter address changed: http://twitter.com/MuhanadY

My Twitter Link Changed

 http://twitter.com/MuhanadY

English / Turkish / Arabic

Learning doesn't stop at 22

 

A great blog article by Dave Winer just want to share it :D

Learning doesn't stop at 22

Parent – Child in recursive data table with LINQ

If you have a data table which looks like this one below and holds child,parent rows at the same table;

ID ParentID Name
guid1 null parent 1
guid2 guid1 child for parent 1
so on so on so on

and you wont to retrieve all records from the table in a table looks like below;

Parent Childs
parent 1 child 1 for parent 1
child 2 for parent 1
child 3 for parent 1
….
Parent 2 child 1 for parent 2
child 2 for parent 2
….

This means that i have to make a recursive query in Sql to retrieve it this way. but with LINQ its more easy to be done, see the query below;

   1:  var q=  from p in TypedDataTable
   2:      where p.ParentID == null  // well get all parents
   3:      select new 
   4:       {
   5:             ParentID = p.ParentID,
   6:            child =  from c in TypedDataTable 
   7:                      where c.ParentID == p.ID select
                           new {ChildID=c.ID,
   8:                          ParentID = c.ParentID}
   9:      };
  10:          

and by the query above you’ll get this result;

linqParentChild 

 NOTICE : this query will load one level at a time

hope this helps

Posted: Nov 07 2009, 04:19 PM by mohi88 | with 8 comment(s)
Filed under: ,
Using 2 Tables Joined with LINQ as data source without anonymous cast error in databond method

Yesterday one of our project team member faced a challenge of using an anonymous data that is returned from joining 2 typed data tables with LINQ. The problem is not how to use the data, the problem was how to be able to cast and use the data in Repeater ItemDataBond method without having “<>f__AnonymousType0….” cast error. below is the join query (tables used are typed) :-

   1:PagedDataSource objPDS = new PagedDataSource();
   2:objPDS.AllowPaging = true;
   3:objPDS.PageSize = 10;
   4:   
   5:objPDS.DataSource = (from p in Table1
   6:                join  d in Table2 on p.ID equals d.ID
   7:                               select new
   8:                               {   
   9:                                   p,
  10:                                   F1= d.f1,
  11:                                   F2= d.f2,
  12:                                   F3= d.f3,
  13:                                   F4= d.f4,
  14:                                 }).ToList();

The code above will return rows with anonymous type that will include fields wanted for table2 and all table1 fields!.
NOTACE : to bind this data to repeater use <%# Eval("F1”) %> for Table2 fields and <%# Eval("p.FieldName”) %> for Table1 Fields.

Now what will happen if we want to use the datarow data bonded to repeater row! the code below will show you that you can not cast that datasource in ItemDataBond method as DataRowView :-

   1:  var bindedRow= e.Item.DataItem as DataRowView; 
   2:  //bindedRow return null value

So how to use a value inside the bonded row! after some researches I found out that reflection must be used to take that value from e.Item.DataItem with anonymous data. Reflection can be done by using DataBind.Eval which will evaluate data at run time. A label added to repeater and we want to bond some data at itemdatabond time, the code below will demonstrate that :- (Sorry for using multiline in code)

   1:  label1.Text = Table3.
   2:  Where(cid => cid.ID == 
           (Guid)DataBinder.
Eval(e.Item.DataItem, "p.FieldName")).
   3:  First().ToString();

DataBind.Eval Done the trick for you and retrieve wonted data from the anonymous type and casting it to needed type (here its guid).

Hope this Helps

Posted: Nov 04 2009, 10:19 AM by mohi88 | with no comments
Filed under: , , ,
Where with dynamic parameter (linq)

Yesterday i faced a satiation that i need to make a search in a datatable with dynamic parameter ( i mean parameters that may change - not the type of the parameter –). So i had this table below

ID                   appID               condition
---------           ---------             ------------
1                       A                          25
2                       A                          35
3                       D                          35
4                       C                          25
5                       D                          45
6                       A                          15

 

and i was looking to do this
for example : i would like to know the applications that have conditions 15,25 and 35 so that will be A and C
or 45 , 25 and that will be C and D.

and after some code refactoring i found the best way to code this is as below;

var appIDKeys= new List<Guid>();  
                   listOfConditions.ForEach(a =>  
                        {  
                            var q = (from p in MainTable  
                                     where p.ConditionKey== new Guid(a)  
                                     select p.AppID).ToList();  
                               if (q.Count > 0)  
                                     {  
                                        if (appIDKeys.Count == 0)  
                                            {  
                                              appIDKeys= q;  
                                            }  
                                 appIDKeys= appIDKeys.Intersect(q).ToList<Guid>();  
                            }  
                  else
                            { 
                               throw new ApplicationException("No Match");  
                            }  
                      });

 

Hope This helps

Posted: Oct 20 2009, 11:03 AM by mohi88 | with 7 comment(s) |
Filed under: ,
More Posts Next page »