Thursday, February 24, 2011

Why validators error messages not displayed in Google Chrome?

I asked myself several times. Why are validators error messages not displayed in Google Chrome? It is weird. Not a single validation error message is displayed in the page as soon as the following CSS is added. It works well with IE, Safari and Mozilla-type browsers but fails on Google Chrome.

  div.sink {padding:20px; width: 190px;border:1px silver solid;}
  div.sink input[type="text"]{width: 190px;}
  div.sink input[type="submit"]{width: 50px;}

I am sure that all the validators are fired and the page as a result reports invalid but there is no error message. There is no doubt that the problem is somehow related to the above CSS. To reduce the complexity of the page and easily to nail down the problem, I marked up a simple login page for investigation.

login page

With a bit modification, the page looks like this - very simple, only text boxes, RequiredFieldValidators and a login button. There is no code behind (no OnClick event) and they are straightly marks up.

<head>
<style type="text/css">

div.login {padding:20px; width: 190px; border:1px silver solid;}
div.login input[type="text"], div.login input[type="password"]{ width: 190px; }
div.login input[type="submit"]{width: 50px;}

</style>
</head>
<body>
<form id="form1" runat="server">
<div class="login">

  User Name:<br />
  <asp:TextBox id="txtUsername" runat="server" MaxLength="30"></asp:TextBox><br />     
  <asp:RequiredFieldValidator ID="RequiredFieldValidatorUsername" runat="server" 
       ControlToValidate="txtUsername" Display="Dynamic" 
       ErrorMessage="A username is required."></asp:RequiredFieldValidator><br />

  Password:<br />
  <asp:TextBox id="txtPassword" runat="server"  TextMode="Password" MaxLength="180" ></asp:TextBox><br />     
  <asp:RequiredFieldValidator ID="RequiredFieldValidatorPassword" runat="server" 
       ControlToValidate="txtPassword" Display="Dynamic" 
       ErrorMessage="A password is required."></asp:RequiredFieldValidator><br />

 <asp:Button ID="btnLogin" runat="server" Text="Log In" /><br />

</div>
</form>
</body>

With the above markup, the error message is shown at least for the User Name, unlike my problem page. The funny is that in this simple example, only the last validator won't be able to display error message if I keep adding more the similar control and validator. For sure, everything works normal if the CSS is removed.

No error message for the only and one validator

no error message for the only and one validator
No error message for the last validator
screen 1

no error message for the last validator - screen 1
No error message for the last validator
screen 2

no error message for the last validator - screen 2
No error message for the last validator
screen 3

no error message for the last validator - screen 3

The CSS is not complex. As a matter of face, it is very simple. What it does is to set the width for the input box or button in the page. To resolve this, I can simply add the width back to the control inself by removing the CSS. However, I cannot do it with my original page. Most controls are from user controls which won't allow me to set width. In addition, If I manage to add the width to them, the changes will affect other pages across the entire project unless I do it programically instead of static. It means I have to go in every single user control to add some code so that it can accept width change. I don't think that I want to go this route.

After playing around for some time, I finally found out the problem. The problem is the width setting in the first line.

  div.login {padding:20px; width: 190px; border:1px silver solid;}
  div.login input[type="text"], div.login input[type="password"]{ width: 190px; }
  div.login input[type="submit"]{width: 50px;}

Adding 4 more pixels fixes the problem!

  div.login {padding:20px; width: 194px; border:1px silver solid;}
  div.login input[type="text"], div.login input[type="password"]{ width: 190px; }
  div.login input[type="submit"]{width: 50px;}

It appears to me that Google Chrome browser cares about the outer width of the DIV when a CSS is specified. Most browsers may ignore it if the outer DIV is not width enough for its child components. From this instance, I learn that I need to pay attention to declare my CSS in order to prevent this from happening.

Saturday, February 12, 2011

Resource interpreted as image but transferred with MIME type text/html

One of my pages failed on Google Chrome. Because of the subject error, I could not debug it with Chrome debugger. The script won't be loaded into the debugger if the page is interpreted as an image. I wonder why and what caused it and I could not ignore it.

After hours looking into the code, I finally found the problem. In my case, I forget to include a JavaScript library reference in one of my user controls. As soon as I added it back, the error is gone and the page can be loaded into the Chrome debugger as other normal pages. Everything works fine.

Although the error message from Chrome is confusing, it at least alerts me that there is something wrong in my page. I am glad I found the problem and fixed it.

Why page events get called twice?

There are a lot of discussions about why the Page events get called twice or even multiple times. Most the solutions from Google search suggested to set AutoEventWireup to false. By default, it is true. Is it really helpful? For sure, a lot of people will disagree. Me either. The solution of AutoEventWireup doesn't stand for all cases. To me, most of the time, this issue is related to image resource.

Consider the following HTML code in the ASP.NET page markup.

<img src="" id="img1" alt="an image" style="display:none" />   cross

The HTML is valid but it is the trouble maker in ASP.NET Web form, which causes the page events being called twice because the src attribute is empty. Removing the src attribute entirely will fix the problem.

Let's consider another image related scenario. What if you want to set a background color in a table cell but mistakenly put background attribute instead of background-color?

<TD background="#008080">   cross

In this case, page events are also being called twice. But if HTML color name is used, everything will work fine. Thus the following HTML code won't cause trouble although it is not correct.

<TD background="Teal">    tickquestion mark

I am not quite sure how or when CalliHelper.EventArgFunctionCaller will bind the above scenarios to the page events. None of them are declared to run as server. But I do know that if the page events are being called twice, the first thing I will check is the markup, especially those HTML codes related to image resource.

Using From Target Attribute

[ Scenario ] [ The Solution ] [ Implemented with JavaScript ] [ Implemented with JQuery ] [ The Code ]

Problem Statement

A page may have several links and buttons to produce different forms of outout. Every single piece of data defined in the page including the input supplied by the user is needed for postback process. Is there a simple way to redirect the output in another window without overriding the current page so that the current page content stays perisistent?

Solution 1: Can we use target attribute of the element?

