Thursday, July 31, 2008

Comparing Two Tables By SQL Stored Procedure

I have created a SQL Stored Procedure to compare any two tables based on Microsoft SQL Server 2005 new syntax EXCEPT and INTERCEPT. Basically, I used EXCEPT and UNION to get the result of differences between tables and INTERCEPT to get the same result of two tables.

In addition to that, the SP will compare two tables by specifying column fields and conditions and display the result by optional ORDER BY clause. Here is the SP:

CREATE procedure [dbo].[SP_CompareTables] (
@table1 varchar(100),
@table2 varchar(100),
@table_colList varchar(3000) = NULL,
@whereClause varchar(3000) = NULL,
@orderByClause varchar(3000) = NULL,
@difference0 int = 0
)
AS
DECLARE
@sql varchar(8000);
DECLARE @colList varchar(3000);
BEGIN
if
( @table_colList is null Or @table_colList = '' )
begin
set
@colList = '*';
end
else
begin
set
@colList = @table_colList;
end
if
( @difference0 = 0 )
begin
set
@sql =REPLACE(REPLACE(REPLACE('
SELECT ''@table1'' AS TblName, *
FROM (
SELECT @colList
FROM @table1
EXCEPT (
SELECT @colList
FROM @table2)
) x
UNION ALL
SELECT ''@table2'' AS TblName, *
FROM (
SELECT @colList
FROM @table2
EXCEPT (
SELECT @colList
FROM @table1)
) y'
,
'@table1', @table1),
'@table2', @table2),
'@colList', @colList);
end;
else
begin
set
@sql =REPLACE(REPLACE(REPLACE('
SELECT @colList
FROM @table1
INTERSECT (
SELECT @colList
FROM @table2)'
,
'@table1', @table1),
'@table2', @table2),
'@colList', @colList);
end;
if ( @whereClause is not null And len(@whereClause) > 0 )
begin
set
@sql = REPLACE(REPLACE('
SELECT * FROM (@sql) v
WHERE @whereClause'
,
'@sql', @sql),
'@whereClause', @whereClause);
end
if
( @orderByClause is not null And len(@orderByClause) > 0 )
begin
set
@sql = REPLACE(REPLACE('@sql
ORDER BY @orderByClause'
,
'@sql', @sql),
'@orderByClause', @orderByClause);
end;
print @sql;
exec(@sql);
return 0;
END


To use this SP is very simple. For example, to compare two tables of [Employees] and [Employees_backup], you can just run the following script to compare two whole tables:

EXEC SP_CompareTables 'Employees', 'Employees_backup';


More examples by specifying columns, where clause and order clause:

EXEC SP_CompareTables 'Employees', 'Employees_backup', 'FirstName, LastName';
EXEC SP_CompareTables 'Employees', 'Employees_backup', 'FirstName, LastName',
'FirstName like ''D%'' AND BirthDate Between ''Jan 01, 1990'' AND ''Jul 30, 2008''';
EXEC SP_CompareTables 'Employees', 'Employees_backup', 'FirstName, LastName',
NULL, 'FirstName, BirthDate' , 1; -- get same results

Read More...

Saturday, July 26, 2008

SQL Server Project (4)

I have to close this series articles on SQL Server Project. The final part will cover some special issues related to SQL Server Project.

The first issue is the connection to SQL server. As I mentioned in SQL Server Project (2), it is recommended to use the context connection since the CLR assembly is already in a SQL server running process. However, this connection can only be created once. You cannot create another context connection for other executions. Normally, you don't need another one in one stored procedure for example. However, if you create several SQL procedures, functions, and triggers in one dll, you might get exceptions if one calls another since only one context connection is allowed. You don't have control who is going to run these stored procedures, functions, or triggers.

Therefore, I think it is better to create one SQL item (SP, function or trigger) in one dll. You could create a normal SQL connection with catalog for a db table, user name, and password information in a connection string if you have to, and that connections can be created more than once. In a SQL server context, it does not make sense to do that unless you need to connect to another SQL server or Oracle server.

An related issue is that always to handle exceptions in your assembly and close any opened connections. As I mentioned before, the assembly is loaded to SQL server running process, and it would not unloaded automatically when your SP exits. The assembly may still in memory. If you don't handle exceptions, the opened connection will block the same SP being called again.

The second issue is that some assemblies may not work in SQL server project. I tried NHibernate and some other dlls as my references. What I found is that some assembly reflection functions are not working in SQL server. For example, I found that there always exceptions when these dlls try to load another assembly file to get class or property information. All these kind calls cause exceptions. This is very unfortunate and I think this is very bad limitation for SQL server project. I have no idea why and how exceptions would happen.

If you are going to write your SQL server project in C#, all the parameters in a SP have to be specified whey the SP is called, unlike MS Transact SQL SP could have default values for parameters.

The installation and deployment process for a SQL Server Project is a complicated one. As I mentioned in my previous articles, some asymmetric keys, log in permissions have to be created, and dependency assemblies have to be registered. The deployment of SQL server project is one click process if you have source codes and Visual Studio avalailbe. However, that click-only-once deployment may hide some SQL calls to register and set up all SPs, function and triggers. If you want to create an automation process in SQL, you have to keep all the assembly files available somewhere even they are not referenced after the installation and deployment. To uninstall it, the process is reverse. You have to remove all the SPs, functions, and triggers first, and then to delete assemblies, and then other dependency items. Since there are many things involved, anything wrong may cause your assembly not being functional.

I had a case that my CLR assembly SP did not work one day. It says about some permissions to load assembly failure. I tried to remove all the assembly and to re-install again, but I could not remove them as well. I was stuck in the middle. Finally I found it is the case SQL server was in low virtual memory. The error message actually was misleading. I restarted the SQL sever and reloaded files I did in the middle, then everything worked fine. Therefore, be prepared to handle all the uncertainties, document all the procedures in a well organized way and save all the source codes and dependency files in repository.

Read More...

Monday, June 09, 2008

SVN, Its Tools and Checkins

Subversion (SVN) is an open source version control system. I used it for source code control or repository. There are two open source SVN tools available for Windows and Visual Studio: TortoiseSVN and AnkhSVN.

Normally, I use Tortoise to check out source codes, a solution or project, to a folder and then it will create SVN client folders and files (hidden) to mark files as a copy out from a SVN reposity. Then, open the sln or project by VS. AnknSVN will detect this project is from SVN and prompt you AnkhSVN is available for use for the project.

If you make a change to a file, the file then is marked as a changed one with red icon. You can commit the change back to the SVN server or check in to the repository. Ankhn works well for editing files. However, it does not support file renaming. You have to remove the file and add a new one as two steps for renaming.

In many cases, I have to revert some changes or the whole changes by using Ankhn's context menu. Revert means no change to the file in local and re-copy the file from repository to local. In case of removing a file, you will be prompt to remove the file from the repository. If you choose Yes, this actually is commit or change to the repository! You cannot just revert the change to get it back. You have to revert to previous versions. If you have several check-ins in a day, it may be hard to find the correct one restored back. Therefore, if you want to make a trial change in local, do not remove the file from the repository. Then you can simply revert the local project back and use Update to refresh the local files if you do not want to commit the change.

If you removed file from local (not in the repository!), and verified the change is OK and want to commit you changes to the repository. Remember, the removed files are still in the repository after your check-in. Use Tortoise's repo-browser to open the repository and remove the file from the browser. That's another commit change to the repository.

In a sense, those SVN tools do not have a check out session, or SVN does not support check out set or locking a check out set. That means several developers can work on a same source code file at same time. Any developer can drop their change and that's fine for others. However, if one checks in the code file, others may have to merge their changes before check in. Ankh provides diff for comparing repository file to local files and will prompt, I think, you if your check out version has been changed by others.

Read More...

Wednesday, June 04, 2008

Add Colors to Codes

Today I did some change to my blog's template html page with some style sheet definitions from ASP.Net forums' colrcode.css.

To find the css file, you have to view its source codes and find link to css at the top of web page. There are several css files. To find the style definitions for programming codes, you can view the partial codes from the forum web page's program codes.

ASP.Net forums provide on-line posting editor with a tool bar to insert source codes with formatted HTML tags around programming source codes, such as C#, VB, SQL, XML, ASP.Net and others. That's why I choose ASP.Net forums' css. I can use its posting editor to get some formatted HTML codes and then post them to my blog. Since I use the same css file in my template, my source codes are marked with colors!

One color is missing in ASP.NET page: color for class, interface and intrinsic or predefined types. I added a new tag as classInterface in my template for these cases. You will see my example codes with colors!

Read More...

Calculate Number of Months from a Date

Here is a simple function to calculate number of months from a date to now:

