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.
# Friday, August 12, 2005

Hey happy coders,
 
I'm currently developing a "2-weeks-max" application for an Israeli bank (If you see "Israeli bank" instead of the name of the bank, you don't have sufficient privileges ;-)). The characterization was written and approved on the fly, without a deep understanding of the client's domain, i.e what are the other applications that the users use in his every day work ? are they look the same ? does he "MUST" have some features that his already used to in his other applications ?
Now I'm facing the harsh results.
 
I'll give you an example of "little-MUST-feature-that-can-come-back-and-bite-you". The user requested a screen which will have to following fields in it (and some others, but they're irrelevant now):
  1. Requester drop down list: show all the users from a specific group in the AD (active directory).
  2. A->B->C linked drop down list: 3  DDL (drop down list) which are connected meaning that when you select a different value in A DDL all the values in B&C DDLs must show all the children of A (changing B will change C values of course).
This looks like a trivial requests right? Well, you're right, if you look at this skeleton request it may appear trivial, but the key is to understand how to user expect to choose a value from those DDLs. In my case, the user likes to work with auto-complete drop down lists. Combining his auto-complete mechanism in this screen was NOT a trivial task at all. The client gave me his code, so it seems that I just have to integrate it in my code and Voila; BUT The code was written for ASP, so I had to wrap it in a custom web control, handle the viewstate of the control, and worst - his code didn't worked so well (client-side behavior) so I was required to adjust and fix it as well(black box component in my a$$).
 
The 2 weeks application is now estimated in 3 weeks, 50% more than the first estimation !
I'm expecting a good night 24:00-06:00 sleep at the office for the next 2 weeks, wish me luck !
 
Some lessons I've learned:
  1. Don't give a fast reply for hours estimation just to move along and get the development process running, it WILL hurt you later on.
  2. Always try to understand the solution domain as well as the client's domain. Ask him to show you other applications that he uses for his every day work, ask him if he wants the same GUI in his new application that you're going to develop for him. If he does, think about the amount of time you'll be needed in order to do that, do you need to use a specific "template" so the new application will look the same as his old ones (how are you going to integrate it with ease?), do you need to allow him some special features that his already used to (auto-complete drop down list)? do you need to support key combination (Ctrl+S will save his document) ? In a "clean"(without technical considerations) characterization it probably will not be shown, but you must consider it in the technical characterization(if you have one) and in your total hours estimation ! Don't forget that the user thinks that adding a new feature to the application is an easy task because he already saw those features in other applications he uses every day ("can't you simply copy it from here???") - you must remind him that it's not a trivial task, and allow him to choose if he wants to spend time on these features.
  3. "Milk" the client for information, write all the possible scenarios that the client expect the system to handle. What screen X will show when I login as Administrator, what it will show when I login as Technician, as Supervisor ? Don't start programming unless you have the answers for those client "trivial" scenarios, refactoring will be a bitch !
  4. update: just to clarify, I didn't write the characterization and neither was my PM (project manager), it was written by another co-worker a long time ago. This is a huge mistake IMHO, you must ask the implementors, if you're not one of them, for their opinion on the development process before you can give your hours estimation.
Any tips you can share with me ?
 
 
Posted by Oren Ellenbogen 
12/08/2005 01:20, Israel time UTC+03:00,     Comments [4]  | 
# Saturday, August 06, 2005

Damn, I read at Edward Jezierski's blog that for every X years at Microsoft they get a bowl with X pounds of M&M ! (Can it get any better than that ?)
 
So, Where do I sign in ?
Posted by Oren Ellenbogen 
06/08/2005 12:14, Israel time UTC+03:00,     Comments [0]  | 
# Wednesday, August 03, 2005

I saw a post in one of the forums I'm active at about "how to insert multiple rows to a table in the database".
The main goal in this scenario, and that's a rule of thumb in almost any database-operation, is to send a bulk of requests so they'll be send for execution in ONE roundtrip to the database.
 
I immediately thought to concatenate the insert requests via ";"(or using the "Bulk Insert" command) for Sql Server or using "BEGIN" + "END" for Oracle.
 
