Saturday, July 28, 2007

Passed the 70-536 exam

Yesterday I've passed the 70-536 exam (TS: Microsoft .NET Framework 2.0—Application Development Foundation).

 To study the exam I've used the Microsoft Training Kit. The book is easy to read and has good practices. It covers all the topics discussed in the exam. Sometimes not in so much details but that is normal I guess.

The next exam that I'm going to do is 70-526 (TS: Microsoft .NET Framework 2.0 – Windows-Based Client Development). I could have choosen for the upgrade exam (MCSD to MCPD) but I prefer to do the exams one by one. This gives me an extra review on things that I don't use that often.

Wednesday, July 25, 2007

Windows Live Writer: creating blog entries in just a few seconds

In a previous post I've mentioned the possibilities of Word 2007 to create new blog entries. A colleague of me informed me about a tool names Windows Live Writer which is a tool created by Microsoft to create blog entries. After testing it for a while, I'm now using Live Writer as my primary blogging tool. You can download it here (currently in Beta).

Especially in combination with the free SyntaxColor4Writer plug-in, creating posts that contains code is no longer a time consuming job. The plug-in allows you to add code to your blog without having to worry about the colors and formatting.

Currently it supports 20 different formats including C#, VB.NET, HTML, XML, SQL, ...


Create a function that returns a table

In SQL Server it is easy to create a function that returns a table when used in the from clause. In Oracle this is not as easy as it seems but since my current client uses Oracle, I was forced to find a solution so here it is.

To create a function that returns a table in Oracle you need to follow a few steps:


  • Create a type that corresponds to a single record
  • Create a type that corresponds to a table and that has the previously declared type as recordtype
  • Create the function
To use the function, you need to include it in the TABLE() function.

Here is an example on how to do it:

  • First I create a simple table that will be used for the sample.
    -- Create a dummy table to show how it works.
    --
    The table contains a hierarchy between boss
    --
    and employee.
    CREATE TABLE employee
    (
    emp_id
    NUMBER(10),
    full_name
    VARCHAR2(50),
    emp_boss_id
    NUMBER(10)
    );

    -- Insert dummy data:
    INSERT INTO employee VALUES (1, 'Geert Verhoeven', null);
    INSERT INTO employee VALUES (2, 'Ford Parker', null);
    INSERT INTO employee VALUES (3, 'Al Bino', 1);
    INSERT INTO employee VALUES (4, 'April May', 1);
    INSERT INTO employee VALUES (5, 'Abbie Birthday', 3);
    INSERT INTO employee VALUES (6, 'Gene E. Yuss', 3);
    INSERT INTO employee VALUES (7, 'Juana Bea', 3);
    INSERT INTO employee VALUES (8, 'Willie Maykit', 4);
    INSERT INTO employee VALUES (9, 'Zoltan Pepper', 4);
    INSERT INTO employee VALUES (10, 'Scott Shawn DeRocks', 4);
    COMMIT;

  • Then I create the types needed to be able to return a table
    -- Create a type that corresponds to a row that you want to have returned.
    CREATE TYPE ind_employee AS OBJECT (emp_id NUMBER(10), full_name VARCHAR2(50));
    --
    Create a type that corresponds to a table of rows with the specified type.

    CREATE TYPE ind_employee_table AS TABLE OF ind_employee;
  • After this is done, you can create a function that returns a table.
    -- Create the function.
    CREATE OR REPLACE FUNCTION FN_GET_EMPLOYEE_DESCENDANTS (
    pin_emp_id
    IN NUMBER
    )
    RETURN ind_employee_table PIPELINED
    IS

    TYPE t_ref_cursor
    IS REF CURSOR;
    lc_employees t_ref_cursor;
    lr_out_rec ind_employee :
    = ind_employee(NULL, NULL);

    BEGIN
    OPEN lc_employees FOR
    -- The connect by prior handles the hierarchy.
    SELECT
    emp_id,
    full_name
    FROM employee
    START
    WITH emp_id = pin_emp_id
    CONNECT
    BY PRIOR emp_id = emp_boss_id;

    LOOP
    FETCH lc_employees
    INTO
    lr_out_rec.emp_id,
    lr_out_rec.full_name;

    EXIT WHEN lc_employees%NOTFOUND;
    PIPE ROW(lr_out_rec);
    END LOOP;
    CLOSE lc_employees;
    RETURN;
    END;

    REMARKS: The PIPELINED command and PIPE ROW() method, work together to make sure that each row is returned to the caller immediately after it is processed. This helps to avoid having big objects in memory.

  • To use the function, you need to use the TABLE() function.
    -- Sample query:
    SELECT * FROM TABLE(FN_GET_EMPLOYEE_DESCENDANTS(1));

  • This gives the following results:
    EMP_ID FULL_NAME

    1 Geert Verhoeven
    3 Al Bino
    5 Abbie Birthday
    6 Gene E. Yuss
    7 Juana Bea
    4 April May
    8 Willie Maykit
    9 Zoltan Pepper
    10 Scott Shawn DeRocks

