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...

Friday, April 27, 2007

DataSet 2.0 Issues

When I tried to use Visual Web Developer 2005 Express to compile a project with TypedDataSet, I got some warning message for compling. Basically, these warning messages are about some XML attributes for DataSet not being declared. For example:

Warning 2 The 'ParameterPrefix' attribute is not declared. G:\Datadc\Programming\ASP.Net\Data Tutorials\DT01\App_Code\Northwind.xsd 8 231 G:\...\DT01\

I googled solution to find out why and to remove these warning. Here is a link about this issue. In short, these attibutes are not defined in VS IDE's xsd file. I could to add these attributes there but it is not recommended. Steve Cheng from Microsoft Online Help said that you can ignore these messages and the build should be fine.

That's a good explaination for this issue.

Read More...

Tuesday, April 24, 2007

SQL 2005 Express error regarding generating new instances

Recently, I installed Microsoft SQL 2005 Express. Late on, I encounted a problem to open a database from Visual Web Developer 2005 Express. The error message is something like:

Generating user instances in SQL Server is disabled. Use 'user instances enabled' ...

I think the problem was caused by my installtion of SQL-Tools for adding Reporting services. I googled through web and found a solution to solve the problem from this link MSDN143684. Here are some steps:

  1. Open Microsoft SQL Server Management Studio Express
  2. Open a query and type in: Select * from sys.dm_os_child_instances. This will list all the users instances.
  3. Comment out the above line. Type in the commands:
sp_configure 'user instances enabled','1'
RECONFIGURE;
GO

Then open a project in VWD, and try to open a db again. The db was opened without error message.


I think there is a configuration in SQL to set either shared DB or new instances. If it is shared DB, no new instances are created.

Read More...

Monday, April 23, 2007

SQL Server Report Service Installation

Here are my nodes about installation of SQL Server Report Service.

My OS is Windows XP Pro. I installed .Net 2.0 Framework for learning ASP.Net purpose. Then When I needed SQL Server Report Service and Report Studio for creating report projects, I had to install IIS 5.1.

After I installed IIS5.1, then I installed SQLEXPR_ADV.exe which includes SQL Report Service. I got a program to browse //localhost/Reports/. The error message is "Failed to access IIS metabase".

The problem is caused by the fact that .Net 2.0 and ASP.Net 2.0 was installed before IIS. The solution is to run aspnet_regiis.exe in a cmd console (at .Net framework 2.0 folder):

aspnet_regiis -i

what this one does is to install and configure APS.Net 2.0 again. After that, the problem is solved!

One IIS related issue: do not use IP number in IP Adress (IIS configuration tool for Detault Web Site). It should be (All unassigned). I think the reason is that I don't fix IP and my IP is dynamically assigned through my router.

Through IIS configuration tool (from Control Panel|Administration Tools or MMC), you can set/add virtual directory, how to access the web page, and what is the default page. Many more settings can be done there.

Report Service configuration problem: use the tool from Microsoft SQL Server 2005|Configuration Tools|Reporting Service Configuration. Make sure all the settings are correct (checked V). I did not set Reporting Service Virtual Directory because it was checked V. However, it was not set and empty. After I accepted the default settings. My SQL Reporting Service page (//localhost/Reprots/) is opened!

Read More...