public int NumberOfMonths(DateTime fromDate)
{
int months;
DateTime dt = DateTime.Now;
months = dt.Month + dt.Year * 12 -
(fromDate.Month + fromDate.Year * 12);
return months;
}


It is simple and no need to add any comments. However, when I first tried to google it, I found some very complex codes to get number of months and they are not right. Finally, based those codes, I figured out that the calculation is simple.

You may use this function twice to get difference between two dates.

One note about this function is that if the input date value is a future time, the number of months is a negative value.

Read More...

Friday, May 30, 2008

Tools and Utilities

Tools and utility programs are essential helpers for programming. I learned a lots of tools from web, blogs and other people. I remembered that when I was working at one SCADA company about 7 years ago. One developer showed me Total Commander tool with his passion. He told me it is much better than Windows File Explorer and he cannot work without it.

Since then, I tried this tool and I fall in love with it. It helps a lot for file exploring, management, and software development. When I work any where, I always bring it with me.

Many other tools are also very good. Here is a list of tools Jean-Paul and Scott Handselman recommend:



I like to read JP's blog. Some of his blogs recommended some really good tools.

Read More...

Thursday, May 29, 2008

Find a Control in ASP.Net Page

One ASP.NET page is composed of one aspx or xml file for front-end UI design and a class either in C# or VB as server side codes related to the page and control events.

Unlike window form application, the code-behind class does not know controls on the page directly. You cannot directly access control instances. For example, a label or text box control within a GridView control's template.

Here is one function I use to get a control by id:

using System.Web.UI;
...
public class WebPageUtil
{
...
public static T FindControlRecursive<T>(Control root, string id) where T: Control
{
T found = null;
if (root != null)
{
found = root.FindControl(id) as T;
if (found == null)
{
if (root.ID == id)
{
found = root as T;
}
else if (root.Controls != null)
{
foreach (Control ctr in root.Controls)
{

found = FindControlRecursive(ctr, id);
if (found != null)
{
break;
}
}
}
}
}

return found;
}
...
}


Where Control is a System.Web.UI.Control. It has FindControl() method. It can only find control within a container control, or root in this case. For example, in a GridView control named as GridView1, a TableCell control in a selected row (GridView1.Rows[0]) may contain some Label or TextBox controls, which are defined within aspx page GridView1 control's template.

However, this call only search for controls directly placed within the current control. If the control is within the next or even deep level, you have to loop its children Controls to call recursively.

I use generic type method call to make the method very simple to use. Here are some examples:

GridViewRow row = GridView1.Rows[e.RowIndex] // e is GridViewUpdateEventArgs object
LinkButton btnSave = WebPageUtil.FindControlRecursive<LinkButton>(row, "btnSave");
if (btnSave != null)
btnSave.Visible = false;

Read More...

Thursday, May 08, 2008

SQL Server Project (3)

In a SQL Server Project, all the SQL Server Objects (SSO), such as stored procedures (SP), must be defined as public static methods. All these methods are marked with Microsoft.SqlServer.Server Attributes, so that they can be deployed as SQL Server Objects.

Let's see how a SSO is called in SQL Sever. For example, when a SP is called first time, the SQL server will load the assembly library from the database, as I mentioned that all the assemblies have to be registered in a DB, into memory. Then the specified static method is called. After the SP finishes its job, however, the assembly stays in the memory forever. I tested this feature with a simple SP and a private static integer counter in its class. The counter increases by 1 for each call. The counter stays in the memory with its last call increment for several days.

This is a quite interesting feature of the deployed SSOs. Actually, if you think it in the context of SQL service process, it is not hard to understand it. The SQL service process loads the assembly into memory. Since static methods are global available, they will stays as long as the SQL service process stays.

However, this posts a problem most developers do not realize. They assume that when a call is finished, all the related resources should be released. If the assembly is not well designed, it may cause memory leaks in a SQL server. For example, if some resources are not cleaned, these resources are left in the memory for each call. You can imagine that if the SSOs were called constantly, it would cause memory leak. Another issue is that if some resources are static and not cleaned, these resources are occupied in memory. As a result, the first call is fine, but the next call may get exception since they cannot access these resources.

Therefore, you have to pay attention to all the cleaning jobs. Make sure that all the resources are freed after the execution, including the case of the execution being interrupted by clients. For example, you have to handle ThreadAbortException exception.

Talking about exception handling, it is not recommended to handle or hide all the exceptions. For example, if you design a Trigger, you may want some exceptions thrown to SQL server so that any related failure would cause the SQL server to roll back transactions. Therefore, if you know how to handle some exceptions, you can handle them, otherwise, leave them alone.

There is a way to clean assembly from memory in SQL server. Run the following command to clean all the unused cache and free up memory:

DBCC FREESYSTEMCACHE ('ALL')

I run this command in a daily job for cleaning memory used during a day.

Read More...

Wednesday, April 30, 2008

Python

Recently, I started to learn Python script language through Python Tutorial. It is a very interesting programming language. It is very powerful and unique. The reason I have interest in Python is that I read an article about Google's open source project. It mentioned that Google promotes this open source language. After reading several sections in the tutorial, I really like Python.

Another reason is that Apple's OS installs Python by default. It is a script language used as Apple's script language. I am going to learn and write some scripts. Python may be a good choice.

I just read a section about Class in Python. Within a Class, there are two types of members, one for attributes and another for methods. You don't need to define all the methods in a class. You can add or delete attributes to a class dynamically. It is really convenient. However, if you defines a attribute, you cannot dynamically to delete it.

Regarding del statement, you can use it to delete a definition of a class as well. If you create an instance of a class and then delete the class, the instance still works For example, you can still call the instance's attributes or methods. I think that the instance is created in memory like an object. In Python, every thing is object.

Read More...

Saturday, April 12, 2008

SQL Server Project (2)

As mentioned in the links in the previous article, SQL Server Project provides some basics to connect to a SQL server and communicate with the server.

Here is a brief of these basics:

  • Connect to SQL server by connection string "Context Connection=true" so that no need to specify database and authentication information for most cases, since the project is deployed to SQL debase and all the stored procedures, functions and others run in the context.

  • Send messages back to SQL server by SqlContext.Pipe.Send() method. The method call has two overloads, one taking a string as its parameter, and another one IDataReader. To call this method, no connection is needed.

  • Execute SQL statements through IDbCommand.ExecuteXXX() methods: ExecuteReader(), ExecuteNoneQuery(), and ExecuteScalar(). By using these methods, you can all SQL query and none query statements.

With all these basics, it looks that you can go ahead to create any SQL server database objects (stored procedure, function, triggers …). However, when I first time rolled my sleeves on a project, I encountered a problem. There was so limited number of references available in my Visual Studio project, about 5 only. There is no browse button for adding references neither. How can I use other Microsoft .Net libraries, as well as libraries I created?

To solve the problem, I finally realized that I have to understand the way how .Net assemblies are loaded and executed in a SQL server database. All the assemblies, including dependent assemblies, have to be registered in the server database. For example, if a stored procedure is defined in a .Net assembly, the assembly and its dependent assemblies have to be registered in a SQL server database. When the stored procedure is executed, the SQL server database will load the assembly and dependent ones from the database, not from local or remote file systems.

Therefore, if you want to add new references to your project, you have to register these libraries to the SQL server database first. The SQL server project’s reference dialog window lists only the libraries from the destination SQL server database.

To register a library to the SQL server database, you have to understand a few of additional concepts. First is the Permission set. To register an assembly, a Permission set has to be specified. There are three types: SAFE, EXTERNAL ACCESS, and UNSAFE. Try to register your libraries from SAFE mode first. If you get any error messages, you may have to try the next level till you can get them registered.

Permission sets are for security and reliability purposes. However, in most cases, you have no choice to use the least secured permission level. My understanding of those modes is that, if you run pure .Net managed codes and only for internal access, you should use SAFE mode. If you have to access to external resources such as file system, you have to use EXTERNAL ACCESS. If the libraries contain codes to access dynamical resources such as reflection load and web services or unmanaged codes, you have to no choice to UNSAFE. As a result, if you use some third party libraries, including many of Microsoft ones, you may end up with UNSAFE in most cases.

The second concept is that your assembly must be a strong named one if the permission mode is not SAFE. SQL server enforces this mandatory requirement for all none SAFE assemblies. If the assembly is not a strong named one, you have to sign it with a key by using the tool of sn.exe from Microsoft.

With these understandings, you are ready to register your dependency assemblies to a SQL server database. The followings are some SQL commands I used:

Add a key to assembly files
Signer.exe -k ..\..\myCompany_key.snk -outdir .\build -a *.dll

