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

Thursday, January 19, 2006

Array var in Managed(.Net) C++

In managed C++, define an array variable for a managed class, in syntax, is different from standard C/C++. For example,


using System::Drawing;
//...
array<PointF, 1>^ pointsF = gcnew array<PointF, 1>(100);
// PointF pointsF[100]; // is wrong
// PointF pointsF[] = gcnew PointF[100]; // is wrong
//...
pointsF[0].X = 11.23f;
pointsF[0].Y = 0.54f;


where PointF is a structure defined in System::Drawing namespace.

For String class, you have define an array of String as:


array<String^, 1>^ s = gcnew array<String^, 1>(10);
//String^ s[] = gcnew String^[10]; // wrong again


The general format to define an array of type is:


[qualifiers] [cli::]array<[qualifiers]type1[, dimension]>^ var =
gcnew [cli::]array<type2[, dimension]> (val[,val...])


See MSDN on Array Keyword

Read More...

Wednesday, January 11, 2006

Windows Installer Problem

Some times I got anoying error messages when I tried to open some applications such as VB6.0. The message is like a dialog window with the message:

Setup is aborting now. Cannot detect file: mediainfo.ini


This is caused by Windows Installer when I tries to find some files based on Registry settings. For example, I removed some binary files which were installed by Windows Installer but I could not find Uninstaller for those files or I could not run uninstaller successfully.

Here are some steps to avoid these messages:

Locate missing files

  • Open Event Viewer from Administration Tools.
  • View property for the most recent warning messages in Application node, and make a note of missing file, for example, "C:\MyTools\Bin\Interop.Utility.dll".
Search for Registry settings for missing files
  • Open RegEdit
  • Locate to "My Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer"
  • Search for the file with path found above. Note, do not include drive like "C:" in the search string.
  • You should find a key like this: "...\UserData\S-1-5-18\Components\D1311F8CC3D78BB42BCF6A". Under this one you will find a key Item with a value like "C?\\MyTools\Bin\Interop.Utility.dll".
Change Reistry Settings
  • What I do first is to find the missing files and copy them to a folder like "C:\MissingFiles\Installer\"
  • Then I change the registry key item's value to "C?\MissingFiles\Installer\Interop.Utility.dll".
After I change all the registry items for these missing files, I will not get warning message any more.

I am not sure if I should remove these registry keys or not. For safe purpose, I try to find missing files and udpate registry instead.

Read More...

Friday, November 04, 2005

WMI class

Here are two entries I posted to my Yahoo blog, regaring the problem of using WMI class to query memory stat and a solution in case of memory > 4GB.

Problem of using WMI class to query memory stat when memory size > 4GB.

A solution of getting memory stat.

I change to Blogger to continue my posting because I found that Yahoo's blog does not have tag feature.

Read More...