[SqlServer]
SqlConnection conn = new SqlConnection("your-connection-string");
string query = "insert into t1 ('value'); insert into t1 ('value2');";
SqlCommand cmd = new SqlCommand(query, conn);
cmd.ExecuteNonQuery();
 
[Oracle]
OracleConnection conn = new SqlConnection("your-connection-string");
string query = "BEGIN insert into t1 ('value'); insert into t1 ('value2'); END;";
OracleCommand cmd = new OracleCommand(query, conn);
cmd.ExecuteNonQuery();
 
Someone from the forum suggested that all we need to do is to create the required commands object (with the query inside) and wrap them with a transaction. His code looked like this:

using (SqlConnection oCon = new SqlConnection("ConnectionString"))
{
   oCon.Open();
   IDbTransaction transaction = oCon.BeginTransaction();

   try
   {
         string Commands[] = new string[] {"insert...", "insert..."};
         foreach (string sqlCommand in Commands)
         {
            SqlCommand oCom = new SqlCommand(sqlCommand, oCon, transaction);
            oCom.ExecuteNonQuery();
         }

         transaction.Commit();
   }
   catch
   {
      transaction.Rollback();
   }
}

He claimed that the transaction object will simply collect the commands and only in transaction.Commit(); the request will be sent to the DB so only one roundtrip was performed.
Well, it didn't sound right to me, I knew that the transaction wraps the commands but I thought that every call to ExecuteNonQuery() will cause a roundtrip to the DB. But I wasn't absolutely sure so I've decided to check it out and I've built a simple tester:

// I've created Cities table (Sql Server) with the fields -
// 1. ID - int - PK & identity
// 2. Name - varchar(50) - Unique !
using (SqlConnection oCon = new SqlConnection("connString"))
{
   oCon.Open();
   SqlTransaction transaction = oCon.BeginTransaction();

   SqlCommand c1 = new SqlCommand("Insert into cities(name)values('oren_test1')", oCon, transaction);
   SqlCommand c2 = new SqlCommand("Insert into cities(name)values('oren_test1')", oCon, transaction); // this will throw an exception for duplicated row (Cities.Name is unique)
   SqlCommand[] commands = new SqlCommand[] {c1, c2};

   try
   {
      foreach (SqlCommand command in commands)
      {
         command.ExecuteNonQuery();
      }

      transaction.Commit();
   }
   catch(Exception err)
   {
      Console.WriteLine("error: {0}, rollback.", err.Message);

      transaction.Rollback(); 
   }
}//using will close the connection even in case of exception.

As you can see for yourself(try it), the second ExecuteNonQuery (for the second insert) throw me an exception about the duplicated row (unique exception) so now I'm sure that the roundtrips are NOT "saved" by wrapping the command with a transaction. It's making a lot of sense, the DB opens a transaction while calling the BeginTransaction() method and keeping it open until we call the Commit() or Rollback() methods. In between, while calling the ExecuteNonQuery() method, the database saves the row in a temporary table just until the the transaction ends (again, via Commit() or Rollback()) and only then the rows are inserted to the "real" table (i.e Cities table).

Conclusion

One of your main concerns while developing a web application is to prevent redundant roundtrips from your application server to the database server.