Add a strong name key and login permission for the key in SQL Server
Use master
IF EXISTS(SELECT * FROM sys.syslogins WHERE NAME = 'Assembly1_Login')
BEGIN
DROP LOGIN Assembly1_Login;
END
IF EXISTS(SELECT * FROM sys.asymmetric_keys WHERE NAME = 'Assembly1_key')
BEGIN
DROP ASYMMETRIC KEY Assembly1_key;
END
CREATE ASYMMETRIC KEY Assembly1_key FROM EXECUTABLE FILE = 'C:\Temp\bin\Assenbly1.dll';
CREATE LOGIN Assembly1_Login FROM ASYMMETRIC KEY Assembly1_key;
GRANT UNSAFE ASSEMBLY TO Assembly1_Login;

Register an assembly
DECLARE @asm VARCHAR(1024);
SET @asm = 'C:\Temp\bin\MyAssembly.dll';
IF EXISTS (SELECT * FROM sys.assemblies asms WHERE asms.name = N'MyAssembly')
DROP ASSEMBLY [MyAssembly]
CREATE ASSEMBLY [MyAssembly] FROM @asm WITH PERMISSION_SET = unsafe;

After your registration process, open your project in VS again. You should be able to add references to you project. I always save my registration process in a script. In case I have to reload my assemblies, or deploy the same one to another production database, I can use the script to do the job.

Read More...

Tuesday, March 18, 2008

SQL Server Project (1)

Visual Studio 2005 provides a template for creating SQL Server Project, which you can create stored procedures, functions, triggers and more. When the project is deployed to a SQL server, all the SQL database objects defined in the project are created on the server. The project is a class library. Therefore, the assembly is also created on the SQL server database. All the database objects defined in the project are dependent on the assembly.

There are some articles on this issue on the web. The following are introduction ones good for beginners.



However, if you want to get into depth of real implementation for your business cases, you will encounter many issues and there are not any good resources available, at least I have not found out yet. I started to work on SQL server project from the idea to call .Net assembly classes from SQL server stored procedure. When I googled this topic. I found the above links. That's actually what I want to do. It looks very attractive. I jumped in the ocean and that has been quite good experience.

Any way, I found out many issues I have to resolve in order to create SQL database objects for real business cases. The links above give you very good start point and some very basic skills such as to create connection to SQL server, to get data, to execute SQL commands, to insert or to delete data, and to send result back to SQL server.

The cool thing of using .Net to create SQL database objects (stored procedure or SP, function and triggers) is that you can use the current context connection to a SQL server since the SP is running in the SQL server. Then you can execute almost any SQL commands. It is very fast. All of these can be done in .Net, for example, c#.

I tried to query data and to insert data with SQL database tables, and compared to the same simple SQL SP scripts as well. For a query of repeating 1000 times, the .Net SP is a little bit faster than the SQL scripts, 00:12:00 compared to 00:12:17. For the insert statement, the SQP scripts is faster than .Net SP, by a very little difference (just seconds for 1000 rows). However if you think in more perspective view, .Net objects are much more attractive than SQL scripts.


  • .Net SQL Sever Project is very similar to PL/SQL's package. You can deploy only the SPs you want to expose, for example, and to hide all the other classes or related methods data in the library. While SQL SP scripts are public only. If you write several SPs and they have dependent relationship, you cannot hide the dependent SPs in a SQL server database. I wrote a calculation SP. Then I separate many codes to other SPs and user defined functions. As a result, the calculation SP is dependent on several other SPs and functions. Those dependent SPs and Function are not supposed to be used for public directly, but I have no way to hide them. This makes the management and usage of SPs and functions very difficult.

  • .Net SQL Server Project separates source codes from SQL Server. What you have to do is to deploy your assembly and dependent assemblies to a SQL Server Database. All the assemblies, SPs and functions are in binary forms. This avoids other people to change them directly. All the source codes can be saved in a source code repository such as SVN.

  • Since .Net SQL Server Project is written in .Net managed codes such as C#, the performance of SPs could be improved. For example, in SQL scripts, there are very limited way to cache data. One way I found to share a group of data between SPs is to use temporary table. I read some articles on this technique. It is not recommended by many people. A temporary table is created in local hard disk. If you constantly access to it such as querying, deleting and saving to the table, your script's performance would be affected. However, in a .Net project, you can easily cache data in memory. For some small amount of data, which will be used constantly during the process, I can run one query to get the data and save them in cache as a class object. Then it can be used by other classes. You don't need to do query again or read from a temporary table. That's a great improvement in terms of performance since less query is needed.

  • By using .Net Server Project, some of existing libraries can be reused. Those reused resources are hidden in assembly form or referenced to, so you can improve or update those resources without changing the public interface of deployed SPs. However, those dependent resources or library assembly files if referenced have to be registered on the SQL server database. I'll continue to discuss on this issue in later articles.

  • The .Net Server Project should provide very simple interface for deploying SQL server database objects such as SPs, Functions and Triggers. Those codes should contain SQL server related classes and objects. All the other business logic, services, and resources should be in another assembly files. In this way, the same codes can be reused in other projects such as Windows applications, console applications, and generic libraries.



I have mentioned so many advantages about SQL Server Project. However, when you get your hands dirty or do it for a real business case, you may find out it's not so easy as you do in other .Net projects. There is a difference how these assemblies are used or executed in a SQL server database or just an application in Windows. There are many issues to be resolved as well before you can fully take the advantages of .Net. For example, you may find out that there are very little references available you can add to your project at the first time. How can you reuse your libraries, third party libraries, even many other Microsoft libraries? That's the next topic for this series.

Read More...

Thursday, February 07, 2008

Use Temporary Table to Pass Global Variables

One limitation of stored procedures (SP) in Microsoft SQL 2005 is that there is no global variables you can define. You can pass values by parameters; however, if you want to add additional information between SPs which are already in use, it will be difficult to make change since the signature of SPs are already defined. Oracle's package is much more convenient. All the global variables can be defined in a package and you can even define private SPs. Off course, .Net assemblies developed by managed codes as C# offer much more choices.

Any way, I find a way to pass values between SPs without changing parameters: using a temporary table. A temporary table can be created in a caller SP and then all the callee SPs can access to it. I have implement this strategy in a SQL application and it works very well.

The structure is that a temporary table, for example #calculationInfo_CachedForCalc, is created in the starting SP. The table contains only one row of data, global variables. Some values are updated in the caller SP (they can be updated in any other SPs). Then the callee SPs will get the value for use. One problem is that the callee SPs may be called or executed in other cases, since they are public accessible. I have created a utility function to check if the temporary table exists or not. Here is the function:

CREATE FUNCTION [dbo].[udf_IsCachedDataAvailable](
@p_cachedDataType int = 0)
RETURNS int
AS
BEGIN
DECLARE @v_ret int;
SET @v_ret = CASE @p_cachedDataType
WHEN 1 THEN
WHEN OBJECT_ID( 'tempdb..#calculationInfo_CachedForCalc') IS NULL
THEN 1
ELSE 0
END
-- ... Check for other objects by other possible parameter values
END
RETURN @v_ret;
END