For a hyperlink, you may think using target attribute to accomplish this. With this approach, you have to gather all the needy input yourself from the current page into the querystring of the URL before posting data back to the server. This will introduce you another problem: querystring size limitation. Different plaforms and browser types have different limitations. Least to say, there is some work to be done in the client side. In addition, your server page must be configured and coded to handle HTTP GET to process the request.

For input button, we are out of luck. There isn't a target attribute defined in the specification. Thus, the action is completely relying on the form action.

Solution 2: How about AJAX?

Another approach to resolve this is using partial page rendering that would provide better user experience by eliminating the full page round trip overhead. Does it really matter in our case if we need every single piece of data defined or entered by the user in that page? It may save some overhead on some resources being loaded. Other than that, every data specified in that page is still posted back to the server for process. What we want is the output in another window so that the user may continue to use the same data to generate another form of output in a separate window and so on. Indeed, using AJAX is a bit complicated here. Of course, you may use some library like JQuery to set up your AJAX calls. For ASP.NET, you can simply accomplish this by using ScriptManager and UpdatePanel. Unfortunately, all of them require you to re-architect your page to accommodate the changes. To me, it is too much work. I need something simpler and make changes as least as possible in the page.

The Ultimate and Simple Solution: by using target attribute of the form.

The solution is to use the old trick defined in HTML with a little Javascript assistance.

In order to post data back to the server, we need a form tag. We usually don't specify the target attribute. In this case, the data is returned to the current page by default. If a target attribute is specified in the form tag, the output will be automatically routed to the specific frame or window by the browser when the data is returned by the server. For example,

Route data to a new window:

<form name="form1" id="form1" target="_blank" method="post" action="Default.aspx" onsubmit="..." >
...
</form>
</pre>

Route data to an iframe:

<form name="form1" id="form1" target="myIframe" method="post" action="Default.aspx" onsubmit="...">
...
</form>
<iframe name="myIframe" id="myIframe" width="400" height="300"></iframe>

Note that the name attribute of the iframe is required in this case. By specification, we should specify the_name_of_the_frame_or_window to the target attribute, not the_id_of_the_frame_or_window. But the id works for some Webkit type of browsers like Google Chrome.

With this simple solution in mind, I finally come up a way to unpuzzle the above problem with a very minor change in the page. The following is the solution presented in ASP.NET. The technique can be applied to elsewhere such as a simple HTML/CGI program.

What I need to do is dynamically adding a target attribute to the form before the data is being posted back to the server.

JavaScript Solution

First, let's define the script which does the injection. The JavaScript function may look like the following.

  function changeFormTarget() {
    var formObj = document.getElementById('form1');
    formObj.setAttribute('target', '_blank');
  }

What the above code does is, before posting data back to the server for process, it injects the target attribute into the form element by producing the following HTML code, which instructs the browser where to output the next document.

<form name="form1" id="form1" target="_blank" method="post" action="Default.aspx" onsubmit="...">

Then, we hook this function to the onclick event of the element before form submission. In ASP.NET, simply add OnClientClick event on the control to instruct the ASP.NET engine to process the client script first before postback.

<asp:LinkButton ID="lnkRptToNewTarget" runat="server" OnClientClick="changeFormTarget()" OnClick="RptToNewTarget_Click">Generate Report to New Target</asp:LinkButton><br />
<asp:Button ID="btnRptToNewTarget" runat="server" OnClientClick="changeFormTarget()" OnClick="RptToNewTarget_Click" Text="Generate Report to New Target"  />

The above markup will result in the following HTML code:

<a onclick="changeFormTarget();" id="lnkRptToNewTarget" 
   href="javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("lnkRptToNewTarget", "", true, "", "", false, true))">Generate Report to New Target</a><br />
<input 
   type="submit" name="btnRptToNewTarget" id="btnRptToNewTarget"
   value="Generate Report to New Target" 
   onclick="changeFormTarget();WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("btnRptToNewTarget", "", true, "", "", false, false))" />

As you can see, with the very minimal changes in the page, a new window will be spawned off from the current page when the result is back.

JQuery Solution

If you're using JQuery, the solution is even simpler without changing any element in the page. Simply put the following script and then the onclick event will be automatically wired to the appropriate elements. In my example, simply ask JQuery to scan my elements and then wire them up with my supplied onclick event.

  $('#lnkRptToNewTarget,#btnRptToNewTarget').click(function() {
    $('form').attr('target', '_blank');
  });

With JQuery, basically the page remains intact without any markup or element being changed. The result is the same as JavaScript approach. Of course, you can write your own auto event wire up to achieve what JQuery does but there will be a lot of work.

Sometimes a simple solution works like a charm and it also eliminates the time to re-test and shortens the development time. I hope you will find this piece of information somehow useful.

The Code

If you want to test it yourself and see how this works, here is my simple backend event handler for output. In real life, the handler could be in another process which generates PDF or other non-HTML types of documents, and then call Response.Redirect() or Response.TransmitFile() to return the document to the client.

  protected void RptToNewTarget_Click(object sender, EventArgs e) {
    Response.Write(
      string.Format("Your report <b>{0}</b> is generated.", this.txtReportName.Text));
    Response.End();
  }

Here is the markup for JQuery approach. You can simply alter it to JavaScript solution that I discussed above.

<form id="form1" runat="server" defaultfocus="txtReportName">
<div>
  Enter Report Name: <br />
  <asp:TextBox ID="txtReportName" runat="server"></asp:TextBox>
  <asp:RequiredFieldValidator ID="RequiredFieldValidatorTxtReportName" runat="server" 
       ErrorMessage="Please enter the report name." Display="Dynamic" ControlToValidate="txtReportName"></asp:RequiredFieldValidator><br />
  <asp:LinkButton ID="lnkRptToNewTarget" runat="server" OnClick="RptToNewTarget_Click">Generate Report to New Target</asp:LinkButton><br />
  <asp:Button ID="btnRptToNewTarget" runat="server" OnClick="RptToNewTarget_Click" Text="Generate Report to New Target"  />
</div>
</form>

<script type="text/javascript">
  $('#lnkRptToNewTarget,#btnRptToNewTarget').click(function() {
    $('form').attr('target', '_blank');
  });
</script>

Sunday, January 23, 2011