While the transaction object is vital for data integrity while inserting\updating\deleting many(more than 1) rows and it can boost your request(Trying to insert 1000 rows to the table, each insert with it's own private transaction, will be much slower than calling the same insert with one transaction for the all 1000 rows), it doesn't mean that it's wrapping your calls to the DB and saves those redundant roundtrips.

And if I wasn't clear so far - You should use the first approach showed in this post.

p.s -
General tip: (need I to say?) Always check your theories before you running along and using them in your applications.

Posted by Oren Ellenbogen 
03/08/2005 08:25, Israel time UTC+03:00,     Comments [2]  | 
# Saturday, July 30, 2005

Why do we(my bad, I) need code generator ?
I really don't want to get into this philosophical argument, whether code generation is good or not, but just think of your Code Generator as a silent programmer which REALLY loves to do your dirty repetitive work. Please read the following with an open mind to the subject, you've got nothing to lose.
 
Background
Way back, When I was still serving my country, I was "introduced" to the world of Code Generation. The concept was well familiar to me, but I didn't saw a tangible implementation until my team leader at the time, Pavel Bitz, showed us his(great) implementation which later on became the first code generator (aka "CG") I ever used. This CG was written in PL/SQL and ran, obviously, on our Oracle (9i) database. I wasn't so happy about the extendability of this code, but we were in a tremendous stress to develop & deploy our projects so there was no time to develop something "cleaner"(in my opinion anyway). After few weeks, at my final days in the army, I was starting to build my own code generator just to understand more of the .NET framework power - i.e usage of templates, custom config files, Database reverse-engineering, reflection, practicing my OOD\OOP etc. After all, nothing teaches you better to "exploit" the framework than writing an application which will test its capabilities. After 2 weeks I had a nice CG which ran quite well and did everything the PL/SQL CG did and then some.
My time at the army was done and I was back in the free market.

2 days after I was employed for SQLink company, I talked with Amir Engel about the idea of code generation. He told me that he managed to write some templates with CodeSmith and he showed them to me. It looked great but I was hoping to use my CG for that purpose, still, I wanted to protect my "baby". But this desire was gone when I read about CodeSmith's SchemaExplorer. My god, I was shocked about how easy it is to write a template which will connect to my database with zero (0 !) effort. In addition, it has its own Studio which allows me to write,test and debug my templates with ease.
BUT the biggest advantage was that there were many open source templates out there - just for me to use !
 
Code Generation - safety first
Before you start to generate code, you must think about how to integrate the code generation usage in your every day work without the need to overwrite your "custom" writing. I'll give you an example - Let's say that we generate the Data Access Object for Users table in our database. This object does the CRUD (Create\Insert, Read, Update, Delete) operations for that table. Now I need to add a "specific" method named "GetUsersFromCity" which will return all the users from a given city id. So I'll add the method to my UsersDAL class and I'm an happy programmer no ?   (think here...)  NO!
Why not ? because the next time I'll want to generate this class again, because one of the fields in the table was changed or a new field was added to the table (whatever), I don't want to overwrite the class and lose my custom changes !
The "Base" principle:
This is where the "Base" principle kicks in and help us to protect our custom changes. My correct "DAL" object class structure will be:

// File: UsersDALBase.cs
public class UsersDALBase
{
    // our "generated" code here - all the CRUD operations for example.
}

// in another file!
// File: UsersDAL.cs
public class UsersDAL : UsersDALBase
{
    // My custom behivors here.
}

Every time I'll regenerate the code, I'll overwrite the "Base" file and no harm done - my custom changes are safe !
In my "upper" layers, I always use UsersDAL(or [table]DAL for that manner) and not UsersDALBase.

Now that we've got the background, it's time to introduce to you my amigo -

CodeSmith - harness its power for your own need

I'm not going to write here about how to use CodeSmith, there is too much information about this issue all over the web - just google a little and I'm sure you'll do just fine. What I'm going to talked about is what's the greatness of CodeSmith and my tips about easy development and debugging while using this tool.
 
  • SchemaExplorer - Stop doing all the reverse engineering for Oracle\SqlServer (via "system tables"), it's already written for you. The only thing you need is to specify is the connection string and... thats it ! You want to see how easy it is? OK OK, relax:

      <%@ CodeTemplate Language="C#" TargetLanguage="C#"
        Src="../OeCodeTemplate.cs" Inherits="OrenEllenbogen.Templates.OeCodeTemplate"
        Debug="False" Description="Generate an entity class for a given table." %>

      <%@ Property Name="SourceTable" Type="SchemaExplorer.TableSchema" 
         Category="Connection" Description="Table Object should be based on." %>

      <%@ Assembly Name="SchemaExplorer" %>
      <%@ Import Namespace="SchemaExplorer" %>

      <%
      // Collection of all columns in the table.
      ColumnSchemaCollection Columns = new ColumnSchemaCollection(SourceTable.Columns); 
      %>

      <% 
      // Variables by table columns.
      for (int i=0; i < Columns.Count; i++) { %>
      /// <summary>
      /// <%=Columns[i].Name%><%=(Columns[i].Description.Length>0) ? " : " + Columns[i].Description : ""%>
      /// </summary>
      protected <%= GetCSType(Columns[i]) %> <%=VariableStyle(Columns[i].Name)%> = <%= GetCSDefaultByType(Columns[i]) %>;
      <% 
      } //end for 
      %>

         Some Explaining:
    • you can use "code behind" file (*.cs) which holds the common methods for all your templates files (mine is OeCodeTemplate.cs)
    • I use the methods GetCSType, VariableStyle and GetCSDefaultByType methods which are in my "code behind" file, but this are simple methods which you can copy\write by yourself.
         As you can see, it's so easy to start dealing with the template itself instead of trying to remember 
         how to get all the indexes\columns\primary keys\(etc)  from a given table.
  • Templates GUI - You've seen that I'm using SourceTable property on the previous section, the great thing about it is when I'll open this template with CodeSmith explorer I'll be able to pick the table directly from my DataSource. So easy and comfortable.
   CodeSmithExplorer.JPG   
 
 
  • Huge community - you can find a lot of examples in CodeSmith forums. Don't try to write something which was already written before you; You can always find a template and get some of its code for your specific need.
  • Its easy - believe me, my 4 years old cousin can write a template with CodeSmith, its that easy !
  • Its(was) free ! - version 2.6 is free for use, but the new one (3.0) costs (nothing you can't afford though).
Developing with CodeSmith
  • Using Lut'z reflector with CodeSmith 2.6 - The main problem with this version (and former) is the lack of IntelliSense. This is a problem due to the simple fact that you can't remember every method\member  in SchemaExplorer object for example which makes it harder for you to develop. The simple solution is to use the reflector over the SchemaExplorer.dll, which "sits" in CodeSmith directory, and explore your way to the required member\method.
  • Debugging - Debugging with CodeSmith 2.6 (and former)  isn't so comfortable, but it doable - that's enough for me. In order to do it, all you need to do is to put Debug="True" in the page header directive and call Debugger.Break(); before the lines you want to debug.

NOTE: in the new version (3.0), Eric .J. Smith, the creator of this great tool, spoiled us with brand new features like built-in IntelliSense and easier debugging options and much more.


Summarize:
Code generation, in my humble opinion, is MONEY SAVER, simple as that, you can cut down the development time by half !
I've built full-spectrum templates for my N-Tier applications - Entities (object which represent table), Data Access objects, Business Object, Web forms, Utilities layer, Cache layer and stored procedures script generator. I'm now able to build 50%-60% of the project "foundation" before I need to write my first code line ! In addition,  I'm using my CodeSmith templates for my every day work - I did some helper templates like generating new "SqlParameter" with the parameter type\size\scale according to the column type, This is great for adding a new SqlParameter to SqlCommand with "full information" about the parameter in single click.
And finally, I'm not afraid to change the database because I know what I need to change and now - it's even EASY to do.

 

Posted by Oren Ellenbogen 
30/07/2005 10:16, Israel time UTC+03:00,     Comments [0]  | 

As I've promised - I share with you my experience with NAnt while attempting to automate my build process for my ASP.NET project. After reading a lot on the subject, I must admit that the documentation is quite poor and the "open source" examples are not exactly what I'm looking for. Before I'll start, if you don't know what is NAnt or NAnt contrib, now will be a good time to do some reading, I'll wait...

Requirements (What do you need to install before you can start):

  1. Download and install NAnt.
  2. Add the nant\bin directory path to your PATH variable ("System Variables").
  3. Download and install NAnt contrib.
  4. Integrate between NAnt and NAnt contrib using these steps:
    1. Copy nant-contrib\bin\*.dll to nant\bin\ directory.
    2. Create the folder nant\bin\tasks\net (manually).
    3. Copy nant-contrib\bin\*.dll to nant\bin\taks\net directory.
  5. Download NAnt.UtilityTasks.dll and put it in nant\bin directory.

Let's Start:

OK, now we're ready to start the build process; So here is my solution structure:

MySolution
   - WebProject (ASP.NET project)
      - *AssemblyInfo.cs
      - Other files and directories (& porno, of course)
   - BusinessLayer (Class Library)
   - DataAccessLayer (Class Library)
   - EntitiesLayer (Class Library)
   - *SolutionInfo.cs
  - etc..

* Before I continue about the process itself, I must mention that I'm using "Link File" option in order to share my AssemblyVersion attribute in my ClassLibraries projects. In a perfect world, ASP.NET projects would be able to "Link File" as well, but (surprisingly) it's not; So I have 2 places which hold the AssemblyVersion:
1. MySolution\SolutionInfo.cs (This file is being linked in all of my class libraries).
2. MySolution\WebProject\AssemblyInfo.cs.

Great, we can carry on -
I've discussed about the proper build process with my friends A&A (The Amir's aka "The markowitz" and "The Engel") and we've agreed that we require 2 processes - "Build"(complete new version) and "Rebuild"(rebuild the current version, it's required after the Build process failed for some reason).