In the start SP, or caller SP, here are some codes:
IF dbo.udf_IsCachedDataAvailable(1) = 1
BEGIN
CREATE TABLE #calculationInfo_CachedForCalc(
[id] [int] IDENTITY(1, 1) NOT NULL,
[calcName] [varchar](50) NULL,
[logFlags] [varchar](50) NULL,
[calcCumulativeType] [varchar](10) NULL)
INSERT INTO #calculationInfo_CachedForCalc
([logFlags] VALUES(@p_parameter); -- log flags passed in by SP parameter
END

-- FETCH LOOP read a row from calculation table
-- ....
UPDATE #calculationInfo_CachedForCalc SET
[calcName] = @v_calcNam, -- Update calculation name variable
[calcCumulativeType] = @v_calcCumulativeType; -- Update calculation type var

EXEC sp_CalcFormula;
-- ....

In other callee SPs, such as sp_CalcFormula(), the temporary table is accessed to get a global variable such as log flags:
IF dbo.udf_IsCachedDataAvailable(1) = 0
BEGIN
SET @v_flags = (SELECT [logFlags] FROM #calculationInfo_CachedForCalc);
-- ....
END

Read More...

Tuesday, February 05, 2008

GridView and AJAX PopupCalendar Issue

I tried to use ASP.NET AJAX CalendarExtender control in GridView's edit template for a date field in the way just as the example show on How Do I: Configure the ASP.NET AJAX Calendar Control? That is, I added a text box binding to a field in the gridview as date, a image button next to it as a button, and a CalendarExtender control which is AJAX control. The extender control's TargetControlID is the text box, and PopupButtonID is the image control.

However, it does not work. Actually, the pop-up calendar does pop up, but it disappears right away, and the whole page is refreshed. It looks like that the lick on image button caused a call to server to send a post-back call. The example works fine, but it is too simple(a text box, a image button and a CalendarExtender on an aspx page). I am not sure why this extender does not work when it is embedded in the gridview. I think I have to find a way to prevent the post-back call so that the pop-up calendar will stay.

Read More...

Friday, February 01, 2008

SQL's NULL Marker and Its Propagation

NULL is a SQL's marker to indicate missing information or unknown status. It is essential part of relational database and SQL. One of NULL feature is that it can propagate the result in many cases and they do make sense.

For example, 1 + NULL is NULL, or NULL in any mathematical expression will result NULL. That's OK. However, it further propagates to SQL internal functions, like LEN and CHARINDEX. It is very difficult to argue why not the result is NULL. I have to say it will depend on your case.

Recently, I have been working on a project with Microsoft SQL 2005. I did not realize that LEN and CHARINDEX functions return NULL if its parameters are NULL. That caused problem in my stored procedures. What I need these functions is to find out if a specified string exists in an expression. The expression is a value retrieved from db table. For my case, if the value is NULL, the result should be either LEN = 0 or CHARINDEX = 0.

As a result, I have to overwrite these internal functions as user defined functions such as udf_LEN() and udf_CHARINDEX. Then will handle NULL parameters and return the correct result. For example, I use the following CASE statement to check an input parameter:

DECLARE @v_ret int;
SET @v_ret = CASE
WHEN @p_string IS NULL THEN 0
ELSE LEN(@p_string);

When you use internal functions, you have to aware NULL's implication or propagation in your result.

Read More...

Saturday, January 05, 2008

Initialize Castle.AR and NHiberate

I tried to use Castle Project's ActiveRecord to map a .Net class to an Oracle DB in an ASP project. I followed the instruction to create an xml configuration file, to load the configuration and then to initialize ActiveRecord like this:

  XmlConfigurationSource source = new XmlConfigurationSource(
"C:\\temp\\ActiveRecords.xml");

ActiveRecordStarter.Initialize(source, typeof(Employee));

I got a failure exception when Initialize() method is called. I struggled for almost a whole day to find out why, and downloaded Castle's example project as well. I got the same error message (System.TypeInitializationException).

Finally, I found out in the detail information in debug mode that the inner exception was caused by "could not find log4net.dll file". When I checked the path for this file in the project references, I realized that it points to a wrong dll file in the MBUnit folder. After I removed and re-added the correct dll file, the problem was solved!

Read More...

Wednesday, December 05, 2007

PageFlow, WorkFlow classes and Designer

Widnows WorkFlow Foundation provides an in-process workflow engine for many classes with visual work flow process in design mode in VS, such as Sequential WorkFlow, Machine WorkFlow, Activities, PageFlow, and so on.

By using the visual designer, you can easily define work flow, process item relationships and constrains as a work flow class. In addition to WWF core WorkFlow classes, other third parties or organizations or open source groups (such as PnP) adds other useful WorkFlow classes. The APS.NET solution I have been working on includes a project with PageFlow class.

The PageFlow class is defined within Microsoft.Practices.PageFlow.WorkFlowFoundation.dll by Microsoft Patterns and Practices group. The problem I encountered is that after I created the project by using Guidance Package Manger Recipe of Add PageFlow Project, I got an error message when I tried to open PageFlow1.cs in design mode in VS, but I don't have problem to compile the project. It looks like that its related designer class is not available.

Actually, the designer class is Microsoft.Workflow.VSDesigner.dll. I have to search for this file first. Then I copy this file to the folder where ...WorkFlowFoundation.dll file sits. After making the designer class directly available to the owner assembly, I can see the class in design mode in VS after I re-open the VS again.

Read More...

Tuesday, December 04, 2007

Add Reference to Visual Studio 2005

I have installed .Net Framework 3.5 in my box (not 3.0) and WCSF for a ASP.NET project based on WCSF. When I tried to use Guidance Package Manger's Add Page Flow Project recipe I got an error and failed to add the project.

I wondered why it failed. It must use some kind template to add project. I then found the template project which has the following references but I cannot see them in my VS Add Reference Dialog window:

<Reference Include="System.Workflow.Activities" />
<Reference Include="System.Workflow.ComponentModel" />
<Reference Include="System.Workflow.Runtime" />

I think that is the reason I get the failure. My direct reaction was that I thought .Net 3.5 may not include or install 3.0 assembly files. That's wrong. From VS Add Reference list, I can see that System.WorkFlowServices.dll is located in C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\, and others which are not in VS's Add Reference window are in ...\v.30 folder.

It must be some settings such as environment or registry settings which make these assembly files visible in VS. I can find where those settings are. Anyway, cut the story in short, I found a msdn link about How to: Add ore Remove Reference in Visual Studio 2005. This web page does provide information on how to add customized assemblies in VS by setting windows registries. I followed the instruction I found that the NUnit and MbUnit assembly files I installed are set in the registry and they are in VS Add Reference window. Here are examples of NUnit 2.4.3 and MbUnit in the current user registry:
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework\AssemblyFoldersEx\NUnit 2.4.3]@="c:\Program Files\NUnit 2.4.3\bin\"
[HKEY_CURRENT_USER\SOFTWARE\Microsoft\.NETFramework\v2.0.50727\AssemblyFoldersEx\MbUnit]@="c:\Program Files\MbUnit\"

Notice that NUnit is not related to any version while MbUnit is under .Net v2.0.50727. According to the msdn, if you add assembly location folders in HKEY_LOCAL_MACHINE in the same way, any user in the pc then can see these assemblies in VS.

Those are settings for third party to add their assemblies to VS 2005's Add Reference window. However, I still can not find any thing bout Microsoft assembly settings. I know where assembly files are, but I don't know what settings to cause them visible in the VS 2005's Add Reference window. Maybe Microsoft does not want people to mess up third party programs with Microsoft ones.

Anyway, I finally find a way to get them visible in VS 2005. I installed Visual Studio 2005 extensions for .NET Framework 3.0 (Windows Workflow Foundation). The installation did some magic settings and I can add Page Flow Project without any failure and I do see these v3.0 WowkFlow assembly files in VS 2005.

Read More...

Monday, December 03, 2007

ASP.NET Authentication Configuration

I was working on a Web application based on ASP.NET and WCSF. The application has a root virtual path with web.config and several sub-folders for other views. Each sub-folder also contains a web.config file.

Before I introduce authentication and Login to the application. It works fine. However, after I added security checking, I got compiling and running exception error. It complains about any authentication in web.config file. The following is an example error:

Line 107: <authentication mode="Forms">
Error It is an error to use a section registered
as allowDefinition='MachineToApplication' beyond application level.
This error can be caused by a virtual directory not
being configured as an application in IIS.
...EmployeeList\Web.config 37

After about half day investigating, I finally found that the error is caused by authentication defined in multiple web.config files. According to ASP.NET's recommendation, in a forum discussion, the authentication can only be defined in the root web.config for each APS.NET application or machine config file once.

That means I have to move all the authentication configurations to the root web.config file. In addition to that, in my application case, if a client logs out from the security from master page's LoginStatus control, it should be redirected to the main page or LoginPage.

After all these changes, my application works like charm!

Read More...

Friday, November 30, 2007

Create Templates for Visual Studio 2005

Create customized templates for Visual Studio 2003 and VS 2005 are very different. David Hayden has one blog on this issue with VS 2005.

It is very easy to create either a template project or template item in VS 2005. VS 2005 provides a wizard to do that from File|Export Templates... By the way, if you cannot find the Export menu item, you have to add it from Customize toolbar and drag the Export item under the File menu item.

However, I don't like to use the wizard to create or modify my template if I find some minor things to change or to create another one based on an existing one. I would like to work on copy-and-past pattern. The first thing I have to find out where my templates are and how they are organized.

For example, I created a template class item for NUnit test class. I want to create a similar one for MbUnit. I found out that after finished the wizard, my NUnit template is created under the following three locations (%userprofile% is "c:\Documents and Settings\[username]"):

%userprofile%\Application Data\Microsoft\VisualStudio\8.0\ItemTemplatesCache\NUnitTestClass.zip\
%userprofile%\My Documents\Visual Studio 2005\My Exported Templates\NUnitTestClass.zip
%userprofile%\My Documents\Visual Studio 2005\Templates\ItemTemplates\NUnitTestClass.zip

Actually, the template is saved at the third location. The first one is a cached template. If I want to change or create a new one, I have to go the last location to update or create one. After that, I copy and paste the new template to the second location.

It is much easier to update or create new template in this way.

By the way, I find one location in Google Code to host project files for downloading. I created my project site. I am going to put my source codes there. Here is list of my templates for NUnit and MbUnit test classes.

Read More...

Thursday, November 29, 2007

A Solution for Assembly Version Issue

Continuing with the issue I described in Rhino.Mocks and AutoMockingContainer, I found another solution to resolve the problem instead of recompiling AutoMockingContainer.

It is not always the case that you can get dependent library source codes. The alternative solution to redirect the .Net CLR to load a new version of the specified assembly. I'll take the my test project with Rhino.Mocks and AutoMockingContainer as an example. The Rhino.Mocks version I used in my project is version 3.3.0.906, while AutoMockingContainer was built with Rhino.Mocks version 2.8.1.2631 as its dependency. My test project will be compiled as TestClasses.dll. By default, all the binaries will be copied to Output directory with the latest Rhino.Mocks (3.3.0.906).

When my test class tries to call any AutoMockingContainer class which depends on Rhino.Mocks (2.8.1.2631), the .Net CLR cannot find the specified strong named assembly dll, and then exception was thrown.

I remembered that when .Net was released, it claimed to resolve COM-hell issue with versions and it allows two or more different versions of assembly running within a process. One way to resolve the version issue is to promote the version by using assembly's configuration file. For more information about .Net configuration, see Configuration File Schema for the .NET Framework.

That link provides a way to redirect old version to new version by using configuration's bindingRedirect element. Here is what I did in my test project:

  1. Add a configuration file to the project where AutoMockingContainer is referenced. The file name should be as same as the project name with congif extension. For example, I used "TestClasses.dll.config".

  2. Right click on this file and set Copy to Output Directory to Copy Always.

  3. Add the following line to the configuration file (make changes depending on your case):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Rhino.Mocks"
publicKeyToken="0b3305902db7183f"
culture="neutral" />
<bindingRedirect oldVersion="2.8.1.2631"
newVersion="3.3.0.906"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

  1. Finally compile the project. The project should run (with NUnit test program) without exception.


I used the tool of Lutz' .Net Reflector to find assembly's version. It's a great tool for developers.

Read More...

Wednesday, November 28, 2007

Update Assembly Version

Continuing from the previous blog, I found two places talking the related issue: how to manage assembly version:



The utility program's author, Matt, also posted two interesting tools: one for system tray icon with tooltips, and another PrefTimer timer class based on API.

Read More...

Rhino.Mocks and AutoMockingContainer

I am working on an ASP.Net project based on WCSF (Web Client Software Factory). For test, I downloaded the latest Rhino.Mocks, NUnit and MbUnit libraries. It works fine at the beginning because all the libraries are new.

For the tests, I need to mock some services and views. I remembered that I used AutoMockingContainer class and I had a generic class for mocking purpose. Then I copied the AutoMockingContainer to the project. After that, my mocking objects stop working and an exception was raised. Here is the error message:

[System.IO.FileLoadException] {"Could not load file
or assembly 'Rhino.Mocks, Version=3.2.0.781, Culture=neutral,
PublicKeyToken=0b3305902db7183f' or one of its dependencies. The located assembly's
manifest definition does not match the assembly reference. (Exception from HRESULT:
0x80131040)":"Rhino.Mocks, Version=3.2.0.781, Culture=neutral, PublicKeyToken=0b3305902db7183f"}
System.IO.FileLoadException


It was very confusing. I thought it might be my Visual Studio or Windows wrong. However, I restarted my Windows and VS again. Still I got the error message. Finally I found that it is the call to AutoMockingContainer class where exception is raised. When I read the error message. I realize that the version of Rhino.Mocks is difference from the same library which is used in the project (ver 3.3.0906).

The problem is that when AutoMockingContainer class is called, CLR is looking for Rhino.Mocks with ver 3.2.0.781. This not-matching caused the exception. It is very interesting. Why does CLR not automatically search for the class or method in a new ver?

Any way, fortunately, I found the source codes of AutoMockingContainer and rebuilt the binary with the same version of Rhino.Mocks. After that, everything works fine. I think that if a library used in a project which depends on old version of assembly, the old version ones have to be installed correctly. It is not as simple as copy library dll files. You have to run deployment or installation to install all the libraries, including dependencies. If both old and new one are used in the same project, the old ones have to be upgraded to new ones.

I think this is an issue of assembly version, and Microsoft has solve the problem. As developers, we have to follow the version management policy to manage version issue. I'll further investigate the issue and try this project with two different versions of Rhino.Mocks library files in one bin directory.

Read More...

Friday, November 23, 2007

Connect to Oracle Dadabase by OracleConnection

I installed Oracle 10g XE in my box, and then Oracle Developer Tools for .Net (ODTwithODAC1020221). After the installation, I started to work on .Net C# project against Oracle DB.

The first thing I have to do is to build a connection. At the start, I got exception when I tried to open an OracleConnection to userID=HR, Data Source=XE:

ORA-12154: TNS:could not resolve the connect identifier specified


Without connection, I cannot continue to do anything about the Oracle DB. After one day struggle, I finally found the reason from Oracle Developer Tools Forum: the home directory for Tools Kit is different from the Oracle db home directory! I have to follow the instruction to copy Oracle's TNSNAMES.ORA to the Tools' home directory. After that, the problem is solved!

Read More...

Thursday, November 22, 2007

Internet Security Issue

Internet is so convenient and useful. It opens a wide door to the world. For most people, it is an important part of their lifes. However, Internet security is a problem for most people who use Internet, especially who use it doing emails, banking and evening personal stuff in their local computer. Most people don't know about it and don't know how to protect their private information.

As a programmer, I realized it and I found it so easy to get some personal private information by writing a simple program, for example, login id and password. For window users, there are some window API functions which can be used to monitor process and keyboard. They are part of Windows' core and available for all windows platforms. A programmer can easily write a program by including those APIs to log keyboard and mouse activities without user's notice (in background).

For example, I wrote a program just for personal test purpose and as a demo to show to my friends. It is a console application. When you start it in a console, it starts to monitor keyboard and mouse activities and print out keys and mouse click on the console. I tried it to login many secured programs such log in and web sites. I can see their login ids and password!

The following is a snap-shot of a case: login to a bank's web site:



You can see that login id is "watchme", then tab to the password text box with "password".

You can image that this feature can be enhanced to work with some process monitors to monitor specified process and steal your personal information (I also verified that there are Windows APIs available to check current process and their titles such browser changes). Some virus or unknown programs can be easily installed in one's machine with those kind of spies.

How can you protect yourself? As a demo shown above, I always advice people don't type in your personal information in a regular habit: login id, tab or mouse click, and then password! You can make fool of these monitor programs. Don't type in your login and password continuously and correctly! You may purposely type in wrong ones or partial ones. Jump around between login and password, even browser tabs. Type something on the page. Make it hard for the spy programs to get your personal information! As well, change your login password regularly.

Some web sites provide more security options for users. For example, in above demo, there is an optional description for you to type in anything. After login the site, this site may ask you additional questions you have previously set if you login from a new location (which may be inconvenient for many users). All these efforts are made to protect you.

Read More...

Saturday, November 17, 2007

Another Update on My Blog Template: Show/Hide Posts

Vin posted another good tip on Show/Hide Posts.

The Show/Hide Posts Tip is actually much better than my previous template update. It uses a javascript and updates on a widget("id=Blog1"). I like this tip very much.

When I tried to update my template with this new feature yesterday, I could not do it. I thought it is Blogger server problem. I tried today. The respond was very quick. However, I got several error messages about #comments or #cdata not being allowed in <skin> or widget tags (I commented out existing codes and added some comments for the changes). Finally, I have no choice to remove all the comments. The update is successful.

I am very happy with the update. I think it is very easy for people to see all the posts in a outline. In addition to the tip, I added some changes to the template. For example, I added title attribute for Post Title. This provides a help information (mouse hover tooltip) because the Post Title is a link and when it is clicked, only this post is displayed with comments visible. If "[+/-]Show/Hide..." is expanded, comments are not visible. Because of this behavior (I don't want to spend time to figure it out why), another change I did is to add a link(See/leave comments for this post in another window/tab) after "[+/-]Show/Hide...".

Happy Blogging!

Read More...

Friday, November 16, 2007

Update My Post Template Formatting

Updated my template based on Vin's guide on Posting Summaries again.

I made a comments about Vin's guide on Enable Post Comments. This page is the testing based on the notes. What I did is to place the following codes in the post template at my Settings|Formatting:

Here is the beginning of my post. <span class="fullpost">And here is the rest of it.</span>


Then save it.

How this works...

When you post a new blog, the "Here is the beginning ..." part is the first paragraph in the blog, which will be displayed in the new post followed by Read more... link. If you click on the link, a new window or tab is displayed with the whole blog content. That looks pretty good!

Read More...

Thursday, November 15, 2007

Updated My Blog with Blogger's New Template

In the past two days, I tried to updated my blog with the new template from Blogger. The new one is much better and simpler than the previous one. The key improvement is widget elements which can be changed from Blogger's Template Tab (Page elements).

Of course, the change removed all my previous changes as well. I had to manually to add my previous changes in, such as RRS section on sidebar and scrollable text boxes. I also find out Dummies Guid to Google Blogger is much helpful!

Enjoy Blog!

Read More...

Monday, November 12, 2007

Single Instance of Application

Many cases require only one instance of a specified application running. This can be done by using Microsoft .Net Mutex class. However, by using Mutex, you can tell if the application is already running or not. If it is running, either active, inactive, or minimized, how can we bring the application to the front? I found that you have to use API functions to do that.

As a result, I have created a class ApplicaitonUtil. This class has two methods exposed: IsAlreadyRunning(name) and SwitchToCurrentInstance(). They are very straightforwd. Here is an example to use it:

[STAThread]
static void Main()
{
AssemblyInfo1 assemblyInfo = new AssemblyInfo1(
Assembly.GetExecutingAssembly());
FileSystemInfo fileinfo = new FileInfo(
Assembly.GetExecutingAssembly().Location);

string name = string.Format("{0} {1}",
fileinfo.Name,
assemblyInfo.Description.Description);

if (ApplicationUtil.IsAlreadyRunning(name))
{
ApplicationUtil.SwitchToCurrentInstance();
}
else
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);

Form1 form = new Form1(); // Assume Form1 in your project
form.Text = name; // Set caption for the form
Application.Run(form);
}
}

Here I used assembly exe name and assembly information description (see my previous blog on AssemblyInfo and Related Utility Classes) as a name for the Mutex object. The name can be anything (no path is included! otherwise you would get an exception). The reason I used assembly's description information is that the same exe file might be deployed to local version and QA version. You may need each one as single instance but you can run two at same time.

By the way, I updated my AssemblyInfo class so that it has additional constructor with specified assembly object. If you place this class in another class or exe as library, you need to pass assembly object as shown in above codes.

Here is the my ApplicationUtil class:
public class ApplicationUtil
{
# region Windows APIs
[DllImport("user32.dll")]
private static extern int IsIconic(IntPtr hWnd);

[DllImport("user32.dll")]
private static extern int ShowWindow(IntPtr hWnd,
int nCmdShow);

[DllImport("user32.dll")]
private static extern int SetForegroundWindow(
IntPtr hWnd);
# endregion

# region Constructor
private ApplicationUtil()
{
}
# endregion

# region Data members
// Define const used for restoring the window
// already opened
private const int SW_RESTORE = 9;
private static Mutex _mutex;
# endregion

# region Public methods
public static bool IsAlreadyRunning(string name)
{
bool mutexCreated;

_mutex = new Mutex(true, name, out mutexCreated);
if (mutexCreated)
_mutex.ReleaseMutex();

return !mutexCreated;
}

public static void SwitchToCurrentInstance()
{
IntPtr handle = GetCurrentInstanceWindowHandle();
if (handle != IntPtr.Zero)
{
// Restore window first if minimized.
// Do not restore if already in
// normal or maximized window state,
// since we don't want to
// change the current state of the window.
if (IsIconic(handle) != 0)
{
ShowWindow(handle, SW_RESTORE);
}

SetWindowToForeground(handle);
}

return;
}

public static void SetWindowToForeground(
IntPtr hWnd)
{
SetForegroundWindow(hWnd);
}
# endregion

# region Private methods
private static IntPtr
GetCurrentInstanceWindowHandle()
{
IntPtr handle = IntPtr.Zero;
Process currentProcess =
Process.GetCurrentProcess();
Process[] processes =
Process.GetProcessesByName(
currentProcess.ProcessName);

foreach (Process process in processes)
{
// Get the first instance that is not this
// instance, has the same process name and
// was started from the same file name
// and location. Also check that the process
// has a valid window handle in this session
// to filter out other user's processes.
if (process.Id != currentProcess.Id &&
process.MainModule.FileName ==
currentProcess.MainModule.FileName &&
process.MainWindowHandle != IntPtr.Zero)
{
handle = process.MainWindowHandle;
break;
}
}

return handle;
}

# endregion
}

This class has another method SetForegroundWindow(), which is used to set a form as foreground. For example, you have a lengthy splash window running, and this form might be set to background if user is working on something else. In this case, when the splash window finishes its job, you can call this method to set the main form to the front so that user is notified the application being ready.

Read More...

Sunday, November 11, 2007

AssemblyInfo and Related Utility Classes

I worked on one project where I need to get an assembly's information defined in the project's AssemblyInfo.cs. There are many ways to get these information. One way is by calling Assemlby class' method GetCustomAttributes() like this:

Assembly _assembly = Assembly.GetExecutingAssembly();
objects[] _assemblyAttributes = _assembly.GetCustomAttributes(true);

I tried to print out the array of retrieved attributes. There are 15 items. I thought the order of these attributes are pre-defined. Then I wrote a class to get some of assembly information out by the index.

However, I run into a problem. When I changed some attributes, for example AssemblyCulture(), my class does not work any more. I finally found out that the order of attributes in the object array are changed! Before I realized this, I tried other ways to get AssebmlyIno. Here is another class by using FileVerionInfo class:
using System;
using System.Reflection;
using System.Diagnostics;
using System.Globalization;
//...
class AssemblyInfo1
{
private Assembly _assembly;
private FileVersionInfo _fileInfo;

public AssemblyInfo1()
{
_assembly = Assembly.GetExecutingAssembly();
_fileInfo = FileVersionInfo.GetVersionInfo(_assembly.Location);

}

public string Title
{
get
{
return _fileInfo.Comments;
}
}

public string Description
{
get
{
return _fileInfo.Comments;
}
}

public string Company
{
get
{
return _fileInfo.CompanyName;
}
}

public string Product
{
get
{
return _fileInfo.ProductName;
}
}

public string CopyRight
{
get
{
return _fileInfo.LegalCopyright;
}
}

public string Trademark
{
get
{
return _fileInfo.LegalTrademarks;
}
}

public string FileVersion
{
get
{
return _fileInfo.FileVersion;
}
}

public string InformationVersion
{
get
{
return _fileInfo.ProductVersion;
}
}

public Version Version
{
get
{
return _assembly.GetName().Version;
}
}

public CultureInfo Culture
{
get
{
return _assembly.GetName().CultureInfo;
}
}
}

The only problem is that I could not find a way to get AssemblyConfiguration() information. After I realized the order change in the object array retrieved from GetCustomAttributes(), I changed the class with string comparing to get assembly's information. My second class can get AssemblyConfiguration() information.
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Globalization;
using System.Diagnostics;
// ...
public class AssemblyInfo2
{
private const string TITLE = "System.Reflection.AssemblyTitleAttribute";
private const string DESCRIPTION = "System.Reflection.AssemblyDescriptionAttribute";
private const string CONFIGURATION = "System.Reflection.AssemblyConfigurationAttribute";
private const string COMPANY = "System.Reflection.AssemblyCompanyAttribute";
private const string PRODUCT = "System.Reflection.AssemblyProductAttribute";
private const string COPYRIGHT = "System.Reflection.AssemblyCopyrightAttribute";
private const string TRADEMARK = "System.Reflection.AssemblyTrademarkAttribute";
private const string FILE_VERSION = "System.Reflection.AssemblyFileVersionAttribute";
private const string INFORMATION_VERSION = "System.Reflection.AssemblyInformationalVersionAttribute";

private Assembly _assembly;
private object[] _assemblyAttributes;

public AssemblyInfo2()
{
_assembly = Assembly.GetExecutingAssembly();
_assemblyAttributes = _assembly.GetCustomAttributes(true);
}

private T GetAttribute<T>(string typeString)
where T : class
{
List<object> objects = new List<object>(_assemblyAttributes);
object assemblyObj = objects.Find(
delegate(object item)
{
bool found = false;
if (item != null)
{
found = item.ToString().Equals(typeString);
}
return found;
});

return assemblyObj as T;
}

public AssemblyTitleAttribute Title
{
get
{
return GetAttribute<AssemblyTitleAttribute>(TITLE);
}
}

public AssemblyDescriptionAttribute Description
{
get
{
return GetAttribute<AssemblyDescriptionAttribute>(DESCRIPTION);
}
}

public AssemblyConfigurationAttribute Configuration
{
get
{
return GetAttribute<AssemblyConfigurationAttribute>(CONFIGURATION);
}
}

public AssemblyCompanyAttribute Company
{
get
{
return GetAttribute<AssemblyCompanyAttribute>(COMPANY);
}
}

public AssemblyProductAttribute Product
{
get
{
return GetAttribute<AssemblyProductAttribute>(PRODUCT);
}
}

public AssemblyCopyrightAttribute CopyRight
{
get
{
return GetAttribute<AssemblyCopyrightAttribute>(COPYRIGHT);
}
}

public AssemblyTrademarkAttribute Trademark
{
get
{
return GetAttribute<AssemblyTrademarkAttribute>(TRADEMARK);
}
}

public AssemblyFileVersionAttribute FileVersion
{
get
{
return GetAttribute<AssemblyFileVersionAttribute>(FILE_VERSION);
}
}

public AssemblyInformationalVersionAttribute InformationVersion
{
get
{
return GetAttribute<AssemblyInformationalVersionAttribute>(INFORMATION_VERSION);
}
}

public Version Version
{
get
{
return _assembly.GetName().Version;
}
}

public CultureInfo Culture
{
get
{
return _assembly.GetName().CultureInfo;
}
}
}

By the way, the Culture property is based on AssemblyCulture("") setting in AssebmlyInfo.cs. You just cannot set this information other than empty string "". I tried to change it to "en" or "en-US". The project just cannot be compiled. Actually, this is the property I tried to change and I tried to change project's property from "assembly information..." in Application tab, and then the order of attributes retrieved from GetCustomeAttributes() is changed. It's very interesting issue. I am not sure how the assembly attribute information are populated in the assembly.

Read More...

Friday, November 09, 2007

Blogger Template Issue

Today I tried to understand Blogger's template and then to reorganize my template for my blog. As I understand that the template is a html-like file. I can update this file so that I can add other elements such as RRS link I did previous.

Based on xml and html knowledge I have, I tried to change me template. Here is an example tags for blog title before my change:

<BlogItemUrl><a href="<$BlogItemUrl$>"
  title="external link"></BlogItemUrl>
  <$BlogItemTitle$>
<BlogItemUrl></a></BlogItemUrl>


These tags are not looks in right logic. Then I tried to change them as:

<BlogItemUrl><a href="<$BlogItemUrl$>"
  title="external link">
  <$BlogItemTitle$>
  </a>
</BlogItemUrl>


I thought the updated one is better. However, after I saved the new template, I lost my blog title! I had to change these codes back. Fortunately, I saved my template before I did the change. As Blogger suggested, Always back up your template before you make any changes!

By the way, this blog demonstrates an example of using a box for codes as seeing above. I introduced a css class "outlinebox" in my Blogger template:

/* Use this style as class ID for a box for some blocks such as div, p */
.outlinebox {
  width: 450px;
  border-color: #666666;
  border-style: solid;
  border-width: 1px;        /* sets border width on all sides */
  padding: 5px
  }

Then in my post, I used this class in a div like this:
<div class="outlinebox"><pre><code>
  some codes ...
</code></pre></div>

I also created another two css classes in my Blogger template: "outlinebox4wrappercodes" and "wrappercodes". These two css classes can be used in the same way to display additional horizontal scroll bar. Here is another example:
<div class="outlinebox4wrappercodes"><div class="wrappercodes"><pre><code>/* Use this style as class ID for a box for some blocks such as div, p */
.outlinebox {
  width: 450px;
  border-color: #666666;
  border-style: solid;
  border-width: 1px;        /* sets border width on all sides */
  padding: 5px
  }</code></pre></div></div>

Read More...

Blogger Template Issue

Today I tried to understand Blogger's template and then to reorganize my template for my blog. As I understand that the template is a html-like file. I can update this file so that I can add other elements such as RRS link I did previous.

Based on xml and html knowledge I have, I tried to change me template. Here is an example tags for blog title before my change:

<BlogItemUrl><a href="<$BlogItemUrl$>"
  title="external link"></BlogItemUrl>

  <$BlogItemTitle$>

<BlogItemUrl></a></BlogItemUrl>


These tags are not looks in right logic. Then I tried to change them as:

<BlogItemUrl><a href="<$BlogItemUrl$>"
  title="external link">

  <$BlogItemTitle$>

  </a>
</BlogItemUrl>


I thought the updated one is better. However, after I saved the new template, I lost my blog title! I had to change these codes back. Fortunately, I saved my template before I did the change. As Blogger suggested, Always back up your template before you make any changes!

Read More...

Test callback delegate with Rhino.Mocks

Here is the case to test callback delegate by using Rhino.Mocks.

The following service class has a method with a delegate callback as parameter to get a list of products:

// somethere delegate is defined, Product is an another class
public delegate void RetrieveProductListCallback(
bool success, List<product> products);

// service class
public class ProductService
{
// ...
List<product> RetrieveProducts(
RetrieveProductCallbackHander callback)
{ //...
}
}

// Define a method which is used as delegate handler
private void ProductListHandler(bool success,
List<Product> products)
{ // ...
}

RetrieveProductListCallback callback = ProductListHandler;

_productService.RetrieveProducts(callback);


What I want to test this service's callback event. There were no direct information about this issue. I spent several hours googling information on web and tested many different ways. Finally I found a way to test the callback. Here is the summary of the tricks: using Last.Callback and Predicate to do the test. Here are some codes for the test:

[test]
public void ShouldGetAllProudctsFromService()
{
List<Product> products = new List<Product>();
// add some products to the list
bool success = true;
// define a none-null callback
RetrieveProductListCallback callback = delegate {};

using (Mocks.Record())
{
// expect to call method with callback
_productService.
RetrieveProudcts(callback);
// Here is the trick to set up callback
// to be called
LastCall.Callback(
(Predicate<RetrieveProjectListCallback>)
delegate(
RetrieveProductListCallback callbackhander)
{
if (callbackhander != null)
{
callbackhander(success, products);
}
return true;
});

// ...
}

using (Mocks.Playback())
{
// ... assert
}
}
}

