What's hot ? (and I mean really ...) - scroll down for more
1).  Code Templating - advanced usage of delegates & generics: my slides & demos are available for download! CodeProject article is also available.

2).  My series "TDD in the eyes of a simpleminded" is in progress(including code!): preface, part1, part2, Q&A 1, Manual Stub .vs. Mock Stub

3).  TDD Workshop: SeeCompass v0.1 and v0.2 are out.
# Tuesday, October 25, 2005

Hey folks,

You can now receive my new posts directly to your email via FeedBlitz service!

All you have to do is click here and insert your email.

Posted by Oren Ellenbogen 
25/10/2005 09:08, Israel time UTC+02:00,     Comments [0]  | 
# Thursday, October 20, 2005

This task can be a little tricky, so after messing with it's HTC (TabStrip.htc) here is how you do it:

To enable tab:

document.all.tags("TabStrip")[0].getTab(0).setAttribute("disabled", false);

To disable tab:

document.all.tags("TabStrip")[0].getTab(0).setAttribute("disabled", true);

* You can select other tabs of course or loop over them to disable\enable all of them at once (as needed).

Maybe it can save someone else the time I've wasted on it.

Back to code...

Posted by Oren Ellenbogen 
20/10/2005 08:55, Israel time UTC+02:00,     Comments [3]  | 
# Monday, October 10, 2005

Our team use Microsoft's Membership Management Component Prototype for our users management in our application. We've wanted to add "forgot my password" screen, and our new member in our team, Dror(pay his blog a visit) was assigned for the mission. While trying to configure the MemberRoles component (in the web.config) to allow password retrieval, we've got a strange "bug"(\behavior); When we've tried to write this code:

<add name="AspNetSqlProvider" type="Microsoft.ScalableHosting.Security.SqlMembershipProvider, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562" connectionStringName="wsha" enablePasswordRetrieval="true" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false" minRequiredPasswordLength="1" minRequiredNonalphanumericCharacters="0" passwordFormat="Hashed" applicationName="test" description="Stores and retrieves membership data from the local Microsoft SQL Server database" />

We've got a strange error "Configuration Error" (with unknown exception and other "helpful" details), and to make it even stranger, if you set the enablePasswordRetrieval to false, everything works well. So, like always, the first thing I do after I smack the keyboard (It works on my TV at home, why not here ?), I googled for solution (and publish it here, for higher PR ;-)) BUT this time - NO LUCK, I didn't manage to find something helpful. I couldn't thought about a better solution than to look at the source via Lutz Reflector so I've opened the dll there and checked MemberShipConfigHandler.Create(..) method; There I saw that this method creates an instance of SqlMembershipProvider and call it's Initialize method with all the data from the web.config. There I found the answer:

if ((this.PasswordFormat == MembershipPasswordFormat.Hashed) && this.EnablePasswordRetrieval)
{
   throw new Exception("Configured settings are invalid: Hashed passwords can not be retrieved. 
       
Either set the password format to different type, or set supportsPasswordRetrieval to false.");
}

So, the error was that we've used passwordFormat="Hashed" instead of "Clear" or "Encrypted". Well, That's making a lot of sense because the "Hashed" algorithm is implemented via SHA1, which is one-way encryption so obviously I can't retrieve the user's original password.

The real problem(and that's why I've called this behavior a "bug") is that somewhere in the way, the original helpful exception was caught and replaced with a really bad exception which doesn't allow the programmer to understand what have he done wrong. This is a very good example of why it's so important to keep the exception stack with you all the way up.

Back to code...

Posted by Oren Ellenbogen 
10/10/2005 02:10, Israel time UTC+02:00,     Comments [0]  | 
# Saturday, October 08, 2005

If you haven't seen this before, pay this link a visit;
It contains a list of useful things you can use via google search engine in order to optimize your searches.
Posted by Oren Ellenbogen 
08/10/2005 01:06, Israel time UTC+02:00,     Comments [1]  | 
# Friday, October 07, 2005

I've just landed this morning in our too-big-too-much-to-walk Ben-Gurion airport from my one week vacation at the beautiful Paris. To be honest, I really needed this vacation, I had too much on my mind during the last couple of months - University planning, work (and lots of it) and some universal (we called it "in-romo-shel-olam" in Hebrew) decisions to think about like my near future goals which I love to think about every new year. Meeting my great family, having some 20 folks dinner with amazing food and lots of good wine can do wonders to your mind and body so I come back with some new powers which I'm sure I'll need in order to progress during this new year.

I picked some insights during this week, some of them I would like to share with you -

Controlling the arm rest in the airplane as a life story.
On my way back, I flew with Arkia Boeing 757, meaning 3 seats in each side of the airplane; Guess what, I had to sit in the middle, between my father and another problematic guy. Why problematic ? I knew you'll ask it, well that's because he always tried to take over my arm rest and kept me awake for 4 damn hours and 5 minutes ! You can't blame me that I haven't tried, I tried to push, to take only the bottom side of the arm rest, only the upper side of the arm rest, to stretch while trying to take over, EVERYTHING ! this guy was persistent ! Well, I'm sometimes more stubborn than necessary, but I saw that this battle wasn't for me to win so I took the battle into a field I knew I can win - the arm rest near my dad. Don't give me that poor smile and nodding, if you try to move the man while he's a sleep, you must come with some heavy armor. The problem was that he was sleeping(\reading, he turned the pages in his book every 2-10 minutes) and I didn't want to move his hand. But... every child knows his parents' weak points and in my father's case it's me. Moving a little bit in my chair and showing him I'm a little bit tired (=unhappy) gave us both a great idea. In a sweep move, my father asked the fellow beside me to get up as he needed to go to the toilet. I had to get up too, but it's LIFO(last in, first out) style, so I had the position before him; Man, I love good tactics. So after 4 hours and 5 minutes, we had left only 10 minutes in the air so my trick was a little bit useless and I couldn't sleep at all, but I think I've learned a lot from it, don't you ?

Arm rests should come in couples for the chair in the middle in 3 sits airplanes.
See the section above. I think I should write a patent on this one, this is gold.

Take yourself some time to think about your goals in the near future, new year holiday is good time IMHO.
This year will be an important year for me, like any other year in our short life but maybe just a little bit more. This year I hope to start on the right foot (and hand, for that manner) my academic course and to step up in my work. In addition I'm planing to release a mini "product" out to the world and to see(and learn) how it goes. Well, you're all familiar with those subjects (work, studies) but they are too big to think over without decomposing them into more feasible tasks. I started my thinking during the vacation and I promised myself to finish up (and "refactor") during the next week.  So, I tried to decompose my "I want to improve at my work" task into smaller tasks like (just a small part from my tasks list):

  1. I want to improve my management skills
    1. I want to learn some time-management tools (so I'll be able to complete the next section).
    2. I want to build my teammates schedules.
    3. I want to follow it with them so I would be able to understand better where do they "waste" time so I can avoid it or think about ways to improve it. I want to be able to detect good progress and good work so I could praise them and make sure that this good phases(\methods) will be longer on their next assignments.
    4. I want to be able to teach my teammates - I really believe that good workers(and human beings for that manner) are those that aren't afraid to say that they want to learn new things every day even if that means they'll have to change their work every X years. I want to be able to teach my teammates a thing or two, direct them to other resources so they'll be able to learn, or any other media so they'll be happy to come to work every morning.
  2. I want to be taught - I'm trying to be a good worker, so section 1.4 must apply to me also. In order to do that I must think about ways to learn and set my mind about the subjects that interesting me; Finally, I have to sit with the people in my company(or surroundings) which I think has the capabilities to teach me and think how can I convince them that teaching me will be beneficial for them as well.
  3. I want to improve my software analyzing capabilities - I want to think and participate in the design of 2 huge softwares we're about the develop.
  4. I want to improve my selling skills - I'm thinking about releasing a small software with a friend of mine and in the last couple of days I'm thinking more and more if to release it as open-source or maybe trying to sell it as a product. I want to insert new technologies(.net 2, sql server 2005 and more) to my company, I must figure a good plan in order to do this smoothly and to justify any changes in our development phases so the management could be relaxed and fully understand why this changes will result "win-win" situation.
  5. I want to finish this year university courses with good success (85+ avg.) - The degree is important and I don't want to let it go just because I'm working, and I can plan my time better so I would be able to work and study at the same time without neglected any one of them, it's up to me, like always.
This is just the tip of the iceberg from my original list, but I think you get the idea. I'm planing to build this kind of list in my office so my teammates would be able to tell me their work expectations for this year and I would be able to think about ways which I can help them to achieve it.

Don't be afraid to let the world know - "I want" to do this, this and that !
Almost all the people I know want to be rich for many well known reasons. The problem in my opinion is not the "rich dad, poor dad" issues of "we're been taught to be humble about our desires, to be satisfied with our average paycheck" etc. It's the lack of preparation from our side that keeps us from being successful. One of the biggest sections in my list is how to learn more about the subjects which will able me to add just a little bit to my regular work paycheck and how can I use the industry I understand the "best" (computers) for making me more money. Being "rich" can be comprehend also as being smarter or becoming a better person, It's all depends on the list you're making. Keep this list updated, this is the hard trick you'll have to master; This will able you to monitor your progression and find new dreams. I have an uncle that good planing and a lot of self confidence got him the job of the president of a universal company and a lot of wealth for his good investments. He was never sorry for demanding more, and this is a lesson I will not forget. The bottom line is, be the best you can be, just be smart about it as we're not living alone and I DO think that being a good person is much more important than being successful, I just say you CAN be BOTH.


I would finish with happy new (Hebrew) year to all of you, may you get a little closer to fulfilling your dreams.
SHANA TOVA !

Posted by Oren Ellenbogen 
07/10/2005 10:55, Israel time UTC+02:00,     Comments [2]  | 
# Wednesday, September 21, 2005

Remember my last post on this subject ?
Just to refresh your memory, I've come across a strange Visual Studio .NET (2003) + Visual Source Safe (6.0d) problem:
I got "The operation could not be completed" alert every time I've closed my solution. Man, It was frustrating, but I think I have a solution for it if you're using the same versioning mechanism I'm using and that is - "Link File" between your Class Libraries. It seems that the "Link File" option mess the solution\VSS\projects up for some unknown and undebuggalbe(is that a word? no ah..., well, it is now) reason.

The solution is quite simple, remove the linked file and put it in each of your class libraries. I know, I hate this solution too, but at least it will keep the sanity of your solution which is much more important than "1 place"(except asp.net 1.1 project, which don't support "Like File" option) version holder.

Now I'm "The operation could not be completed" FREE !

.NET | VSS
Posted by Oren Ellenbogen 
21/09/2005 02:39, Israel time UTC+03:00,     Comments [2]  | 
# Sunday, September 18, 2005

I'm not a happy coder right now.
I gave Eran, a new gifted programmer in my department, a task:

I have a simple table in my database, named Users, with the fields ID (int, identity) and Name(varchar).
I want to send xml to a web-service which looks like this:
<User>
    <ID>1</ID>
    <Name>Oren</Name>
</User>

I want the web-service to add this row to the Users table in some magic way. I thought that by using Typed DataSet, which will use the table's schema, and loading the xml into it will do the trick, but I was wrong. We tried many things but they didn't seem to work.

The reason I want to use schema is to verify the given data(xml) structure before I insert it to the DB (and of course, without it how the DS(DataSet) will "know" to load it properly?). In addition, if tomorrow I need to add Password field to Users table, the only thing I'll have to do is to re-generate the Typed DataSet and set the password via the xml (<Password>mypassword</Password>).

The code looks like this:

string sXml = "<User><Id>1</Id><Name>Oren</Name></User>";
using (SqlDataAdapter adapter = new SqlDataAdapter("", connString))
{
    UsersDS ds = new UsersDS();

    System.IO.StringReader xmlSR = new System.IO.StringReader(sXml);

    ds.ReadXml(xmlSR, XmlReadMode.ReadSchema);
    ds.ReadXmlSchema(HttpContext.Current.Server.MapPath (".") + "\\UsersDS.xsd");

    adapter.Update(ds.Tables["Users"]);
}

For some reason my ds isn't getting filled.

Do you have any idea what am I doing wrong ?

btw - I know I can always parse the xml by myself and create the required commands, but I thought it will be a maintenance nightmare and less comfortable than letting the schema & the Typed DataSet doing the job for me.

Update [20.09.2005]:

Amir Markowitz, again, came to the rescue and with his help we've managed to solve this one:

using (SqlDataAdapter adapter = new SqlDataAdapter("SELECT * FROM Users", connString))
{
   SqlCommandBuilder scb = new SqlCommandBuilder (adapter) ;
   UsersDS ds = new UsersDS();
                    
   XmlTextReader reader = new XmlTextReader(new StringReader(sXml));

   ds.ReadXml(reader);
   ds.ReadXmlSchema(HttpContext.Current.Server.MapPath (".") + "\\UsersDS.xsd");

   adapter.Update(ds.Tables["Users"]);
}

Now, the xml data (in "sXml" variable) looks like this:

<UsersDS xmlns="http://tempuri.org/UsersDS.xsd">
    <Users>
        <UserName>Orenn</UserName>
        <Name>Oren E.</Name>
    </Users>
</UsersDS>

So thanks again Markowitz, I owe you one (again, add it to my list).

Posted by Oren Ellenbogen 
18/09/2005 07:06, Israel time UTC+03:00,     Comments [0]  | 
# Saturday, September 17, 2005

I'm responsible for an hybrid ASP-ASP.NET application with an ASP log-in screen; This screen authenticate the user and set a unique session value in case he's valid. All the other ASP screens check this unique session value and let the user stay in the system as long as it exists. The problem was that there were ASP.NET pages that I had to use this security mechanism in them, meaning to check the session in my .aspx files in the same pattern (same unique session) as the other .asp pages did. In order to do that I had to access the ASP session from my ASP.NET pages, which is impossible due to the simple fact that they DO NOT share the same "room" (teenagers problems, you know). The solution came after googling a little bit and testing the suggested solution on my application.

The pattern goes like this:

aspToaspnet.gif

Once again, I'm a happy camper.

Posted by Oren Ellenbogen 
17/09/2005 02:53, Israel time UTC+03:00,     Comments [0]  | 
# Tuesday, September 13, 2005

I've encounter a numerous bad usages of try, catch and throw statements in my last 3 years in .NET so I thought to write here my "best practices" in this subject.

Before I begin, just to remind you about the "using" keyword

" The using statement defines a scope at the end of which an object will be disposed. " (MSDN)

Meaning, this code:

using (MyDisposableObject o = new MyDisposableObject())
{
   // use o...
}

Is equal to:

MyDisposableObject o;
try
{
   o = new MyDisposableObject();
   // use o...
}
finally
{
   // Don't forget, MyDisposableObject must implement IDisposable
   o.Dispose();
}

The using statement is much more "cleaner" than the try-finally(->call Dispose) block. Of course, in order to use the using statement, MyDisposableObject must implement IDisposable interface, but most of the .NET frameworks' classes which use external resources do, so no problem here.

When do I use the using keyword instead of "try-catch(-finally)" ?

In any case your code block doesn't required any exception handling (catch) and you're using a disposable object.
 
When do I catch an exception ?
 
You should use the catch statement only if you can REALLY handle the exception - meaning you want\need to "eat"(catch it and do nothing about it) the exception or you (want to)\can try to "fix" the application's flow according the exception type (call transactionInstance.Rollback() in my data-access-layer if an error occurred, for example).
 
Do NOT catch exceptions as a "default" behavior in your code !
The following code is a BAD practice in exception handling:

try
{
   //some code
}
catch(Exception e)
{
   throw new Exception("X operation error: " + e.Message);
}
finally // if exists.
{
   //some code
}

Why is it bad ? The catch statement doesn't handling the original exception, it creates a (bad)new one which means:
  1. The Stack Trace of the original exception will be LOST, which means I lose the ability to view the entire "process" (who called to who flow).
  2. In the demonstrated code, I catch an exception and re-throwing a pointless new exception. Throwing exceptions is an expensive task so you should avoid (at any cost) throwing them as long as you don't really need to !
  3. If you wrap an exception, at least save the original exception in the InnerException property (I'll elaborate later on).
When do I wrap an exception, when do I rethrow it ?
  1. You should catch and wrap the exception with a new one only if you can add INFORMATIVE data to the original exception which WILL be used later on. Writing this type of code (in my DAL) will be a smart idea usually:

    SqlTransaction trans;
    SqlConnection conn = null;
    try
    {
        // use the connection to do some DB operation
        
        trans.Commit();
    }
    catch(Exception e)
    {
        if (trans != null)
            trans.Rollback();
        
        // Wrap the exception with DALException
        // I can check if e is SqlException and by the e.Number -
        // Set a "clean"(show to user) message to the DALException.
        // I can add the full "sql" exception in some custom property, 
        // I can determine which stored procedure went wrong, 
        // I can determine the line number (and so on).

        throw new DALException("clean message to the user", e);
    }
    finally
    {
        if ( conn != null && conn.State == ConnectionState.Open )
            conn.Close();
    }

    Why is this code smart ? Because I call the Rollback() in case of an error, which will ensure "clean" database. Because it "hides" the original SqlException which allows me, at my Business Layer, to catch a generic DALException which will abstract the Business Layer from the Data Access Layer. Because I CAN add more informative data to the exception so the Business Layer could send the GUI (to show the user).

  2. You should rethrow the exception if you catch-ed it but you "found out" that you can't really handle it:
    try
    {
        // do some code...
    }
    catch(Exception e)
    {
        if (e is SqlException)
        {
            // Add more information about the exception and
            // throw a new, more informative, exception:
            throw new DALException ("more data", e);
        }
        else
        {
            // I can't handle it really, so I'm not even going to try
            throw; // <-- look at this syntax ! I'll explain later on
        }    
    }
     
    Calling throw; will bubble the original exception (including its' Stack Trace) - this will actually "cancel" the catch statement.
When you wrap an exception, you should *almost* always use the "InnerException" property
 
When you wrap an exception, you should save the original exception as InnerException:

try
{
}
catch(Exception e)
{
   throw new MyCustomException("custom data", e);

   // OR

   MyCustomException mce = new MyCustomException("custom data");
   mce.InnerException = e;
}

This will preserve the original stack which will be important for later debugging.

 

Any Insights you want to share with me ?

Posted by Oren Ellenbogen 
13/09/2005 11:16, Israel time UTC+03:00,     Comments [2]  | 
# Sunday, September 11, 2005

Searching Oren Ellenbogen in Google placed me on the third(3rd!) place !
It's a huge progress if you keep in mind that just last week I was at the 15th place (second page, at the middle)...

update [14.09.2005]:

I'm at the first place now ! Respect !

Posted by Oren Ellenbogen 
11/09/2005 12:36, Israel time UTC+03:00,     Comments [1]  |