The desired processes work flow
:
Note: you don't need to copycat my process, you're a free human being, consider me as your Build mentor :-o

1. "Build" process -
   1.1 Increment my build version (SolutionInfo.cs & AssemblyInfo.cs)
         In order to do that, I'm using a great code snippet I found during my last weekend searches to 
         create a new version number. Afterwards, I'm checking-out the SolutionInfo.cs file and imprint the 
         new AssemblyVersion using <asminfo> task.
         Eventually I'm checking-in the SolutionInfo.cs file.

         * I'm using some properties - ${property_name} - for easy maintenance, you can see it in the 
            file I've upload (way over down).

   <vsscheckout username="${vss.username}" password="${vss.password}" 
      localpath="${slndir}" recursive="false" writable="true" dbpath="${vss.dbpath}" 
      path="${vss.slnpath}/SolutionInfo.cs" failonerror="true" />

   <asminfo output="${slndir}\SolutionInfo.cs" language="CSharp">
      <imports>
         <import namespace="System" />
         <import namespace="System.Reflection"/>
         <import namespace="System.Runtime.CompilerServices"/>
      </imports>
      <attributes>
         <attribute type="AssemblyVersionAttribute" value="${build.version}" />
         <attribute type="AssemblyCompanyAttribute" value="${company}" />
         <attribute type="AssemblyProductAttribute" value="${product}" />
         <attribute type="AssemblyCopyrightAttribute" value="Copyright (c) 2005, ${company}." />
         <attribute type="AssemblyTrademarkAttribute" value="Trademark by ${company}" />
         <attribute type="AssemblyDelaySignAttribute" value="false" />
         <attribute type="AssemblyKeyFileAttribute" value="..//..//..//key.snk" />
         <attribute type="AssemblyKeyNameAttribute" value="" />
      </attributes>
   </asminfo>

   <vsscheckin username="${vss.username}" password="${vss.password}" 
      localpath="${slndir}\SolutionInfo.cs" recursive="false" writable="true" 
      dbpath="${vss.dbpath}" path="${vss.slnpath}/SolutionInfo.cs"
      comment="change build version: ${build.version}" />

         I use the same code (with minor changes) to update my AssemblyInfo.cs file as well.

   1.2 Put a label on the VSS with the current new version.
         This is even easier, I just use <vsslabel>(NAnt contrib) task:

      <vsslabel
           username="${vss.username}"
           password="${vss.password}"
           dbpath="${vss.dbpath}"
           path="${vss.slnpath}"
           comment="New build version: ${build.version}"
           label="${build.version}"
      />

   1.3 Get the files from the VSS to my local directory recursively using <vssget>(NAnt contrib) task.
      <vssget
           username="${vss.username}"
           password="${vss.password}"
           localpath="${vss.outdir}"
           recursive="true"
           replace="true"
           writable="false"
           dbpath="${vss.dbpath}"
           path="${vss.slnpath}"
      />

   1.4 If I'm required to (by property) - generate the projects pdb's.
        This is great for release mode, I can pull the pdb's for the version at the Production environment 
        and make some extreme production debugging using the pdb's as symbols - 
        I must give the credit to "The markowitz" for the idea !
      

        The code is quite simple - build the solution in Debug mode and copy the *.pdb files
        to my "version_directory"\pdb\WebProject.
        You can see the code in the attached file.

   1.5 Build the solution.
         I'm using <solution> task and <webmap> for easy build.
         Again, nothing fancy, look in the attached file.

   1.6 Copy the web project output to my MySolution\Builds\[version_number] directory for 
        an easy XCOPY deployment. I'm using <copywebproject> task in order to do 
        this magic, it's working like a charm.  
   <copywebproject project="${slndir}\WebApp\WebApp.csproj" 
      todir="${outdir}\WebApp" configuration="${config}" />

   