Read More...

Sunday, October 28, 2007

Added RRS Feed to My Blog

Today I found a way to add RRS feed to my blog. You will find RRS and a link in my blog page on lower right side. I'll update my feed so that any subscribes can get updated posts on my blog.

I have been using RRS feed a lot for many web sites. It is very convenient way to access my favorite sites and read new posts/feeds. For example, I have added a RRS folder in my browser's Bookmark Toolbar. When I find a good site with RRS feed link, I always add the feed to my RRS folder. As a result, I can get latest updates on these pages when I open my browser.

BBloger provides a setting feature to add RRS. There is a Site Feed Tab in BBloger's settings. Based on the recommendation, I used FeedBurner to generate my feeds. I guess that I have to log in to the link to update my feeds whenever I update my blogs. Hopefully, you will like this feature if you are interested in my blog.

By the way, I have to add my RRS link manually from my blog template. BBloger's templates are very easy to update. There are many commented-out paragraphs in the template. I removed the comment tags and added my RRS text and link, then my RRS is available on my blog page. It's great and exiting to add this feature to my blog!

Read More...

Hide/Display Debug Fields for InfoPath 2003

I have been working on a InfoPath 2003 project for about one month. I have put some hidden fields on the form for debug or values which are used by some Rules but not for display purpose. At the beginning, I thought to use other visible fields as condition for their display condition since fields/controls do not have hidden property I can set directly. For example, I set those hidden fields' conditional format as hidden if other visible controls is present.