Thursday, July 19, 2007

How (not) to create a deadlock with the Thread.Join() method

In one of my projects I needed to be able to execute multiple tasks at the same time and show the results when all the tasks were finished.

The tasks included updating of the user interface. Since you cannot update a control on the user interface from a thread different than the thread that owns the control, you need to use the Control.Invoke method.

Control.Invoke(delegate method) executes the specified delegate on the thread that owns the control. So this way, you can have a second thread make a call to the main thread to update the user interface. So far so good.

The goal was to load multiple datasets in different threads and call a Control.Invoke for each dataset to bind it to a control on the form. After all the threads were finished, I wanted to show the form to the user. 

To be able to check that all the threads were finished, I used the Thread.Join() method. This method blocks the main method until the thread finishes. If you create a loop that loops through all the threads you started and call Thread.Join() you are sure that all threads have finished.

The issue with this is that Thread.Join() blocks the main thread. So it also blocks the calls made via Control.Invoke. This is why you can't use Thread.Join() in combination with Control.Invoke. Pretty logic but if you don't realize what is going wrong, you can spent quite some time on it.

References:

Tuesday, July 17, 2007

Blogging with Office 2007

Since a few days I'm using Word 2007 to create new blog entries. I've tried several utilities to add new blog entries but was always struggling with the layout. After doing a few tests, I'm very pleased with Word 2007. The only pity is that since I'm using Blogger, I can't upload images and don't have the possibility to add tags (Categories).

Here is a link on how to get it started http://spsfactory.blogspot.com/2007/03/blogger-is-integrated-in-microsoft.html.

Monday, July 9, 2007

Add a new code group based on a .snk file by using the caspol command line

For one of my projects, I needed to be able to give the FullTrust permission to my smart client applications. Since all the applications created at the client are signed using the same strong name key, I've used this to set up the security requirements.

Normally I would use the ".NET Framework 2.0 Configuration" but not all the user's have the .NET Framework SDK installed (which includes the configuration tool), I used the caspol.exe command line to set the security permissions.

Since it took me quiet some time to get all the parameters right, I thought to give you a head start by posting the commands.

Steps to follow to add a new code group that gives fulltrust to all applications signed by a given snk file. In order to add the strong name to the security policies, you either need to have a signed dll/exe or the snk file. The below sample uses an .snk file.

  1. Extract the public key from the .snk file (in this case Sample.snk) by using the sn.exe tool:

    sn -p sample.snk sample.pk

  2. Now you need to have the hex value of the public key (saved in sample.pk). Since notepad doesn't support the format of the .pk file, you need to have a hex editor to open it. I used the free HxD tool which has all the features you need (http://mh-nexus.de/hxd/).

    Open HxD.exeOpen the sample.pk file and copy the hex value.


    3. The following command creates the new key in the machine security policy:

    caspol -machine -addgroup 1 -strong -hex "0024000004800000940000000602000000240000525341310004000001000100DDEEAD8B27321D3FB0E872FABDFA62627CCA03864AF3F7A19C6D978788F5DCD89BEFD1B897BAC5C74253091FB6747E2723D5239B802F074B1AC930A9C187D52FCF3ED65AF467F4F656F392CF5E6E2FF69071C398EA931B2EB862F6CE832350B24A6524F06F9F5F630A2B00B30F59A87BC847989D2D09DDD7A49BE92FE2EFB5B2" -noname -noversion FullTrust -name "Code Group Name" -description "Code Group Description" -exclusive on

    The hex key can not contain any spaces or carriage returns so you need to remove them from the copied result.


References:

Friday, July 6, 2007

Problems when signing my ClickOnce application

When I tried to sign my ClickOnce application, I received the following error:

Unable to find manifest signing certificate in the certificate store.

I’ve noticed that even after removing the sign option in the project properties page, the .csproj file (opened with notepad) still contained parameters indicating that the application needed to be signed.


<SignManifests>true<SignManifests>
<ManifestCertificateThumbprint
>ACBE668D16D794DA9E35301D49C834864C4D9C2A<ManifestCertificateThumbprint>
<ManifestKeyFile>GuiWinApp_TemporaryKey.pfx<ManifestKeyFile>

After removing these lines of code and reselecting the .snk file in the property pages, everything worked fine.