2. "Rebuild" process - 
      Call steps 1.3 to 1.6.

TIPS:
I recommend that you'll download VSTweak and let the VS.NET treat your .build file as .xml file.

TODO:
I'm going to add a NAnt task which will get all the *.js\*.htc files from the web project (.csproj) and format them
via Jazmin - this will cut down the size of the files(by removing comments and other not-required characters) for performance improvement (the smaller the file is, the faster the client will download it).

CREDIT:
If you're using my file as your "template", I would appreciate if you'll add a comment and let me know about it, including new features you've added or planning to add. I've dedicated my time to share with you, please do the same grace with me. Thanks !

My (template) build file:
default.zip (3 KB)

How to run the build file ?
You'll need to configure the default.build file I've attached (5 minutes max).
Go to your solution directory and copy the "default.build" file into it.
Now, activate "cmd" and navigate to that directory.
Type "nant build" and Voila !

Posted by Oren Ellenbogen 
30/07/2005 01:04, Israel time UTC+03:00,     Comments [2]  | 
# Thursday, July 28, 2005

Hey folks,

I'm sure that all of you encountered this message at least once in your life as a programmer.
Well, I've managed to understand and fix one aspect(\scenario) of the beast:

In my project, I have a directory named "References" which holds all my compiled (in Release mode of course) Dlls which are being used as "black box" component (i.e file reference). Because of all these files are in the VSS and I put them as "Solution Items"(easier deployment), they downloaded to my computer as "Read-only" files. So at the first time the solution builds, no problem, The web project can copy those Dlls (they are not exist in his bin directory), afterwards it's working fine as well (later builds) because there are no changes to this Dlls so the VS.NET simply don't copy them again (like "he" don't compile the ClassLibrary if no changes were made, he's a smart fellow you know).