However, when I want to set those fields visible for debug purpose, it is very tedious to go to each control to enable their visibility, specially when there are many hidden fields. What I need is a quick way to set their visibility by one flag.

Finally, I found a way to do that. There is place I can set Rules for Form Open, that is the place I can set a variable or field to true or false. I named this field as SetHiddenFieldVisible as boolean. All the hidden fields/controls conditional format is changed to hidden if this var is false, or 1 = 2. This makes my debug much easier. By using this, I found several bugs. For example, some hidden fields were set as invalid values (string to a boolean value). Because they are hidden fields, I could not see the error when I got an error message. When I turn on the visible flag, I could see these fields marked as red right away.

By set some initial values when the Form is opened, I could set many initial values used later on in the form. This simplifies my Rules and Conditional Format settings, and it is easy to update.

Read More...

Friday, October 26, 2007

Great Tutorial Articls about CAB/SCSF

I posted a question to CodePlex's Smart Client Guidance Discussion on the difference between Items and SmartParts collections. I got very good post back to explain the difference.

At the same time, I found a post about CAB/SCSF tutorial articles by Rich Newman. This link provides great articles on CAB. I have been working on CAB for months. At first, I was lost about this complex application block framework. It is very complicated. It took me about one week to just get very basic understanding of these mysterious blocks. This link provides much clear explanation and description about CAB structure and patterns used. It is a great site!