RealPlayer Free Version Offline Installers for Version 14.0.1.609

Do you have a hard time to locate RealPlayer Free version installer for offline use? Let me share some standalone installers URLs that I discovered for specific regions and languages. How to discover the offline installer download URLs is presented at the end of this post.

English - United States
English - United Kingdom
Traditional Chinese - Taiwan
Simplified Chinese - Mainland China
Japanese - Japan
Deutsch - Germany
French - France

RealPlayer Version:   14.0.1.609
Installer File Version:  12.0.1.609

If you don't care the latest version of RealPlayer and don't mind using a version older, you can simply go RealPlayer old version page for download. This page offers older standalone installers for offline use including all supported languages.


URL Patterns

Looking at the URLs, I found that only the first two query strings are the keys for getting offline installers.

Every URL straightly follows the same pattern (except for English US. The main difference between them is the distcode, which consists of the version (i.e., R61) and the language or region code (i.e., UK, TW, CN, JA, DE, and FR) and plus a character D. Anyway, you should get what I mean and go figure out for other regions if you're interested.

How to Find out Where to Download Offline Installer

  • Go to the Real Website in your region
  • Download the Web version. Free version won't ask you for email address. If so, you're downloading the wrong version. Some regions may say a basic version instead of free.
  • Ensure no Internet connection and then run the Web installer.
  • Wait until its error out. It will take a while, possibly about 3 minutes.
  • As soon as the Web installer gives up, it will offer you a re-download RealPlayer option. Click that button and then the Web installer will bring up the download URL at the browser.
  • Grab the URL and go Internet for download

Adobe Reader Offline Installers

The easy way to download an Adobe Reader standalone installer for offline use is to get it from Adobe FTP site. And then choose your OS, your desired Adobe version, your language and then download.

Note that sometimes browsing/accessing to the Adobe ftp site is a bit slow.

As of today, the current version is still Adobe Reader 10 (as known as Adobe Reader X). The followings are some links for Adobe Reader v10.0.0 in some languages used on Windows.

Major Adobe Reader Supported Platforms

Windows offline Adobe Reader Installer
Apple Machintosh offline Adobe Reader Installer
Unix/Linux offline Adobe Reader Installer
Android mobile device offline Adobe Installer

For Adobe Reader news update, you can visit their blog.

Monday, January 10, 2011

Registry Mechanic vs AML Free Registry Cleaner

Despite all the good reviews about PC Tools Registry Mechanic, I am disappointed by it.

I don't use registry cleaner but lately I would like to try it out and possibly find one to add into my collection. Under google search, Registry Mechanic by PC Tools is highly recommended by most reviews I have read. Unfortunately, I would not recommend it.

I did a very simple test myself a week ago on one of my virtual machines. This machine is always abused to use for bit torrent, software tryout, far-sites movie watching and etc. Thus I know its registry could be a mess. Because it is a virtual machine, it will be easy for me to recover it if something goes wrong during this registry test. In the course of searching good registry cleaner, AML Free Registry Cleaner is another good one on my mind. Thus, this test is Registry Mechanic vs AML. If you seek for professional opinions on registry cleaners, you may have to go some place else. Here is simply my opinion.

Registry Mechanic vs AML Free Registry Cleaner:

Test Targets Registry Mechanic AML Free Registry Cleaner
Version 10.0.134    (currently also known as
Registry Cleaner 2011)
4.21
Price Free to try
(First 6 sections repairing trial);
$29.95 to buy
Free

Test machine: Windows XP SP3.

Test Results based on problem found and detected:
Registry Mechanic 2011: 150 problems found
AML Free Registry Cleaner: 327 problems found

I went ahead to fix all problems found by AML and run the test twice (before and after reboot). Both results are the same and shown below:

Registry Mechanic 2011: 17 problems found
AML Free Registry Cleaner: 0 problem found

I don't find any abnormality after the fix by AML. Everything is working fine.

I cannot use Registry Mechanic to fix all problems it found because of its trial version restriction. However, I did something else interesting that may be an interest to you.

At pctools site, it features Registry Mechanic 2011 supports 17 languages but there is no further information about which languages it actually supports (or I could not find this information nor separate installers for other languages). When I installed it, it would not present me a language selection. I was curious how well its language detection was. Since that XP installed in this virtual machine is a multilingual version, I started fresh and switched to Traditional Chinese to test its language detection.

Why Traditional Chinese? Most software cannot handle well Traditional Chinese. They usually mistake the OS as Simplified Chinese if they try to be smart without letting the user to make a choice. Registry Mechanic suffers the same problem.

Similar to AML, the installation of Registry Mechanic is simple and straightforward. AML supports English only while Registry Mechanic claims to support multiple languages. Unfortunately it won't present you a language selection and it tries to be smart to use the language to match your OS. Sometimes it is not what you want. The worst is that it could present you a wrong UI language. Registry Mechanic mistakenly presented me everything in Simplified Chinese while my OS language is in Traditional Chinese. Because of this problem, some characters on screen are garbags.

As I mentioned before, I could not find the details of which 17 languages Registry Mechanic supports. Based on my test, it doesn't support Traditional Chinese but Simplified. To me, it is a serious problem for a software (which claims to support multiple languages but provides no language selection) to present the wrong UI language. Indeed, a lot of users would prefer to choose their languages.

There is one thing that annoys me most I found with AML Free Registry Cleaner. When it starts, it is always in a maximized mode. I personally don't like it. There is no way to configure AML to remember my preference. Other than this, I am fond of AML.

AML Free Registry Cleaner comes with free Disk Cleaner option. At first, I was surprised it found a lot of tmp files while CCleaner reported nothing about them. Later, I found that those tmp files are created everytime I reboot. Thus, I won't be able to get rid of them because they could be used or created by the system or the software (like anti-virus) you installed. They are needed whenever the system restarts. Thus, AWL Disk cleaner at this case is no use.

Conclusion

Between Registry Mechnanic and AML, I would highly recommend AML Free Registry Cleaner. The most importances are that AML detects more problems than Registry Mechanics and it is free!

Sunday, January 9, 2011

Impressive PDFCreator File Size Optimization

I have been using both PDFCreator and PrimoPDF for 3+ years. I mainly use them as a PDF converter and a virtual printer. I personally like PDFCreator most. But PrimoPDF can handle/convert some Web pages that PDFCreator cannot. To me, they both compensate each other. However, I have never paid attention to the PDF file size generated by them until recently. PDFCreator definitely is the winner. If anyone looks for a good PDF compression tool, I would highly recommend PDFCreator.

The following table presents you the file sizes generated by PDFCreator, PrimoPDF and GIRAC freewares from Microsoft WORD 2003 which doesn't contain images.

MS WORD 2003 with no image73KB
PDFCreator35KB
PrimoPDF124KB
GIRAC123KB

As you can see, PDFCreator file size optimization is the champion.

Updated on Jan 27, 2011:

Today I need to convert a document from WORD to PDF. The document is embedded with a tiny image. I used both PDFCreator and PrimoPDF for comparison to see which one does a better job. As expected, the PDF by PDFCreator results in very small size. But this time, the PDF made by PrimoPDF is a bit huge.

MS WORD 2003 embedded with a tiny image69.5 KB (71,168 bytes)
PDFCreator47.2 KB (48,388 bytes)
PrimoPDF1.18 MB (1,245,833 bytes)

Wednesday, January 5, 2011

Facebook Hidden Privacy Setting for Wall Posts by Friends

On April 7, 2010, I mentioned one of the confusing privacy settings Who can see posts made by friends? As of today, the setting was reworded a bit and honors your wish. Unfortunately, this setting is still the gatekeeper which controls who can post to your wall regardless of your specific setting.

If you go into your Privacy Settings | Customize Settings page, scroll down a bit, you will see the similar setting below.

can_see_posts_by_friends

What happens when I change the setting Can see Wall posts by friends to Only Me and leave Friend can post on my Wall unchanged, still enabled?

  • Yes, my friends will only see my posts when they visit my wall.
  • Unfortunately, their privilege to post to my wall is also taken away. The post box in my wall is no longer available to them.

It looks to me that Can see Wall posts by friends setting takes precedence. Previously, we could not use this to filter wall posts by friends. Now Facebook fixed it but it doesn't fix the wall post control. This setting still controls who can post to your wall.

If you play games at Facebook and rely on your friend Wall-to-Wall posts, be sure to set appropriate setting to this seting, Can see Wall posts by friends. Otherwise, no one can post to your wall but yourself.

Sunday, November 21, 2010

XMLHttpRequest.responseXML returns null

Issue: [JavaScript] Loading XSLT via XMLHttpRequest.responseXML always results in null.

Reason: It is due to incorrect MIME type "application/octet-stream" returned by the HTTP response found in "Content-Type" response header.

   var responseMIMEType = xhttp.getResponseHeader('Content-Type'); // xhttp is XMLHttpRequest object.

According to the XMLHttpRequest specification 3.7.5, XMLHttpRequest.responseXML will return null if the HTTP response header 'content-type' is not XML.

Resolution: If resultant responseXML is null, we could force to override the MIME type or convert XML text to XML DOM.

  • For the latest modern browsers like Mozilla (both SeaMonkey 2.0.10 and Firefox 3.5), Safari 5.0 and Opera 10.51, we could simply instruct the browser to override the MIME Type when it receives the document. Do this before XMLHttpRequest.send.
        // Override MIME type.  Set this before send. 
        if (xhttp.overrideMimeType)   xhttp.overrideMimeType('text/xml');
  • For others except IE, we could set up another defend mechanism by converting XML string to DOM with DOMParser.
        // Create XML DOM from string
        xmlDoc = (new DOMParser()).parseFromString(xhttp.responseText, 'text/xml');
  • IE doesn't support MIME overridden. And you may not be able to use DOMParser to parse XML string either. Otherwise, you may step into another error.

    The stylesheet does not contain a document element. The stylesheet may be empty, or it may not be a well-formed XML document.

    If it is the case, for IE, do this:

     xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
     xmlDoc.async = false;
     xmlDoc.loadXML(xhttp.responseText);
    

    The code for loading XML and XSLT may look like the following:

      var xhttp;
      function loadXMLDoc(url) {
        if (window.XMLHttpRequest) {
          xhttp = new XMLHttpRequest();
        }
        else {
          xhttp = new ActiveXObject('Microsoft.XMLHTTP');
        }
        
        xhttp.open('GET', url, false);  
        
        if (xhttp.overrideMimeType) 
          xhttp.overrideMimeType('text/xml');       
    
        xhttp.send(null);
     
    var xmlDoc = xhttp.responseXML; if (!xmlDoc) { if (isIE) { xmlDoc = new ActiveXObject('Microsoft.XMLDOM'); xmlDoc.async = false; xmlDoc.loadXML(xhttp.responseText); } else xmlDoc = (new DOMParser()).parseFromString(xhttp.responseText, 'text/xml'); }
    return xmlDoc; }
    One more thing, if you run or test this code under a file-system-based environment such as Visual Studio instead of being served by a Web server, the above stylesheet error on IE may still occur. To resolve this, both XML and XSLT must be loaded by the same method like this:
        var xmlDoc;
        if (isIE) {
          xmlDoc = new ActiveXObject('Microsoft.XMLDOM');
          xmlDoc.async = false;
          xmlDoc.loadXML(xhttp.responseText);
        }
        else {
          xmlDoc = xhttp.responseXML;
          if (!xmlDoc) {
            xmlDoc = (new DOMParser()).parseFromString(xhttp.responseText, 'text/xml');
          }
        }

After the XML and the XSLT have successfully been loaded, we can transform the XML using the loaded XSLT.

  // Transform XML using XSLT
  // Here both xml and xslt are xml dom objects
  function getTransformedXML(xml, xslt) {
    if (window.ActiveXObject)  { // for IE
       return xml.transformNode(xslt);      
    }
    // for Mozilla (SeaMonkey and FireFox), Safari, Opera, etc.
    else if (document.implementation && document.implementation.createDocument) {
      var xsltProcessor = new XSLTProcessor();
      xsltProcessor.importStylesheet(xslt);
      return xsltProcessor.transformToFragment(xml, document);
    }
     
    return null;
  }

The complete code

Here the code is revised a bit to locate the MS latest XML parser for use instead of using the default old version, Microsoft.XMLDOM.
  var xhttp;
  function loadXMLDoc(url) {
    if (window.XMLHttpRequest) {
      xhttp = new XMLHttpRequest();
    }
    else {
      xhttp = new ActiveXObject('Microsoft.XMLHTTP');
    }
    
    xhttp.open('GET', url, false);  

    if (xhttp.overrideMimeType) 
      xhttp.overrideMimeType('text/xml');       

    xhttp.send(null);

    if (isIE) {
      xmlDoc = getMSXmlParser();
      xmlDoc.async = false;
      xmlDoc.loadXML(xhttp.responseText);
    }
    else {
      xmlDoc = xhttp.responseXML;
      if (!xmlDoc) {
        xmlDoc = (new DOMParser()).parseFromString(xhttp.responseText, 'text/xml');
      }
    }
    return xmlDoc;
  }

  // Transform XML using XSLT
  // Here both xml and xslt are xml dom objects
  function getTransformedXML(xml, xslt) {
    if (window.ActiveXObject)  { // for IE
       return xml.transformNode(xslt);      
    }
    // for Mozilla (SeaMonkey and FireFox), Safari, Opera, etc.
    else if (document.implementation && document.implementation.createDocument) {
      var xsltProcessor = new XSLTProcessor();
      xsltProcessor.importStylesheet(xslt);
      return xsltProcessor.transformToFragment(xml, document);
    }
     
    return null;
  }
  
function getMSXmlParser() { var parser = ['Msxml2.DOMDocument.6.0', 'Msxml2.DOMDocument.5.0', 'Msxml2.DOMDocument.4.0', 'Msxml2.DOMDocument.3.0', 'MSXML2.DOMDocument', 'Microsoft.XMLDOM']; // the same as MSXML.DOMDocument for (var i in parser) { try { var xParser = new ActiveXObject(parser[i]); if (xParser) { return xParser; } } catch (e) {} } return null; }

Tuesday, September 28, 2010

Free calls to US by gmail is NOT available to anywhere yet!

In Aug, 2010, I was very excited to learn the newly added gmail's phone call feature and wonder I could make use of it when I travel to Asia in September. Unfortunately, this feature is not available when I was out of the USA. Luckily I have my MagicJack around.

Re-visiting the gmail official blog, I found that they have an update on Aug 26 saying this feature is only available in the US. Thus, this feature is not useful to me.

Friday, August 27, 2010

BIOSAgent is no longer available

I have been using BIOSAgent since 2007 when I was working in a project that extensively dealt with system detection. It helped me to fix a lot BIOS issues by providing me every single piece of information stored in the BIOS. Sadly, this wonderful desktop, standalone BIOSAgent is no longer available for download now. The last version is 3.66. I don't have the last version but up to v3.61.

BIOSAgentPlus is the successor or the replacement. The current version I tested is 2.2010.1.8. Unlike BIOSAgent, BIOSAgentPlus requires Internet connection for data interpretation. It doesn't scan your system over the Internet; currently you still have to download an EXE file to do the scanning and then interpret the scanned data at their online server.

Basically, there are two ways to submit the scanned data:

  • Default: Run BIOSAgentPlus while you are connected to the Internet. After the scanning, BIOSAgentPlus will auto-fetch the data.
  • Offline: Set "Work Offline" (see my offline section below to see how) and manually submit your data to DriverAgent (another tool by eSupport).

If the scanned data is auto-fetched by your local copy of BIOSAgentPlus, the result page will display not only the information of the BIOS but also every driver of your system. Any new driver(s) available to your system will also be shown in that page. If you post the data yourself, the BIOS information will not be displayed but you are still able to view the information of your existing and new available drivers online. Thus, the manual method at this point is useless. After all, the data is actually interpreted by DriverAgent, which won't interpret BIOS data.

If you scan your system offline, BIOSAgentPlus will automatically open a text XML file for you. Do a search on <D:smbios> in the file and you should find all the BIOS data. On XP, this file is stored in the folder of %TEMP%\DriverAgent.

Regardless of which method you use to submit and interpret the scanned data, you can always be allowed to choose to "Save Scan Data" for future use. This simply saves the reference data in a HTML file. Next time, you double-click on it and the data will be fetched and viewed from their online server. Again, Internet connection is absolutely required. With this, the BIOS data is always interpreted and displayed in the page.

I personally don't like the BIOSAgentPlus because I am not interested in the driver information or its upgrade. I just want to instantly see what data was written in the BIOS. In addition, when I am doing this, most of time the Internet connection is not available or the system has not completely configured well yet. With BIOSAgentPlus, I have to do more steps to view the data or I interpret data myself. I really miss the nice and simple BIOSAgent.


How to Run BIOSAgentPlus Offline (for version: v2.2010.1.8)

As usual, the downloaded EXE file doesn't require to install; simply download and run it. When BIOSAgentPlus runs and performs the scanning, on XP, the BIOSAgentAgent icon will be displayed in your system tray.

Right click the icon, select "Work Offline" if the Internet connection is not available. If you need scan again, then click "Scan". Note that The Scan button will be grayed out while BIOSAgentPlus is scanning.

As soon as the scanning is done, a text file named DriverAgent.xml.txt will be opened for you. Follow the instruction in that file and submit its XML content to http://driveragent.com/manual.php. As discussed before, the BIOS information will not be interpreted when you manually submit data to DriverAgent.

Wednesday, August 25, 2010

MagicJack: Contacts list is empty and drives inaccessible

MagicJack has done some upgrade within these two weeks that cause some users' contact list wiped forever (see their current announcement or the captured image). In addition, the MagicJack drives are no longer accessible after the softphone has been up and running; both drives occupied by MagicJack become "CD Drive" and "Removable Disk" while the softphone is in service.

Drives while softphone is loading right arrow Drives after softphone is loaded
MJ drives before softphone is loaded MJ drives after softphone is loaded
Accessible Inaccessible

I am lucky still to find my contacts list file in the device. Yours may still exist. See my how-to for details.

From now on, all the profile information including the contacts list and the call history will be stored in the MagicJack server. Thus, your softphone may indicate "Contacts list is empty" after the upgrade regardless of the file existence in your device. Currently there is no way to upload the list to the server but manually input yourself.

How to access the MagicJack device to find your contacts list

  • Unplug the MagicJack if currently connected.
  • Wait a few seconds for your system to clear the device.
  • Hold down the SHIFT key and then plug your MagicJack device in. DON'T RELEASE THE SHIFT KEY WHILE YOU'RE PLUGGING IT IN BEFORE YOU HEAR THE USUAL DEVICE CONNECTION SOUND. The SHIFT key will temporarily disable the softphone auto-run. Therefore, you should see two drives named "magicJack".
  • Go to the drive which contains a folder called "magicJack" as well. Usually it is the 2nd one. Your contact list is stored in AddressBook.xml

Wednesday, August 18, 2010

Will Hong Kong be no longer to call Hong Kong?

Next month I will go Hong Kong for visit. At the same time, I may go Shanghai for a few days if possible. I found that quite a lot of people now go by train instead of flight. Thus I started my research on train. There is a direct train traveling between Hong Kong and Shanghai. Each way operates every other day.

I am surprised that a lot of people emphasized in their blogs to look for the word Jiulong for buying return train ticket in China. Huh? Jiulong? Where is it? Should it be Hong Kong? Some place in Hong Kong? Or the train station in Hong kong?

The train station in Hong Kong to Shanghai is called Hung Hom Train Station and located in Kowloon, Hong Kong. There is no place or a train station in Hong Kong called Jiulong. Then where is Jiulong?

After having done some digging, I finally reach my conclusion. Jiulong is the direct translation from Mandarin pronunciation to English. It is actually referring to Kowloon, the official name in Hong Kong. Why did China make this new name to Kowloon, Hong Kong? Has Kowloon already had a name in English? It is extremely confusing. This makes me wonder that Hong Kong may have a new name in English soon. 50 years unchanged? Certainly something have been changed on their ways. Look! The name is one of the changes. Would Hong Kong be called Xiang Gang in English in the future or whatever name in Mandarin? Note that Xiang Gang is the Mandarin pronunciation in English for "Hong Kong" according to one of the online dictionaries. Please correct me if it is incorrect.

Will Hong Kong people accept this new name? Unfortunately, a lot of people don't even know.


Friday, August 6, 2010

I'm certified - MCTS

keep smiling

Today is my lucky and happy day. I finally got certified with ASP.NET 3.5. I was preparing it for the past few months. Today I finally get an award of it.

My exam time was scheduled at 11:30AM today. I left and headed to the test center an hour ahead of my exam time. It was just about 10 minutes drive but I was almost late and missed the time because of the incorrect Google map. I kept calling the test center but I could not reach anyone. I was panic and even thought that I might be doomed today. The time was ticking and I had only 10 minutes left. Finally, my call got through and I arrived just right on time. Still, my feeling was not so good that I was afraid what happened before was to give me some sort of symbolic or indication that I could fail my exam. However, the result turns out fantastic (a perfect one) and it makes me keep smiling.

The actual exam time lasts 180 minutes (3 hours) for 45 questions. But my confirmation sheet (from Prometric registration) said 4 hours because the additional hour was used for reading instructions, answering questions for survey (compulsorily) and leaving comments to questions after test (voluntarily). When I started taking the exam, the time was set to 180 and then counted down. I spent about 2 hours and read twice. The full score is 1000 and the passing mark is 700.

Monday, June 21, 2010

Double-click and right-click are extremely slow

In the past few months, one of my laptops running with windows XP responded very slowly to both double-click and right-click. Double-click to open a photo less than 1 KB takes more than a minute while the right-click sometimes might freeze the Windows Explorer. Everything works fine if I use the program to open it. This problem is not specific to any type of files.

Unlike others, this laptop didn't install many applications. It doesn't even have Microsoft Office on it. But it carries adobe reader, Nero burning software, AVG anti-virus, Spybot Seach & Destroy, and the default graphic card software by Intel. That's. It was used to be super fast.

Using ShellExView for diagnostics and disabling every single Context Menu Handler, Icon Handler and Property Sheet don't help. Finally the System File Checker (sfc) command fixed the problem.

sfc /scannow

Be sure to have your Windows installation CD ready before you issue the above command.

Now I enabled all the extensions that were disabled via ShellExView. Everything is back to normal now.

In this article, it mentions Context Menu handler for Intel® Graphics could be the possible culprit. But it isn't in my case. The problem I had was not only right-click but also double-click. Thus, if you have the similar trouble, you may have to trial-and-error to rule out the issue. Using ShellExView to find the root cause is extremely time-consuming because every change you make require a reboot in order to see the actual effect. Luckily I finally have my problem solved.

Saturday, June 12, 2010

The LoadDataRow and Delete Methods of DataTable

Oftentimes we encounter problems when we perform update using LoadDataRow or rollback data using RejectChanges after the Delete method. Why do the methods sometimes not do what we want?

Googling a solution for LoadDataRow, we may find that most people resolve the update performed by LoadDataRow must call DataTable.AcceptChanges first. Does this solution work for you 100%? There are still some unresolved posts left unanswered. They follow the solution to call AcceptChanges but the problem still exists. Why?

Deleting a DataRow and then immediately performing RejectAccepts to rollback cause us to receive System.Data.RowNotInTableException. What is it going on? Is the DataRow marked as Deleted? Why can't I rollback?

The above problems are related to either the RowState of a DataRow or if we set up the constraints on DataTable correctly.

continue Assuming there is no constraint problem, the DataRow must be either Unchanged or Modified when we perform an update using the LoadDataRow method on an existing DataRow. The same principle applies to the RejectChanges after calling the Delete method. Apparently, the operations requires an Original version existed for the DataRow. When the RowState of DataRow is Unchanged or Modified, an Original version of the DataRow has been created/existed. Thus, any operations after it won't cause a problem.

continueIf you receive a System.Data.ConstraintException in regard to System.Data.UniqueConstraint.CheckConstraint, please ensure the primary key set up properly. Most likely, setting the Unique property of a DataColumn without primary key to true will cause this problem to occur.

continueIf you receive a System.Data.ConstraintException in regard to System.Data.DataTable.EnableConstraints, please ensure an Original version existed for the DataRow. It means the RowState of the DataRow is still in the state of Added and you need to commit changes first by calling the AcceptChanges method to update the state to Unchanged.

continueSimilarly, if you receive a System.Data.RowNotInTableException when you try to roll back the DataRow after having called the Delete method, a AcceptChanges call is required before the Delete method. After AcceptChanges, an Original version of the DataRow is created and the RowState of the DataRow is set to Unchanged. From this state onwards, any modification including the LoadDataRow method, or calling the Delete method and then the RejectChanges method can be performed.

To sum up what the RowState means is described in the following table.
DetachedThe DataRow is created but it hasn't been added to a DataTable yet. Since it does not exist in a DataTable, no operations can be performed at the DataTable level.
AddedThe DataRow is added to a DataTable but the DataTable has not accepted changes yet. At this stage, it requires AcceptChanges to create Original version for other update operations including rollback.
UnchangedThe DataRow has not changed since the last AcceptChanges call. At this stage, an Original version of the DataRow has already existed. Thus, any operations can be performed without a problem.
ModifiedThe DataRow has been modified since the last AcceptChanges call. Like Unchanged, an Original version of the DataRow has already existed in this stage. A DataRow with Modified row state can continously be modified but the RejectChanges will only roll the data back to the last AcceptChanges call. Any modification made in between is disgarded because the Original version of the DataRow is only pointing the copy when the last AcceptChanges is called.
DeletedThe DataRow was deleted by using the Delete method of the DataRow only when the RowState of the DataRow is Unchanged or Modified.

I also attach some test results I conducted for reference.

Friday, June 11, 2010

About DataRow.Delete, .AcceptChanges and .RejectChanges

See The LoadDataRow and Delete Methods of DataTable for intention.

Purpose

The following 3 tests [ Test 1 | Test 2 | Test 3 ] tell you about in which situation you can roll back your data and when you cannot.

This page is generated by the application developed in C# under Visual 2008 Profession SP + .NET 3.5 SP1 on Windows XP Professional SP3.

Test 1: No AcceptChanges before deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Without AcceptChanges, immediately delete the 2nd DataRow using Delete method.
  • The RowState of the deleted row is not Deleted but Detached; The result is different from what it is said in the documentation [According to MSDN, it is currently supported in: 4, 3.5, 3.0, 2.0, 1.1, 1.0]. Please also see the test foot notes in blue.
  • Then RejectChanges after deletion; unfortunately, the System.Data.RowNotInTableException is received.

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Using Delete method to delete [B223456789, Rex] at RowState: Added...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded

The deleted row after deletion: RowState: Detached
Version: Original doesn't not exist.
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

This row has been removed from a table and does not have any data.  BeginEdit() will allow creation of new data in this row.
System.Data.RowNotInTableException
at System.Data.DataRow.GetDefaultRecord() at System.Data.DataColumn.CheckNullable(DataRow row) at System.Data.DataColumn.CheckColumnConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.SetNewRecord(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Boolean fireEvent) at System.Data.DataTable.RollbackRow(DataRow row) at System.Data.DataRow.RejectChanges() ...

After error: RowState: Detached
Version: Original doesn't not exist.
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

  • By definition of DataRow.Delete method, the row should have been marked as Deleted.
  • According to this, this bug should have been fixed in VS 2008. Apparently, it still exists. Or there may be a typo in the document. Originally it said, "If the RowState of the row is Added, the RowState becomes Detached and the row is removed from the table when you call AcceptChanges." Perhaps, it is meant to say, ""If the RowState of the row is Added, the RowState becomes Detached and the row is removed from the table when you call RejectChanges." Then everything will become and make more sense.
  • Because DataRow.RowState is set to Detached, we cannot roll it back by using RejectChanges.


Test 2: AcceptChanges before deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Then AcceptChanges, which changes the RowState from Added to Unchanged.
  • Delete the 2nd DataRow using Delete method. The RowState of the 2nd DataRow is marked as Deleted now.
  • Immdiately RejectChanges after deletion, which changes the RowState from Deleted back to Unchanged

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

AcceptChanges. [B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Using Delete method to delete [B223456789, Rex] at RowState: Unchanged...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
?????Deleted

The deleted row after deletion: RowState: Deleted
Version: Original Value: Rex
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

RejectChanges:
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789RexBloomer12.00Bloomer, RexUnchanged

[B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

  • After deletion using Delete method, the RowState is set to Deleted.
  • Thus, RejectChanges can be used to roll back the DataRow to the point where the AcceptChanges method is last called.
  • The RowState of the deleted row is also rolled back to Unchanged. Everything looks exactly like before deletion.

Test 3: AcceptChanges, modification and then deletion
  • Set up a DataTable with 2 rows; so the initial RowState of all DataRows is Added.
  • Then AcceptChanges, which changes the RowState from Added to Unchanged.
  • Start BeginEdit ... EndEdit block to modify the 2nd row. Change the FirstName from Rex to Susan.
  • The expression column LastName and FirstName remains unchanged until the EndEdit method is called while FirstName is modified before calling EndEdit.
  • Then delete the 2nd DataRow using Delete method. The RowState of the 2nd DataRow is marked as Deleted now.
  • Immdiately RejectChanges after deletion, which changes everything back to the state when the AcceptChanges is last called; thus the RowState is rolled back all the way from Deleted to Unchanged

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeAdded
B223456789RexBloomer12.00Bloomer, RexAdded

Initial state: [B223456789, Rex] RowState: Added
Version: Original doesn't not exist.
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

AcceptChanges. [B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

BeginEdit and modified the 2nd row:
 row.BeginEdit(); row["FirstName"] = "Susan";

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789SusanBloomer12.00Bloomer, RexUnchanged
[B223456789, Susan] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed Value: Susan
Version: Default Value: Susan

After EndEdit:
  row.EndEdit();

EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789SusanBloomer12.00Bloomer, SusanModified
[B223456789, Susan] RowState: Modified
Version: Original Value: Rex
Version: Current Value: Susan
Version: Proposed doesn't not exist.
Version: Default Value: Susan

Using Delete method to delete [B223456789, Susan] at RowState: Modified...
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
?????Deleted

The deleted row after deletion: RowState: Deleted
Version: Original Value: Rex
Version: Current doesn't not exist.
Version: Proposed doesn't not exist.
Version: Default doesn't not exist.

RejectChanges:
EmpIdFirstNameLastNameSalaryLastName and FirstNameRowState
A123456789BettyeWilliams11.00Williams, BettyeUnchanged
B223456789RexBloomer12.00Bloomer, RexUnchanged

[B223456789, Rex] RowState: Unchanged
Version: Original Value: Rex
Version: Current Value: Rex
Version: Proposed doesn't not exist.
Version: Default Value: Rex

Interesting of this test is that the "LastName and FirstName" column remains unchanged [Bloomer, Rex] after the FirstName has been modified to Susan. The "LastName and FirstName" column is an Expression column set up by expression that contains the values from both FirstName and LastName columns. Changing FirstName will not refect the change immediately in the "FirstName and LastName" column until EndEdit is called.

Wednesday, June 9, 2010

LoadDataRow(object[], bool) and ConstraintException

See The LoadDataRow and Delete Methods of DataTable for intention.


Introduction

In this test, I will use LoadDataRow to perform content update on a DataTable with or without primary key constraint. bool AcceptChanges will be passed as a parameter in LoadDataRow(object[], bool). For result using LoadDataRow(object[], LoadOption), please see this.

When the LoadDataRow method is call, the following statement is used:
   employee.LoadDataRow(
      new object[] { "B223456789", "Denise", "Miller", 13.00 },
      false);  // don't AcceptChanges
When primary key is applied, the following statement is used and it will be executed before the LoadDataRow method:
   employee.PrimaryKey = new DataColumn[] {eid}; // eid is the EmpId column   

The DataTable used for the test has the five (5) columns and initially is populated with 2 sample data rows.
ColumnNameEmpIdFirstNameLastNameSalaryLastName and FirstName **
DataTypestringstringstringdecimalstring
MaxLength1035-1-170
Uniquetruefalsefalsefalsefalse
AllowDBNullfalsefalsefalsetruetrue

** The column of LastName and FirstName is defined as an expression column containing the values from the column of LastName and the column of FirstName.

Every test is based on this table with the initial sample data. The 2nd row is the target to update by using the LoadDataRow method. A grid shown in each test is represented the final result of the DataTable even though the update performed by the LoadDataRow method may fail. Execution messages about the RowState of the 2nd row and its versions are shown afterwards. For clarity, the initial state of the 2nd row is also attached to each test for reference.

The rest of the page is generated by the application developed in C# under Visual 2008 Profession SP + .NET 3.5 SP1 on Windows XP Professional SP3.


Set up a DataTable with 2 rows
- EmpId is the unique key (eid.Unique = true).
- Primary key is not set up initially.

  • Initial Table:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


No primary key applied
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataRowCollection.Add(Object[] values) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, no AcceptChanges before or after LoadDataRow
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


No primary key, AcceptChanges before LoadDataRow
Expect errors [System.Data.UniqueConstraint.CheckConstraint]!
The last row remains unchanged.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    Column 'EmpId' is constrained to be unique.  Value 'B223456789' is already present.
    System.Data.ConstraintException
    at System.Data.UniqueConstraint.CheckConstraint(DataRow row, DataRowAction action) at System.Data.DataTable.RaiseRowChanging(DataRowChangeEventArgs args, DataRow eRow, DataRowAction eAction, Boolean fireEvent) at System.Data.DataTable.SetNewRecordWorker(DataRow row, Int32 proposedRecord, DataRowAction action, Boolean isInMerge, Int32 position, Boolean fireEvent, Exception& deferredException) at System.Data.DataTable.InsertRow(DataRow row, Int32 proposedID, Int32 pos, Boolean fireEvent) at System.Data.DataRowCollection.Add(Object[] values) at System.Data.DataTable.UpdatingAdd(Object[] values) at System.Data.DataTable.LoadDataRow(Object[] values, Boolean fAcceptChanges) ...

    After error: [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, AcceptChanges before LoadDataRow
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise


No primary key, LoadDataRow in conjunction with Begin/EndLoadData
Expect errors [System.Data.DataTable.EnableConstraints()]!
Duplicate rows are found.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
    System.Data.ConstraintException
    at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.set_EnforceConstraints(Boolean value) at System.Data.DataTable.EndLoadData() ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData
Expect errors [System.Data.DataTable.EnableConstraints()]!
Duplicate rows are found.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789RexBloomer12.00Bloomer, Rex
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    Failed to enable constraints. One or more rows contain values violating non-null, unique, or foreign-key constraints.
    System.Data.ConstraintException
    at System.Data.DataTable.EnableConstraints() at System.Data.DataTable.set_EnforceConstraints(Boolean value) at System.Data.DataTable.EndLoadData() ...

    After error: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex


Primary key applied, LoadDataRow in conjunction with Begin/EndLoadData, ApplyChanges before BeginLoadData
No error! The last row is updated.

  • Resulted DataTable:
  • EmpIdFirstNameLastNameSalaryLastName and FirstName
    A123456789BettyeWilliams11.00Williams, Bettye
    B223456789DeniseMiller13.00Miller, Denise

  • Status duing execution:
  • Initial state: [B223456789, Rex] RowState: Added
    Version: Original doesn't not exist.
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    Apply AcceptChanges(): [B223456789, Rex] RowState: Unchanged
    Version: Original Value: Rex
    Version: Current Value: Rex
    Version: Proposed doesn't not exist.
    Version: Default Value: Rex

    BeginLoadData(): turn off notification/constraints/indexing.

    Executing LoadDataRow(...)
    After LoadDataRow: [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise

    EndLoadData(): turn on validation, constraints, etc.

    [B223456789, Denise] RowState: Modified
    Version: Original Value: Rex
    Version: Current Value: Denise
    Version: Proposed doesn't not exist.
    Version: Default Value: Denise