BUT, in my scenario, I've updated one of those "black box" Dll and I tried to rebuild my solution. You can understand from the title that I got this annoying message that it can't copy the Dll. After I've checked a little, I found out the problematic file in my webproject\bin directory is checked as read-only, So I've unchecked it, rebuild the solution and it worked faultlessly.

If found 2 solutions for this problem:

  1. Call attrib -r [path-to-web-project]\bin\*.dll on pre-build (Build Event) of any ClassLibrary project; I would've put it in my WebProject project but unfortunately it doesn't support Build Events (why MS, why ?)
  2. Go to your "References" directory and manualy set all the files to *NOT* Read-only.
.NET | VSS
Posted by Oren Ellenbogen 
28/07/2005 11:32, Israel time UTC+03:00,     Comments [5]  | 
# Wednesday, July 27, 2005

For some reason, every time I closed my (specific) solution from Visual Studio .NET (2003) the IDE throw an "The operation could not be completed" error. After I've tried to open another(different) solution in the same IDE instance, the solution was not bounded to the VSS !
I swear, this is a regular solution structure... nothing fancy;
After digging a little, and talking about it with Amir (aka "The Markowitz"), we've come to the conclusion that the solution (*.sln) file have problems with the VSS. It became obvious when I tried to add a file to the Solution Items and I simply couldn't check-in the new file.

I've start googling about "troubleshoot VS.NET log" but no luck, I can't seem to find a log file which will give me some more data about the "The operation could not be completed" error. I hate the "restart-your-computer" solutions style, but after I've spent 2 hours exploring the *.sln files, *.csproj files and tried to reproduce the problem on a different solution(tester), I was getting tired and frustrated.