Read More...

Thursday, October 04, 2007

Use Data Connection in InfoPath 2003

Recently, I was asked to work on an InfoPath form project. The form can be opened from a SharePoint intranet site. The form contains several parts to be filled by different people. The person who fills the form can select the next person from company's employee list to fill the next part. If the next person approves the application form, he/she will continue to fill the form and select another person for approval or to fill. If he/she rejects the form, the previous person will be notified.

I used a Drop-Down List Box control for selecting an employee. The DDL box is filled with employees by using a web service (RetrievingAllEmployees method). I set the binding Value to @Email (property of employee), and Display Name to @FullName. However, the problem is that I cannot use the selected employee full name (displayed in the DDLB) in the next part, for example, a Text Box, because the Value of DDLB is an email address.

I realized that in the same web service, there is a method called as RetrieveEmployeeByNetworkUserName, which takes NetworkUserName as an parameter to get an employee object back. I tried to add this as an Data Connection to the InfoPath form, but I did not know how to use, or how to set its parameter.

InfoPath is new for me. There are not much information available on the Web. I tried to post several help questions to Microsoft InfoPath Forum, but no answer yet.

After several hour tries and tests, I finally found a way to solve the problem, using this web service method with parameter as a Data connection. Basically, this data connection has two sets of data (through InfoPath GUI):


  • query fields which are mapped to methods parameters, ie, NetworkUserName, and

  • data fields as properties of returned object, ie, employee.

Base on this information, I figured out that I can use this connection dynamically with the DDLB's Rules (when an item is changed). I added a Rule to the DDLB with the following actions:

  • Set DDLB's value to the data connection's query field NetworkUserName,

  • Use Query Data Connection action with the data connection,

  • Set the data connection's @FullName property value to a text box, and

  • Set the data connection's @Email property value to another text box.

Whalla! This works perfectly. Of course, I changed the DDLB's binding Value to NetworkUser. By using the data connection with parameters, I can let use to specify an employee, and then the employee's information can be obtained easily!

Read More...

Saturday, September 29, 2007

Installation of Windows PowerShell

I just watched dnrTV show #82 Scott Hanselman on Windows PowerShell. This shell is really very cool one. I followed the instruction to install the PowerShell and PowerTab.

The installation of PowerShell is straightforward. After the installation, I added a shortcut of this program to my desktop.

PowerTab installation is very clear. The downloaded file is a zip file. Fortunately, the show explained the steps of installation. In the PowerShell console, type the following command to get the profile location:

$PROFILE
C:\Documents and Settings\[user name]\My Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1


The folder of "WindowsPowerShell" and the profile do not exist. I had to create the folder first. Then I unzip the PowerTAB to a folder called as PowerTAB there:

md WindowsPowerShell
cd WindowsPowerShell
md PowserTAB
cd PowerTAB


After dumping the zip file there, run the following command to set execution policy(first getting command usage):


Get-Help Set-ExecutionPolicy
Set-ExecutionPolicy Unrestricted


Then run the script to install the PowerTAB:


.\Setup.Cmd


Accept all the default settings, the PowerTAB is installed.

I am very impressed by the tool of PowerShell and the plugin PowerTAB. I think this is a must-have tool for .Net developers or programmers.

Read More...

Sunday, June 17, 2007

Building Solution Failure: binary files could not be created

Recently, I installed Ubuntu Linux desktop on my computer. Before the installation, I had Windows XP. I got a bigger hard drive and I did partition on HD as 2 partitions. I plan to set a dual boots system, one for my Windows and another for Ubuntu.

My previous HD also had two partitions, that was done by HP, one small one for backup systems. I used Norton Ghost to do a partition image of my Windows and after I install the new HD, I restored my windows. That safes me a lot of time to reinstall my application and configure my working environment. So far so good.

The Ubuntu was installed successfully, and it is very impressive. I am going to further to investigate the OS.

My Windows works fine. However, I encountered a problem while I was compiling a solution project. I got a message saying that "The volume does not contain a recognized file system, ...". The build was failed because the binary files could not be created. I checked my path. It is fine. The message is very misleading.

Finally, I figured out the problem. It is the environment var Temp. I set this one to my "D:\temp". After the dual OS systems was set up, the D: partition was not available any more. What I did is to format the missing partition D:. After that, all the temporary files can be created and there is no problem to build my solution.

Read More...

Signing a Solution for publishing

For publishing application by click-once to deploy, I found that I have to set all the assemblies or projects to sign with a key file (pfx). In the project which is the start one, you have to make sure the Certificate option is checked in project's property Signing tab and make sure this certificate was generated by the same key file. Otherwise, you will get an error message saying failure to run tool SignTool.

After every thing are built correctly, you may use internet explorer to link to the URL which was set in the solution's property (Publication Location). Click on Install to deploy the application. You may have download the setup.exe installation file first. You will get an application file such as Bankshell.application. Still you cannot run the application in your downloaded folder. You have find the file in your URL location, where you can click on Bankshell.application to install the application.

This is just a note for me as a reference. I got this problem while I was doing exercises of Lab 5: Building the End-to-End Global Bank Application, Patterns & Practices (CAB).

Read More...

Tuesday, May 08, 2007

Add Microsoft.Practices.CompositeUI.WinForms components to VS ToolBox

I installed Microsoft Pattern & Practices Composite UI Application Block (CAB) in my box (CBA_CS.msi). Howerver I could not find Microsoft.Practices.CompositeUI components in my VS Toolbox.

What I did is to Browser components from the dialog window and find the file (Microsoft.Practices.CompositeUI.WinForms.dll) in:

C:\Program Files\Microsoft SCSF\GuidancePkg\bin

Before I add these components, I create a tab in Toolbox "MSPP CompositeUI" and then add those components there.

Read More...

Saturday, May 05, 2007

DetailView/GridView/FormView and ObjectDataSource (APS.Net 2.0)

I found one thing interesting about web UI controls and ObjectDataSource control in APS.Net. The background story of this finding is that I tried to create a business logic layer (BLL) with a method to update some data in a database through those web UI controls.

My BLL, ProductsBLL, has a method UpdateProducts() with a list parameters corresponding some fields defined in a table Products, such as productName, unitPrice, unitsInStock, unitsOnStock, reorderLevel, etc. Somehow, I mistyped some field names in the parameter, for example, reorderLeve. That's OK. It is just a parameter for a cs class method.

I tried to configure my ObjectDataSource in an aspx page through ODS' wizard. The mistyped parameter name is auto-generated in aspx file as followings:

<asp:ObjectDataSource ID="ObjectDataSource" runat="server"
DeleteMethod="DeleteProduct" InsertMethod="AddProduct"
SelectMethod="GetProducts" TypeName="ProductsBLL"
OldValuesParameterFormatString="{0}" UpdateMethod="UpdateProduct" >
<DeleteParameters>
<asp:Parameter Name="productID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="productName" Type="String" />
<asp:Parameter Name="supplierID" Type="Int32" />
<asp:Parameter Name="categoryID" Type="Int32" />
<asp:Parameter Name="quantityPerUnit" Type="String" />
<asp:Parameter Name="unitPrice" Type="Decimal" />
<asp:Parameter Name="unitsInStock" Type="Int16" />
<asp:Parameter Name="unitsOnOrder" Type="Int16" />
<asp:Parameter Name="reorderLeve" Type="Int16" />
<asp:Parameter Name="discontinued" Type="Boolean" />
<asp:Parameter Name="productID" Type="Int32" />
</UpdateParameters>

In the web UI control(DetailView/GridView/FormView) section, I also used the same ODB control through GetProducts() methods in ProductsBLL, which returns a ProductTable with correct field names (for example, ReorderLevel). As a result, my aspx page got an expception when I tried to update a record. The exception's message is something like this:

ObjectDataSource 'ObjectDataSource' could not find a non-generic method 'UpdateProduct' that has parameters: ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, reorderLeve, Discontinued, ProductID, ReorderLevel.

Notice that reorerLeve and ReorderLevel appear in the error message. The first one is the one defined in parameter list, and the next one is the field in UI control. They have to be matched! Otherwise, they both are used to make a method call to ProductsBLL, which results method not matching exception.

In addition to this finding, I find that the case is not sensitive for matching parameter names to UI field names for updating. I hope it would be better in a UI field definition where you can use a new attribute to specify which parameter is matched for updating/editting/deleting. By explicitly specifying a parameter, there would no need to couple ProductsBLL method's parameters to UI field names.

Read More...