As last resort, I've unbounded the all solution, deleted (permanently) the $/MyProject directory from the VSS and reattached the all solution to the VSS again using the recommended guideline.

Now everything is good, weird ah ?

.NET | VSS
Posted by Oren Ellenbogen 
27/07/2005 12:03, Israel time UTC+03:00,     Comments [5]  | 
# Tuesday, July 26, 2005

I'm working on my Code Generator so it will be able to generate stored procedures for me. Until now I generated the SQL queries in my C# code, but now, due to a development request(\demand) from my client I must work with stored procedures.

The first thing I thought about is how to make my search pages easy to upgrade and maintain if I'm going to use SP(stored procedure). Now, when I need to add another Field to my dynamic where clause, it's quite simple - I'm building the query in my data ccess object according to the parameters and everything is OK. I feared that by using SP for my search pages, I'll need to call something like EXEC which looks like a joke - If you must call EXEC in the SP, you better put the SQL in your C# code and get it over with.

After doing some searches, I found this article which present a way to build and execute dynamic where clauses with "COALESCE" function. After I've searched a little more, I found a similar way to do the same thing with better performance:

" I check the value against NULL and achieve good performance and flexibility. No problem with LIKE values either:

WHERE
(@title IS NULL OR title LIKE @title)
AND
(@min_release_date IS NULL OR release_date >= @min_release_date)
AND
(@document_id IS NULL or document_id = @document_id)

Great performance and flexibility! All indexes are used as expected. " (Zelk)

Looks great !
If the sent parameter is null, don't "cut" the results by the parameter, else - use it...

OK, I must dig into my generator and start implementing this... 

Posted by Oren Ellenbogen 
26/07/2005 05:13, Israel time UTC+03:00,     Comments [6]  | 

Sometimes my VS.NET just can't "catch" my breakpoints in my .js files for some reason.
Yes, I made sure that the "Script" box is checked on the attached process, still, no luck.

Fortunately debugger; command is in the house !

It's simple to use and it can be great for production debugging as well.

example (in myexample.js file):
function MyMethod()
{
   debugger; // ==> this will make the debugger to take over (you can use VS.NET or any other suitable program).   

   // your code to debug here.
}

Posted by Oren Ellenbogen 
26/07/2005 02:08, Israel time UTC+03:00,     Comments [1]  | 
# Monday, July 25, 2005

Damn, such a long title... I must take a minute to relax; Done -

I had to change the directory name of my Web project in order to ease my build process.
Well, I must admit, this isn't an easy task when you don't remember the steps or you're too
tired to messing around with it (rule of thumb: gather the required powers, it won't get easier to adjust it later you know).

So, from my experience here are the steps for changing the VSS bounded ASP.NET project
directory name without killing your VSS\Solution:

  1. Close the solution if it's open (i.e - close the Visual Studio .NET).
  2. Create the new directory name you want to address the ASP.NET project into.
  3. Go to the IIS (Ctrl + Q -> iis, oh wait, assuming you've followed my advice and installed SlickRun) and change the virtual directory path to point to the new directory.
  4. Open the *.sln file with notepad (right-click->open with...) and find "SccLocalPath[number]" which points to your current(unwanted) directory name; overwrite the directory name with the new directory name.
  5. Delete the *.suo file - NOTICE: this is a hidden file so you must check the option to view all the hidden files (OS configuration). This file keeps the user configuration about the solution (like what is my StartUp project\file etc.)
  6. Open the *.sln via VS.NET and you'll get a window which will ask you to choose the web project path (http://localhost/VirtualDirectoryName_1) - remove the "_1" suffix and click OK.
  7. Delete the old web project directory. TIP: if you're trying to delete the old web project directory and you'll get an error that there are files in use - try to delete VSWebCach directory (in your c:\Documents and Settings\[username]) and then try to delete the directory again.
  8. Drink something and relax, you deserve it !
.NET | VSS
Posted by Oren Ellenbogen 
25/07/2005 07:41, Israel time UTC+03:00,     Comments [1]  |